show miner name on block timeline
This commit is contained in:
parent
156bf12034
commit
25482b9a06
@ -34,6 +34,7 @@ import { calculateFastBlockCpfp, calculateGoodBlockCpfp } from './cpfp';
|
|||||||
import mempool from './mempool';
|
import mempool from './mempool';
|
||||||
import CpfpRepository from '../repositories/CpfpRepository';
|
import CpfpRepository from '../repositories/CpfpRepository';
|
||||||
import accelerationApi from './services/acceleration';
|
import accelerationApi from './services/acceleration';
|
||||||
|
import { parseDATUMTemplateCreator } from '../utils/bitcoin-script';
|
||||||
|
|
||||||
class Blocks {
|
class Blocks {
|
||||||
private blocks: BlockExtended[] = [];
|
private blocks: BlockExtended[] = [];
|
||||||
@ -342,7 +343,12 @@ class Blocks {
|
|||||||
id: pool.uniqueId,
|
id: pool.uniqueId,
|
||||||
name: pool.name,
|
name: pool.name,
|
||||||
slug: pool.slug,
|
slug: pool.slug,
|
||||||
|
minerNames: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (extras.pool.name === 'OCEAN') {
|
||||||
|
extras.pool.minerNames = parseDATUMTemplateCreator(extras.coinbaseRaw);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extras.matchRate = null;
|
extras.matchRate = null;
|
||||||
|
@ -299,6 +299,7 @@ export interface BlockExtension {
|
|||||||
id: number; // Note - This is the `unique_id`, not to mix with the auto increment `id`
|
id: number; // Note - This is the `unique_id`, not to mix with the auto increment `id`
|
||||||
name: string;
|
name: string;
|
||||||
slug: string;
|
slug: string;
|
||||||
|
minerNames: string[] | null;
|
||||||
};
|
};
|
||||||
avgFee: number;
|
avgFee: number;
|
||||||
avgFeeRate: number;
|
avgFeeRate: number;
|
||||||
|
@ -14,6 +14,7 @@ import chainTips from '../api/chain-tips';
|
|||||||
import blocks from '../api/blocks';
|
import blocks from '../api/blocks';
|
||||||
import BlocksAuditsRepository from './BlocksAuditsRepository';
|
import BlocksAuditsRepository from './BlocksAuditsRepository';
|
||||||
import transactionUtils from '../api/transaction-utils';
|
import transactionUtils from '../api/transaction-utils';
|
||||||
|
import { parseDATUMTemplateCreator } from '../utils/bitcoin-script';
|
||||||
|
|
||||||
interface DatabaseBlock {
|
interface DatabaseBlock {
|
||||||
id: string;
|
id: string;
|
||||||
@ -1054,6 +1055,7 @@ class BlocksRepository {
|
|||||||
id: dbBlk.poolId,
|
id: dbBlk.poolId,
|
||||||
name: dbBlk.poolName,
|
name: dbBlk.poolName,
|
||||||
slug: dbBlk.poolSlug,
|
slug: dbBlk.poolSlug,
|
||||||
|
minerNames: null,
|
||||||
};
|
};
|
||||||
extras.avgFee = dbBlk.avgFee;
|
extras.avgFee = dbBlk.avgFee;
|
||||||
extras.avgFeeRate = dbBlk.avgFeeRate;
|
extras.avgFeeRate = dbBlk.avgFeeRate;
|
||||||
@ -1123,6 +1125,10 @@ class BlocksRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (extras.pool.name === 'OCEAN') {
|
||||||
|
extras.pool.minerNames = parseDATUMTemplateCreator(extras.coinbaseRaw);
|
||||||
|
}
|
||||||
|
|
||||||
blk.extras = <BlockExtension>extras;
|
blk.extras = <BlockExtension>extras;
|
||||||
return <BlockExtended>blk;
|
return <BlockExtended>blk;
|
||||||
}
|
}
|
||||||
|
@ -201,3 +201,26 @@ export function getVarIntLength(n: number): number {
|
|||||||
return 9;
|
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');
|
||||||
|
}
|
@ -53,14 +53,32 @@
|
|||||||
<td i18n="block.miner">Miner</td>
|
<td i18n="block.miner">Miner</td>
|
||||||
<td *ngIf="stateService.env.MINING_DASHBOARD">
|
<td *ngIf="stateService.env.MINING_DASHBOARD">
|
||||||
<a placement="bottom" [routerLink]="['/mining/pool' | relativeUrl, block.extras.pool.slug]" class="badge" style="color: #FFF;padding:0;">
|
<a placement="bottom" [routerLink]="['/mining/pool' | relativeUrl, block.extras.pool.slug]" class="badge" style="color: #FFF;padding:0;">
|
||||||
|
<ng-container *ngIf="block.extras.pool.minerNames != undefined && block.extras.pool.minerNames.length > 1 && block.extras.pool.minerNames[1] != ''; else centralisedPool">
|
||||||
|
{{ block.extras.pool.minerNames[1] }}
|
||||||
|
<div class="on-pool">
|
||||||
|
on
|
||||||
|
<img class="pool-logo" [src]="'/resources/mining-pools/' + block.extras.pool.slug + '.svg'" onError="this.src = '/resources/mining-pools/default.svg'" [alt]="'Logo of ' + block.extras.pool.name + ' mining pool'">
|
||||||
|
{{ block.extras.pool.name}}
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
<ng-template #centralisedPool>
|
||||||
<img class="pool-logo" [src]="'/resources/mining-pools/' + block.extras.pool.slug + '.svg'" onError="this.src = '/resources/mining-pools/default.svg'" [alt]="'Logo of ' + block.extras.pool.name + ' mining pool'">
|
<img class="pool-logo" [src]="'/resources/mining-pools/' + block.extras.pool.slug + '.svg'" onError="this.src = '/resources/mining-pools/default.svg'" [alt]="'Logo of ' + block.extras.pool.name + ' mining pool'">
|
||||||
{{ block.extras.pool.name }}
|
{{ block.extras.pool.name }}
|
||||||
|
</ng-template>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="!stateService.env.MINING_DASHBOARD && stateService.env.BASE_MODULE === 'mempool'">
|
<td *ngIf="!stateService.env.MINING_DASHBOARD && stateService.env.BASE_MODULE === 'mempool'">
|
||||||
<span [attr.data-cy]="'block-details-miner-badge'" placement="bottom" class="badge"
|
<span [attr.data-cy]="'block-details-miner-badge'" placement="bottom" class="badge"
|
||||||
[class]="!block?.extras.pool.name || block?.extras.pool.slug === 'unknown' ? 'badge-secondary' : 'badge-primary'">
|
[class]="!block?.extras.pool.name || block?.extras.pool.slug === 'unknown' ? 'badge-secondary' : 'badge-primary'">
|
||||||
|
<ng-container *ngIf="block?.extras.pool.minerNames != undefined && block?.extras.pool.minerNames.length > 1 && block?.extras.pool.minerNames[1] != ''; else centralisedPool">
|
||||||
|
{{ block?.extras.pool.minerNames[1] }}
|
||||||
|
<div class="on-pool">
|
||||||
|
on {{ block?.extras.pool.name }}
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
<ng-template #centralisedPool>
|
||||||
{{ block?.extras.pool.name }}
|
{{ block?.extras.pool.name }}
|
||||||
|
</ng-template>
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -182,8 +182,17 @@
|
|||||||
<td i18n="block.miner">Miner</td>
|
<td i18n="block.miner">Miner</td>
|
||||||
<td *ngIf="stateService.env.MINING_DASHBOARD">
|
<td *ngIf="stateService.env.MINING_DASHBOARD">
|
||||||
<a placement="bottom" [routerLink]="['/mining/pool' | relativeUrl, block.extras.pool.slug]" class="badge" style="color: #FFF;padding:0;">
|
<a placement="bottom" [routerLink]="['/mining/pool' | relativeUrl, block.extras.pool.slug]" class="badge" style="color: #FFF;padding:0;">
|
||||||
|
<div class="on-pool-container" *ngIf="block.extras.pool.minerNames != undefined && block.extras.pool.minerNames.length > 1 && block.extras.pool.minerNames[1] != ''; else centralisedPool">
|
||||||
|
{{ block.extras.pool.minerNames[1] }}
|
||||||
|
<div class="on-pool">
|
||||||
|
<span class="on-pool-text">on</span>
|
||||||
<img class="pool-logo" [src]="'/resources/mining-pools/' + block.extras.pool.slug + '.svg'" onError="this.src = '/resources/mining-pools/default.svg'" [alt]="'Logo of ' + block.extras.pool.name + ' mining pool'">
|
<img class="pool-logo" [src]="'/resources/mining-pools/' + block.extras.pool.slug + '.svg'" onError="this.src = '/resources/mining-pools/default.svg'" [alt]="'Logo of ' + block.extras.pool.name + ' mining pool'">
|
||||||
{{ block.extras.pool.name }}
|
{{ block.extras.pool.name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ng-template #centralisedPool>
|
||||||
|
<img class="pool-logo" [src]="'/resources/mining-pools/' + block.extras.pool.slug + '.svg'" onError="this.src = '/resources/mining-pools/default.svg'" [alt]="'Logo of ' + block.extras.pool.name + ' mining pool'"> {{ block.extras.pool.name }}
|
||||||
|
</ng-template>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td *ngIf="!stateService.env.MINING_DASHBOARD && stateService.env.BASE_MODULE === 'mempool'">
|
<td *ngIf="!stateService.env.MINING_DASHBOARD && stateService.env.BASE_MODULE === 'mempool'">
|
||||||
|
@ -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 {
|
.row {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@media (min-width: 768px) {
|
@media (min-width: 768px) {
|
||||||
|
@ -61,8 +61,19 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="animated" *ngIf="block.extras?.pool != undefined && showPools">
|
<div class="animated" *ngIf="block.extras?.pool != undefined && showPools">
|
||||||
<a [attr.data-cy]="'bitcoin-block-' + offset + '-index-' + i + '-pool'" class="badge" [routerLink]="[('/mining/pool/' + block.extras.pool.slug) | relativeUrl]">
|
<a [attr.data-cy]="'bitcoin-block-' + offset + '-index-' + i + '-pool'" class="badge" [routerLink]="[('/mining/pool/' + block.extras.pool.slug) | relativeUrl]">
|
||||||
<img class="pool-logo" [src]="'/resources/mining-pools/' + block.extras.pool.slug + '.svg'" onError="this.src = '/resources/mining-pools/default.svg'" [alt]="'Logo of ' + block.extras.pool.name + ' mining pool'">
|
<div class="on-pool-container" *ngIf="block.extras.pool.minerNames != undefined && block.extras.pool.minerNames.length > 1 && block.extras.pool.minerNames[1] != ''; else centralisedPool">
|
||||||
{{ block.extras.pool.name}}
|
{{ block.extras.pool.minerNames[1] }}
|
||||||
|
<div class="on-pool">
|
||||||
|
<span class="on-pool-text">on</span>
|
||||||
|
<img class="pool-logo faded" [src]="'/resources/mining-pools/' + block.extras.pool.slug + '.svg'" onError="this.src = '/resources/mining-pools/default.svg'" [alt]="'Logo of ' + block.extras.pool.name + ' mining pool'">
|
||||||
|
<span class="on-pool-name-text">{{ block.extras.pool.name }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ng-template #centralisedPool>
|
||||||
|
<div class="pool-container">
|
||||||
|
<img class="pool-logo" [src]="'/resources/mining-pools/' + block.extras.pool.slug + '.svg'" onError="this.src = '/resources/mining-pools/default.svg'" [alt]="'Logo of ' + block.extras.pool.name + ' mining pool'"> {{ block.extras.pool.name }}
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -19,6 +19,37 @@
|
|||||||
pointer-events: none;
|
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 {
|
.mined-block {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
@ -125,7 +156,7 @@
|
|||||||
#arrow-up {
|
#arrow-up {
|
||||||
position: relative;
|
position: relative;
|
||||||
left: calc(var(--block-size) * 0.6);
|
left: calc(var(--block-size) * 0.6);
|
||||||
top: calc(var(--block-size) * 1.28);
|
top: calc(var(--block-size) * 1.38);
|
||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
border-left: calc(var(--block-size) * 0.2) solid transparent;
|
border-left: calc(var(--block-size) * 0.2) solid transparent;
|
||||||
@ -155,7 +186,7 @@
|
|||||||
|
|
||||||
.badge {
|
.badge {
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 15px;
|
top: 8px;
|
||||||
z-index: 101;
|
z-index: 101;
|
||||||
color: #FFF;
|
color: #FFF;
|
||||||
}
|
}
|
||||||
@ -168,6 +199,10 @@
|
|||||||
margin-right: 2px;
|
margin-right: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pool-logo.faded {
|
||||||
|
filter: grayscale(100%) brightness(1.5);
|
||||||
|
}
|
||||||
|
|
||||||
.animated {
|
.animated {
|
||||||
transition: all 0.15s ease-in-out;
|
transition: all 0.15s ease-in-out;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
@ -281,6 +281,14 @@ export class BlockchainBlocksComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
if (block?.extras) {
|
if (block?.extras) {
|
||||||
block.extras.minFee = this.getMinBlockFee(block);
|
block.extras.minFee = this.getMinBlockFee(block);
|
||||||
block.extras.maxFee = this.getMaxBlockFee(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 || {
|
this.blocks.push(block || {
|
||||||
@ -323,6 +331,14 @@ export class BlockchainBlocksComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
if (block?.extras) {
|
if (block?.extras) {
|
||||||
block.extras.minFee = this.getMinBlockFee(block);
|
block.extras.minFee = this.getMinBlockFee(block);
|
||||||
block.extras.maxFee = this.getMaxBlockFee(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.blocks[blockIndex] = block;
|
||||||
this.blockStyles[blockIndex] = this.getStyleForBlock(block, blockIndex);
|
this.blockStyles[blockIndex] = this.getStyleForBlock(block, blockIndex);
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.blockchain-wrapper {
|
.blockchain-wrapper {
|
||||||
height: 260px;
|
height: 272px;
|
||||||
-webkit-user-select: none; /* Safari */
|
-webkit-user-select: none; /* Safari */
|
||||||
-moz-user-select: none; /* Firefox */
|
-moz-user-select: none; /* Firefox */
|
||||||
-ms-user-select: none; /* IE10+/Edge */
|
-ms-user-select: none; /* IE10+/Edge */
|
||||||
|
@ -684,8 +684,18 @@
|
|||||||
@if (pool) {
|
@if (pool) {
|
||||||
<td class="wrap-cell">
|
<td class="wrap-cell">
|
||||||
<a placement="bottom" [routerLink]="['/mining/pool' | relativeUrl, pool.slug]" class="badge" style="color: #FFF;padding:0;">
|
<a placement="bottom" [routerLink]="['/mining/pool' | relativeUrl, pool.slug]" class="badge" style="color: #FFF;padding:0;">
|
||||||
|
<div class="on-pool-container" *ngIf="pool.minerNames != undefined && pool.minerNames.length > 1 && pool.minerNames[1] != ''; else centralisedPool">
|
||||||
|
{{ pool.minerNames[1] }}
|
||||||
|
<div class="on-pool">
|
||||||
|
<span class="on-pool-text">on</span>
|
||||||
<img class="pool-logo" [src]="'/resources/mining-pools/' + pool.slug + '.svg'" onError="this.src = '/resources/mining-pools/default.svg'" [alt]="'Logo of ' + pool.name + ' mining pool'">
|
<img class="pool-logo" [src]="'/resources/mining-pools/' + pool.slug + '.svg'" onError="this.src = '/resources/mining-pools/default.svg'" [alt]="'Logo of ' + pool.name + ' mining pool'">
|
||||||
{{ pool.name }}
|
{{ pool.name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ng-template #centralisedPool>
|
||||||
|
<img class="pool-logo" [src]="'/resources/mining-pools/' + pool.slug + '.svg'" onError="this.src = '/resources/mining-pools/default.svg'" [alt]="'Logo of ' + pool.name + ' mining pool'">
|
||||||
|
{{ pool.name }}
|
||||||
|
</ng-template>
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
} @else {
|
} @else {
|
||||||
|
@ -60,6 +60,33 @@
|
|||||||
top: -1px;
|
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 {
|
.badge.badge-accelerated {
|
||||||
background-color: var(--tertiary);
|
background-color: var(--tertiary);
|
||||||
color: white;
|
color: white;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
.dashboard-container {
|
.dashboard-container {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-top: 0.5rem;
|
margin-top: 1.0rem;
|
||||||
.col {
|
.col {
|
||||||
margin-bottom: 1.5rem;
|
margin-bottom: 1.5rem;
|
||||||
}
|
}
|
||||||
|
@ -203,6 +203,7 @@ export interface BlockExtension {
|
|||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
slug: string;
|
slug: string;
|
||||||
|
minerNames: string[] | null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user