From 25482b9a0665ed0e673b5850eaccc9bae4d4eae5 Mon Sep 17 00:00:00 2001 From: BitcoinMechanic Date: Fri, 20 Sep 2024 14:31:31 -0700 Subject: [PATCH] show miner name on block timeline --- backend/src/api/blocks.ts | 6 +++ backend/src/mempool.interfaces.ts | 1 + backend/src/repositories/BlocksRepository.ts | 6 +++ backend/src/utils/bitcoin-script.ts | 23 +++++++++++ .../block/block-preview.component.html | 26 +++++++++++-- .../app/components/block/block.component.html | 13 ++++++- .../app/components/block/block.component.scss | 27 +++++++++++++ .../blockchain-blocks.component.html | 15 ++++++- .../blockchain-blocks.component.scss | 39 ++++++++++++++++++- .../blockchain-blocks.component.ts | 16 ++++++++ .../blockchain/blockchain.component.scss | 2 +- .../transaction/transaction.component.html | 14 ++++++- .../transaction/transaction.component.scss | 27 +++++++++++++ .../app/dashboard/dashboard.component.scss | 2 +- .../src/app/interfaces/node-api.interface.ts | 1 + 15 files changed, 204 insertions(+), 14 deletions(-) diff --git a/backend/src/api/blocks.ts b/backend/src/api/blocks.ts index 306179ca5..9a7d8b11a 100644 --- a/backend/src/api/blocks.ts +++ b/backend/src/api/blocks.ts @@ -34,6 +34,7 @@ import { calculateFastBlockCpfp, calculateGoodBlockCpfp } from './cpfp'; import mempool from './mempool'; import CpfpRepository from '../repositories/CpfpRepository'; import accelerationApi from './services/acceleration'; +import { parseDATUMTemplateCreator } from '../utils/bitcoin-script'; class Blocks { private blocks: BlockExtended[] = []; @@ -342,7 +343,12 @@ class Blocks { id: pool.uniqueId, name: pool.name, slug: pool.slug, + minerNames: null, }; + + if (extras.pool.name === 'OCEAN') { + extras.pool.minerNames = parseDATUMTemplateCreator(extras.coinbaseRaw); + } } extras.matchRate = null; diff --git a/backend/src/mempool.interfaces.ts b/backend/src/mempool.interfaces.ts index ccbc94bfa..6eee1a9ee 100644 --- a/backend/src/mempool.interfaces.ts +++ b/backend/src/mempool.interfaces.ts @@ -299,6 +299,7 @@ export interface BlockExtension { id: number; // Note - This is the `unique_id`, not to mix with the auto increment `id` name: string; slug: string; + minerNames: string[] | null; }; avgFee: number; avgFeeRate: number; diff --git a/backend/src/repositories/BlocksRepository.ts b/backend/src/repositories/BlocksRepository.ts index de6c1deb8..f958e5c8b 100644 --- a/backend/src/repositories/BlocksRepository.ts +++ b/backend/src/repositories/BlocksRepository.ts @@ -14,6 +14,7 @@ import chainTips from '../api/chain-tips'; import blocks from '../api/blocks'; import BlocksAuditsRepository from './BlocksAuditsRepository'; import transactionUtils from '../api/transaction-utils'; +import { parseDATUMTemplateCreator } from '../utils/bitcoin-script'; interface DatabaseBlock { id: string; @@ -1054,6 +1055,7 @@ class BlocksRepository { id: dbBlk.poolId, name: dbBlk.poolName, slug: dbBlk.poolSlug, + minerNames: null, }; extras.avgFee = dbBlk.avgFee; extras.avgFeeRate = dbBlk.avgFeeRate; @@ -1123,6 +1125,10 @@ class BlocksRepository { } } + if (extras.pool.name === 'OCEAN') { + extras.pool.minerNames = parseDATUMTemplateCreator(extras.coinbaseRaw); + } + blk.extras = extras; return blk; } diff --git a/backend/src/utils/bitcoin-script.ts b/backend/src/utils/bitcoin-script.ts index 8f551aa23..619f1876d 100644 --- a/backend/src/utils/bitcoin-script.ts +++ b/backend/src/utils/bitcoin-script.ts @@ -200,4 +200,27 @@ export function getVarIntLength(n: number): number { } else { return 9; } +} + +/** Extracts miner names from a DATUM coinbase transaction */ +export function parseDATUMTemplateCreator(coinbaseRaw: string): string[] | null { + let bytes: number[] = []; + for (let c = 0; c < coinbaseRaw.length; c += 2) { + bytes.push(parseInt(coinbaseRaw.slice(c, c + 2), 16)); + } + + // Skip block height + let tagLengthByte = 1 + bytes[0]; + + let tagsLength = bytes[tagLengthByte]; + if (tagsLength == 0x4c) { + tagLengthByte += 1; + tagsLength = bytes[tagLengthByte]; + } + + const tagStart = tagLengthByte + 1; + const tags = bytes.slice(tagStart, tagStart + tagsLength); + const tagString = String.fromCharCode(...tags); + + return tagString.split('\x0f'); } \ No newline at end of file diff --git a/frontend/src/app/components/block/block-preview.component.html b/frontend/src/app/components/block/block-preview.component.html index 56fa8886e..b1cafc05e 100644 --- a/frontend/src/app/components/block/block-preview.component.html +++ b/frontend/src/app/components/block/block-preview.component.html @@ -53,15 +53,33 @@ Miner - - {{ block.extras.pool.name }} + + {{ block.extras.pool.minerNames[1] }} +
+ on + + {{ block.extras.pool.name}} +
+
+ + + {{ block.extras.pool.name }} +
- {{ block?.extras.pool.name }} - + + {{ block?.extras.pool.minerNames[1] }} +
+ on {{ block?.extras.pool.name }} +
+
+ + {{ block?.extras.pool.name }} + + diff --git a/frontend/src/app/components/block/block.component.html b/frontend/src/app/components/block/block.component.html index 1dd9d8a8d..d97ebafc5 100644 --- a/frontend/src/app/components/block/block.component.html +++ b/frontend/src/app/components/block/block.component.html @@ -182,8 +182,17 @@ Miner - - {{ block.extras.pool.name }} +
+ {{ block.extras.pool.minerNames[1] }} +
+ on + + {{ block.extras.pool.name }} +
+
+ + {{ block.extras.pool.name }} +
diff --git a/frontend/src/app/components/block/block.component.scss b/frontend/src/app/components/block/block.component.scss index fe5318375..887d7281f 100644 --- a/frontend/src/app/components/block/block.component.scss +++ b/frontend/src/app/components/block/block.component.scss @@ -81,6 +81,33 @@ h1 { } } +.on-pool-container { + display: inline; + flex-direction: row; +} + +.on-pool { + background-color: var(--bg); + display: inline-block; + margin-top: 4px; + padding: .25em .4em; + border-radius: .25rem; +} + +.on-pool-text { + font-weight: normal; + color: gray; + padding-inline-end: 4px; +} + +.pool-logo { + width: 25px; + height: 25px; + position: relative; + top: -1px; + margin-right: 2px; +} + .row { flex-direction: column; @media (min-width: 768px) { diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html index a60e1db0a..3fdafb540 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html @@ -61,8 +61,19 @@ diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss index b8de4f2ca..b03b3d3cb 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss @@ -19,6 +19,37 @@ pointer-events: none; } +.on-pool-text { + font-weight: normal; + color: gray; + padding-inline-end: 4px; +} + +.on-pool-name-text { + display: inline-block; + padding-top: 2px; + font-weight: normal; +} + + +.on-pool { + align-items: center; + background-color: var(--bg); + display: inline-block; + margin-top: 4px; + padding: .25em .4em; + border-radius: .25rem; +} + +.on-pool-container { + display: flex; + flex-direction: column; +} + +.pool-container { + margin-top: 12px; +} + .mined-block { position: absolute; top: 0px; @@ -125,7 +156,7 @@ #arrow-up { position: relative; left: calc(var(--block-size) * 0.6); - top: calc(var(--block-size) * 1.28); + top: calc(var(--block-size) * 1.38); width: 0; height: 0; border-left: calc(var(--block-size) * 0.2) solid transparent; @@ -155,7 +186,7 @@ .badge { position: relative; - top: 15px; + top: 8px; z-index: 101; color: #FFF; } @@ -168,6 +199,10 @@ margin-right: 2px; } +.pool-logo.faded { + filter: grayscale(100%) brightness(1.5); +} + .animated { transition: all 0.15s ease-in-out; white-space: nowrap; diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts index 1a7598079..512886f23 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts @@ -281,6 +281,14 @@ export class BlockchainBlocksComponent implements OnInit, OnChanges, OnDestroy { if (block?.extras) { block.extras.minFee = this.getMinBlockFee(block); block.extras.maxFee = this.getMaxBlockFee(block); + if (block.extras.pool?.minerNames) { + block.extras.pool.minerNames = block.extras.pool.minerNames.map((name) => { + if (name.length > 16) { + return name.slice(0, 16) + '…'; + } + return name; + }); + } } } this.blocks.push(block || { @@ -323,6 +331,14 @@ export class BlockchainBlocksComponent implements OnInit, OnChanges, OnDestroy { if (block?.extras) { block.extras.minFee = this.getMinBlockFee(block); block.extras.maxFee = this.getMaxBlockFee(block); + if (block.extras.pool?.minerNames) { + block.extras.pool.minerNames = block.extras.pool.minerNames.map((name) => { + if (name.length > 16) { + return name.slice(0, 16) + '…'; + } + return name; + }); + } } this.blocks[blockIndex] = block; this.blockStyles[blockIndex] = this.getStyleForBlock(block, blockIndex); diff --git a/frontend/src/app/components/blockchain/blockchain.component.scss b/frontend/src/app/components/blockchain/blockchain.component.scss index 32225598a..7f98f5ed1 100644 --- a/frontend/src/app/components/blockchain/blockchain.component.scss +++ b/frontend/src/app/components/blockchain/blockchain.component.scss @@ -14,7 +14,7 @@ } .blockchain-wrapper { - height: 260px; + height: 272px; -webkit-user-select: none; /* Safari */ -moz-user-select: none; /* Firefox */ -ms-user-select: none; /* IE10+/Edge */ diff --git a/frontend/src/app/components/transaction/transaction.component.html b/frontend/src/app/components/transaction/transaction.component.html index b2e55a3b0..d00ab0e02 100644 --- a/frontend/src/app/components/transaction/transaction.component.html +++ b/frontend/src/app/components/transaction/transaction.component.html @@ -684,8 +684,18 @@ @if (pool) { - - {{ pool.name }} +
+ {{ pool.minerNames[1] }} +
+ on + + {{ pool.name }} +
+
+ + + {{ pool.name }} +
} @else { diff --git a/frontend/src/app/components/transaction/transaction.component.scss b/frontend/src/app/components/transaction/transaction.component.scss index 1706dfcab..43cece726 100644 --- a/frontend/src/app/components/transaction/transaction.component.scss +++ b/frontend/src/app/components/transaction/transaction.component.scss @@ -60,6 +60,33 @@ top: -1px; } +.on-pool-container { + display: inline; + flex-direction: row; +} + +.on-pool { + background-color: var(--bg); + display: inline-block; + margin-top: 4px; + padding: .25em .4em; + border-radius: .25rem; +} + +.on-pool-text { + font-weight: normal; + color: gray; + padding-inline-end: 4px; +} + +.pool-logo { + width: 25px; + height: 25px; + position: relative; + top: -1px; + margin-right: 2px; +} + .badge.badge-accelerated { background-color: var(--tertiary); color: white; diff --git a/frontend/src/app/dashboard/dashboard.component.scss b/frontend/src/app/dashboard/dashboard.component.scss index 9ad09981f..0864f0096 100644 --- a/frontend/src/app/dashboard/dashboard.component.scss +++ b/frontend/src/app/dashboard/dashboard.component.scss @@ -1,6 +1,6 @@ .dashboard-container { text-align: center; - margin-top: 0.5rem; + margin-top: 1.0rem; .col { margin-bottom: 1.5rem; } diff --git a/frontend/src/app/interfaces/node-api.interface.ts b/frontend/src/app/interfaces/node-api.interface.ts index 3e38ff88b..4c7796590 100644 --- a/frontend/src/app/interfaces/node-api.interface.ts +++ b/frontend/src/app/interfaces/node-api.interface.ts @@ -203,6 +203,7 @@ export interface BlockExtension { id: number; name: string; slug: string; + minerNames: string[] | null; } }