Merge branch 'master' into nymkappa/feature/widget-size-align
This commit is contained in:
@@ -81,15 +81,26 @@
|
||||
<ng-template [ngIf]="fees !== undefined" [ngIfElse]="loadingFees">
|
||||
<tr>
|
||||
<td i18n="block.total-fees|Total fees in a block">Total fees</td>
|
||||
<td *ngIf="network !== 'liquid' && network !== 'liquidtestnet'; else liquidTotalFees"><app-amount [satoshis]="fees * 100000000" digitsInfo="1.2-2" [noFiat]="true"></app-amount> <span class="fiat"><app-fiat [value]="fees * 100000000" digitsInfo="1.0-0"></app-fiat></span></td>
|
||||
<td *ngIf="network !== 'liquid' && network !== 'liquidtestnet'; else liquidTotalFees">
|
||||
<app-amount [satoshis]="block.extras.totalFees" digitsInfo="1.2-3" [noFiat]="true"></app-amount>
|
||||
<span class="fiat">
|
||||
<app-fiat [value]="block.extras.totalFees" digitsInfo="1.0-0"></app-fiat>
|
||||
</span>
|
||||
</td>
|
||||
<ng-template #liquidTotalFees>
|
||||
<td><app-amount [satoshis]="fees * 100000000" digitsInfo="1.2-2" [noFiat]="true"></app-amount> <app-fiat [value]="fees * 100000000" digitsInfo="1.2-2"></app-fiat></td>
|
||||
<td>
|
||||
<app-amount [satoshis]="fees * 100000000" digitsInfo="1.2-2" [noFiat]="true"></app-amount> <app-fiat
|
||||
[value]="fees * 100000000" digitsInfo="1.2-2"></app-fiat>
|
||||
</td>
|
||||
</ng-template>
|
||||
</tr>
|
||||
<tr *ngIf="network !== 'liquid' && network !== 'liquidtestnet'">
|
||||
<td i18n="block.subsidy-and-fees|Total subsidy and fees in a block">Subsidy + fees:</td>
|
||||
<td>
|
||||
<app-amount [satoshis]="(blockSubsidy + fees) * 100000000" digitsInfo="1.2-2" [noFiat]="true"></app-amount> <span class="fiat"><app-fiat [value]="(blockSubsidy + fees) * 100000000" digitsInfo="1.0-0"></app-fiat></span>
|
||||
<app-amount [satoshis]="block.extras.reward" digitsInfo="1.2-3" [noFiat]="true"></app-amount>
|
||||
<span class="fiat">
|
||||
<app-fiat [value]="(blockSubsidy + fees) * 100000000" digitsInfo="1.0-0"></app-fiat>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</ng-template>
|
||||
@@ -105,7 +116,18 @@
|
||||
</ng-template>
|
||||
<tr>
|
||||
<td i18n="block.miner">Miner</td>
|
||||
<td><app-miner [coinbaseTransaction]="coinbaseTx"></app-miner></td>
|
||||
<td *ngIf="stateService.env.MINING_DASHBOARD">
|
||||
<a placement="bottom" [routerLink]="['/mining/pool' | relativeUrl, block.extras.pool.slug]" class="badge"
|
||||
[class]="block.extras.pool.name === 'Unknown' ? 'badge-secondary' : 'badge-primary'">
|
||||
{{ block.extras.pool.name }}
|
||||
</a>
|
||||
</td>
|
||||
<td *ngIf="!stateService.env.MINING_DASHBOARD && stateService.env.BASE_MODULE === 'mempool'">
|
||||
<span placement="bottom" class="badge"
|
||||
[class]="block.extras.pool.name === 'Unknown' ? 'badge-secondary' : 'badge-primary'">
|
||||
{{ block.extras.pool.name }}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -10,6 +10,7 @@ import { SeoService } from 'src/app/services/seo.service';
|
||||
import { WebsocketService } from 'src/app/services/websocket.service';
|
||||
import { RelativeUrlPipe } from 'src/app/shared/pipes/relative-url/relative-url.pipe';
|
||||
import { BlockExtended } from 'src/app/interfaces/node-api.interface';
|
||||
import { ApiService } from 'src/app/services/api.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-block',
|
||||
@@ -31,7 +32,6 @@ export class BlockComponent implements OnInit, OnDestroy {
|
||||
blockSubsidy: number;
|
||||
fees: number;
|
||||
paginationMaxSize: number;
|
||||
coinbaseTx: Transaction;
|
||||
page = 1;
|
||||
itemsPerPage: number;
|
||||
txsLoadingStatus$: Observable<number>;
|
||||
@@ -50,10 +50,11 @@ export class BlockComponent implements OnInit, OnDestroy {
|
||||
private location: Location,
|
||||
private router: Router,
|
||||
private electrsApiService: ElectrsApiService,
|
||||
private stateService: StateService,
|
||||
public stateService: StateService,
|
||||
private seoService: SeoService,
|
||||
private websocketService: WebsocketService,
|
||||
private relativeUrlPipe: RelativeUrlPipe,
|
||||
private apiService: ApiService
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
@@ -88,7 +89,6 @@ export class BlockComponent implements OnInit, OnDestroy {
|
||||
const blockHash: string = params.get('id') || '';
|
||||
this.block = undefined;
|
||||
this.page = 1;
|
||||
this.coinbaseTx = undefined;
|
||||
this.error = undefined;
|
||||
this.fees = undefined;
|
||||
this.stateService.markBlock$.next({});
|
||||
@@ -124,7 +124,7 @@ export class BlockComponent implements OnInit, OnDestroy {
|
||||
this.location.replaceState(
|
||||
this.router.createUrlTree([(this.network ? '/' + this.network : '') + '/block/', hash]).toString()
|
||||
);
|
||||
return this.electrsApiService.getBlock$(hash);
|
||||
return this.apiService.getBlock$(hash);
|
||||
})
|
||||
);
|
||||
}
|
||||
@@ -134,7 +134,7 @@ export class BlockComponent implements OnInit, OnDestroy {
|
||||
return of(blockInCache);
|
||||
}
|
||||
|
||||
return this.electrsApiService.getBlock$(blockHash);
|
||||
return this.apiService.getBlock$(blockHash);
|
||||
}
|
||||
}),
|
||||
tap((block: BlockExtended) => {
|
||||
@@ -145,7 +145,6 @@ export class BlockComponent implements OnInit, OnDestroy {
|
||||
|
||||
this.seoService.setTitle($localize`:@@block.component.browser-title:Block ${block.height}:BLOCK_HEIGHT:: ${block.id}:BLOCK_ID:`);
|
||||
this.isLoadingBlock = false;
|
||||
this.coinbaseTx = block?.extras?.coinbaseTx;
|
||||
this.setBlockSubsidy();
|
||||
if (block?.extras?.reward !== undefined) {
|
||||
this.fees = block.extras.reward / 100000000 - this.blockSubsidy;
|
||||
@@ -167,9 +166,6 @@ export class BlockComponent implements OnInit, OnDestroy {
|
||||
if (this.fees === undefined && transactions[0]) {
|
||||
this.fees = transactions[0].vout.reduce((acc: number, curr: Vout) => acc + curr.value, 0) / 100000000 - this.blockSubsidy;
|
||||
}
|
||||
if (!this.coinbaseTx && transactions[0]) {
|
||||
this.coinbaseTx = transactions[0];
|
||||
}
|
||||
this.transactions = transactions;
|
||||
this.isLoadingTransactions = false;
|
||||
},
|
||||
@@ -212,13 +208,10 @@ export class BlockComponent implements OnInit, OnDestroy {
|
||||
this.queryParamsSubscription.unsubscribe();
|
||||
}
|
||||
|
||||
// TODO - Refactor this.fees/this.reward for liquid because it is not
|
||||
// used anymore on Bitcoin networks (we use block.extras directly)
|
||||
setBlockSubsidy() {
|
||||
if (this.network === 'liquid' || this.network === 'liquidtestnet') {
|
||||
this.blockSubsidy = 0;
|
||||
return;
|
||||
}
|
||||
const halvings = Math.floor(this.block.height / 210000);
|
||||
this.blockSubsidy = 50 * 2 ** -halvings;
|
||||
this.blockSubsidy = 0;
|
||||
}
|
||||
|
||||
pageChange(page: number, target: HTMLElement) {
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<div class="tooltip-custom">
|
||||
<a class="clear-link" [routerLink]="['/mining/pool' | relativeUrl, block.extras.pool.slug]">
|
||||
<img width="22" height="22" src="{{ block.extras.pool['logo'] }}"
|
||||
onError="this.src = './resources/mining-pools/default.svg'">
|
||||
onError="this.src = './resources/mining-pools/default.svg'" [alt]="'Logo of ' + block.extras.pool.name + ' mining pool'">
|
||||
<span class="pool-name">{{ block.extras.pool.name }}</span>
|
||||
</a>
|
||||
<span *ngIf="!widget" class="tooltiptext badge badge-secondary scriptmessage">{{ block.extras.coinbaseRaw | hex2ascii }}</span>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<nav class="navbar navbar-expand-md navbar-dark bg-dark">
|
||||
<a class="navbar-brand" [routerLink]="['/' | relativeUrl]" style="position: relative;">
|
||||
<ng-container *ngIf="{ val: connectionState$ | async } as connectionState">
|
||||
<img [src]="officialMempoolSpace ? './resources/mempool-space-logo.png' : './resources/mempool-logo.png'" height="35" width="140" class="logo" [ngStyle]="{'opacity': connectionState.val === 2 ? 1 : 0.5 }">
|
||||
<img [src]="officialMempoolSpace ? './resources/mempool-space-logo.png' : './resources/mempool-logo.png'" height="35" width="140" class="logo" [ngStyle]="{'opacity': connectionState.val === 2 ? 1 : 0.5 }" alt="The Mempool Open Source Project logo">
|
||||
<div class="connection-badge">
|
||||
<div class="badge badge-warning" *ngIf="connectionState.val === 0" i18n="master-page.offline">Offline</div>
|
||||
<div class="badge badge-warning" *ngIf="connectionState.val === 1" i18n="master-page.reconnecting">Reconnecting...</div>
|
||||
@@ -13,16 +13,16 @@
|
||||
|
||||
<div (window:resize)="onResize($event)" ngbDropdown class="dropdown-container" *ngIf="env.TESTNET_ENABLED || env.SIGNET_ENABLED || env.LIQUID_ENABLED || env.BISQ_ENABLED || env.LIQUID_TESTNET_ENABLED">
|
||||
<button ngbDropdownToggle type="button" class="btn btn-secondary dropdown-toggle-split" aria-haspopup="true">
|
||||
<img src="./resources/{{ network.val === '' ? 'bitcoin' : network.val }}-logo.png" style="width: 25px; height: 25px;" class="mr-1">
|
||||
<img src="./resources/{{ network.val === '' ? 'bitcoin' : network.val }}-logo.png" style="width: 25px; height: 25px;" class="mr-1" [alt]="(network.val === '' ? 'bitcoin' : network.val) + ' logo'">
|
||||
</button>
|
||||
<div ngbDropdownMenu [ngClass]="{'dropdown-menu-right' : isMobile}">
|
||||
<button ngbDropdownItem class="mainnet" routerLink="/"><img src="./resources/bitcoin-logo.png" style="width: 30px;" class="mr-1"> Mainnet</button>
|
||||
<button ngbDropdownItem *ngIf="env.SIGNET_ENABLED" class="signet" [class.active]="network.val === 'signet'" routerLink="/signet"><img src="./resources/signet-logo.png" style="width: 30px;" class="mr-1"> Signet</button>
|
||||
<button ngbDropdownItem *ngIf="env.TESTNET_ENABLED" class="testnet" [class.active]="network.val === 'testnet'" routerLink="/testnet"><img src="./resources/testnet-logo.png" style="width: 30px;" class="mr-1"> Testnet</button>
|
||||
<button ngbDropdownItem class="mainnet" routerLink="/"><img src="./resources/bitcoin-logo.png" style="width: 30px;" class="mr-1" alt="bitcoin logo"> Mainnet</button>
|
||||
<button ngbDropdownItem *ngIf="env.SIGNET_ENABLED" class="signet" [class.active]="network.val === 'signet'" routerLink="/signet"><img src="./resources/signet-logo.png" style="width: 30px;" class="mr-1" alt="signet logo"> Signet</button>
|
||||
<button ngbDropdownItem *ngIf="env.TESTNET_ENABLED" class="testnet" [class.active]="network.val === 'testnet'" routerLink="/testnet"><img src="./resources/testnet-logo.png" style="width: 30px;" class="mr-1" alt="testnet logo"> Testnet</button>
|
||||
<h6 *ngIf="env.LIQUID_ENABLED || env.BISQ_ENABLED" class="dropdown-header" i18n="master-page.layer2-networks-header">Layer 2 Networks</h6>
|
||||
<a [href]="env.BISQ_WEBSITE_URL + urlLanguage" ngbDropdownItem *ngIf="env.BISQ_ENABLED" class="bisq"><img src="./resources/bisq-logo.png" style="width: 30px;" class="mr-1"> Bisq</a>
|
||||
<a [href]="env.LIQUID_WEBSITE_URL + urlLanguage" ngbDropdownItem *ngIf="env.LIQUID_ENABLED" class="liquid" [class.active]="network.val === 'liquid'"><img src="./resources/liquid-logo.png" style="width: 30px;" class="mr-1"> Liquid</a>
|
||||
<a [href]="env.LIQUID_WEBSITE_URL + urlLanguage + '/testnet'" ngbDropdownItem *ngIf="env.LIQUID_TESTNET_ENABLED" class="liquidtestnet" [class.active]="network.val === 'liquid'"><img src="./resources/liquidtestnet-logo.png" style="width: 30px;" class="mr-1"> Liquid Testnet</a>
|
||||
<a [href]="env.BISQ_WEBSITE_URL + urlLanguage" ngbDropdownItem *ngIf="env.BISQ_ENABLED" class="bisq"><img src="./resources/bisq-logo.png" style="width: 30px;" class="mr-1" alt="bisq logo"> Bisq</a>
|
||||
<a [href]="env.LIQUID_WEBSITE_URL + urlLanguage" ngbDropdownItem *ngIf="env.LIQUID_ENABLED" class="liquid" [class.active]="network.val === 'liquid'"><img src="./resources/liquid-logo.png" style="width: 30px;" class="mr-1" alt="liquid mainnet logo"> Liquid</a>
|
||||
<a [href]="env.LIQUID_WEBSITE_URL + urlLanguage + '/testnet'" ngbDropdownItem *ngIf="env.LIQUID_TESTNET_ENABLED" class="liquidtestnet" [class.active]="network.val === 'liquid'"><img src="./resources/liquidtestnet-logo.png" style="width: 30px;" class="mr-1" alt="liquid testnet logo"> Liquid Testnet</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
<ng-template [ngIf]="loading" [ngIfElse]="done">
|
||||
<span class="skeleton-loader"></span>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #done>
|
||||
<ng-template [ngIf]="miner" [ngIfElse]="unknownMiner">
|
||||
<a placement="bottom" [ngbTooltip]="title" [href]="url" [target]="target" class="badge badge-primary">{{ miner }}</a>
|
||||
</ng-template>
|
||||
<ng-template #unknownMiner>
|
||||
<span class="badge badge-secondary" i18n="miner.tag.unknown-miner">Unknown</span>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
@@ -1,3 +0,0 @@
|
||||
.badge {
|
||||
font-size: 14px;
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
import { Component, Input, OnChanges, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
|
||||
import { AssetsService } from 'src/app/services/assets.service';
|
||||
import { Transaction } from 'src/app/interfaces/electrs.interface';
|
||||
import { StateService } from 'src/app/services/state.service';
|
||||
import { RelativeUrlPipe } from 'src/app/shared/pipes/relative-url/relative-url.pipe';
|
||||
|
||||
@Component({
|
||||
selector: 'app-miner',
|
||||
templateUrl: './miner.component.html',
|
||||
styleUrls: ['./miner.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class MinerComponent implements OnChanges {
|
||||
@Input() coinbaseTransaction: Transaction;
|
||||
miner = '';
|
||||
title = '';
|
||||
url = '';
|
||||
target = '_blank';
|
||||
loading = true;
|
||||
|
||||
constructor(
|
||||
private assetsService: AssetsService,
|
||||
private cd: ChangeDetectorRef,
|
||||
public stateService: StateService,
|
||||
private relativeUrlPipe: RelativeUrlPipe,
|
||||
) { }
|
||||
|
||||
ngOnChanges() {
|
||||
this.miner = '';
|
||||
if (this.stateService.env.MINING_DASHBOARD) {
|
||||
this.miner = 'Unknown';
|
||||
this.url = this.relativeUrlPipe.transform(`/mining/pool/unknown`);
|
||||
this.target = '';
|
||||
}
|
||||
this.loading = true;
|
||||
this.findMinerFromCoinbase();
|
||||
}
|
||||
|
||||
findMinerFromCoinbase() {
|
||||
if (this.coinbaseTransaction == null || this.coinbaseTransaction.vin == null || this.coinbaseTransaction.vin.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
this.assetsService.getMiningPools$.subscribe((pools) => {
|
||||
for (const vout of this.coinbaseTransaction.vout) {
|
||||
if (!vout.scriptpubkey_address) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pools.payout_addresses[vout.scriptpubkey_address]) {
|
||||
this.miner = pools.payout_addresses[vout.scriptpubkey_address].name;
|
||||
this.title = $localize`:@@miner-identified-by-payout:Identified by payout address: '${vout.scriptpubkey_address}:PAYOUT_ADDRESS:'`;
|
||||
const pool = pools.payout_addresses[vout.scriptpubkey_address];
|
||||
if (this.stateService.env.MINING_DASHBOARD && pools.slugs && pools.slugs[pool.name] !== undefined) {
|
||||
this.url = this.relativeUrlPipe.transform(`/mining/pool/${pools.slugs[pool.name]}`);
|
||||
this.target = '';
|
||||
} else {
|
||||
this.url = pool.link;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
for (const tag in pools.coinbase_tags) {
|
||||
if (pools.coinbase_tags.hasOwnProperty(tag)) {
|
||||
const coinbaseAscii = this.hex2ascii(this.coinbaseTransaction.vin[0].scriptsig);
|
||||
if (coinbaseAscii.indexOf(tag) > -1) {
|
||||
const pool = pools.coinbase_tags[tag];
|
||||
this.miner = pool.name;
|
||||
this.title = $localize`:@@miner-identified-by-coinbase:Identified by coinbase tag: '${tag}:TAG:'`;
|
||||
if (this.stateService.env.MINING_DASHBOARD && pools.slugs && pools.slugs[pool.name] !== undefined) {
|
||||
this.url = this.relativeUrlPipe.transform(`/mining/pool/${pools.slugs[pool.name]}`);
|
||||
this.target = '';
|
||||
} else {
|
||||
this.url = pool.link;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.loading = false;
|
||||
this.cd.markForCheck();
|
||||
});
|
||||
}
|
||||
|
||||
hex2ascii(hex: string) {
|
||||
let str = '';
|
||||
for (let i = 0; i < hex.length; i += 2) {
|
||||
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
|
||||
}
|
||||
return str;
|
||||
}
|
||||
}
|
||||
@@ -93,8 +93,9 @@
|
||||
<tbody *ngIf="(miningStatsObservable$ | async) as miningStats">
|
||||
<tr *ngFor="let pool of miningStats.pools">
|
||||
<td class="d-none d-md-block">{{ pool.rank }}</td>
|
||||
<td class="text-right"><img width="25" height="25" src="{{ pool.logo }}"
|
||||
onError="this.src = './resources/mining-pools/default.svg'"></td>
|
||||
<td class="text-right">
|
||||
<img width="25" height="25" src="{{ pool.logo }}" [alt]="pool.name + ' mining pool logo'" onError="this.src = './resources/mining-pools/default.svg'">
|
||||
</td>
|
||||
<td class=""><a [routerLink]="[('/mining/pool/' + pool.slug) | relativeUrl]">{{ pool.name }}</a></td>
|
||||
<td class="" *ngIf="this.miningWindowPreference === '24h' && !isLoading">{{ pool.lastEstimatedHashrate }} {{
|
||||
miningStats.miningUnits.hashrateUnit }}</td>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<!-- Pool overview -->
|
||||
<div *ngIf="poolStats$ | async as poolStats; else loadingMain">
|
||||
<div style="display:flex" class="mb-3">
|
||||
<img width="50" height="50" src="{{ poolStats['logo'] }}"
|
||||
<img width="50" height="50" src="{{ poolStats['logo'] }}" [alt]="poolStats.pool.name + ' mining pool logo'"
|
||||
onError="this.src = './resources/mining-pools/default.svg'" class="mr-3">
|
||||
<h1 class="m-0 pt-1 pt-md-0">{{ poolStats.pool.name }}</h1>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user