Merge branch 'master' into simon/angular-17
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
|
||||
<div class="grid-align" [style.gridTemplateColumns]="'repeat(auto-fit, ' + resolution + 'px)'">
|
||||
<div class="graph-alignment" [class.grid-align]="!autofit" [style.gridTemplateColumns]="'repeat(auto-fit, ' + resolution + 'px)'">
|
||||
<div class="block-overview-graph">
|
||||
<canvas *browserOnly class="block-overview-canvas" [class.clickable]="!!hoverTx" #blockCanvas></canvas>
|
||||
<div class="loader-wrapper" [class.hidden]="(!isLoading || disableSpinner) && !unavailable">
|
||||
|
||||
@@ -22,9 +22,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
.grid-align {
|
||||
.graph-alignment {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.grid-align {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, 75px);
|
||||
justify-content: center;
|
||||
|
||||
@@ -32,6 +32,7 @@ const unmatchedAuditColors = {
|
||||
export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, OnChanges {
|
||||
@Input() isLoading: boolean;
|
||||
@Input() resolution: number;
|
||||
@Input() autofit: boolean = false;
|
||||
@Input() blockLimit: number;
|
||||
@Input() orientation = 'left';
|
||||
@Input() flip = true;
|
||||
@@ -206,6 +207,10 @@ export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, On
|
||||
|
||||
update(add: TransactionStripped[], remove: string[], change: { txid: string, rate: number | undefined, acc: boolean | undefined }[], direction: string = 'left', resetLayout: boolean = false): void {
|
||||
if (this.scene) {
|
||||
add = add.filter(tx => !this.scene.txs[tx.txid]);
|
||||
remove = remove.filter(txid => this.scene.txs[txid]);
|
||||
change = change.filter(tx => this.scene.txs[tx.txid]);
|
||||
|
||||
this.scene.update(add, remove, change, direction, resetLayout);
|
||||
this.start();
|
||||
this.updateSearchHighlight();
|
||||
|
||||
@@ -70,8 +70,9 @@
|
||||
<div class="col-sm chart-container">
|
||||
<app-block-overview-graph
|
||||
#blockGraph
|
||||
[autofit]="true"
|
||||
[isLoading]="false"
|
||||
[resolution]="80"
|
||||
[resolution]="86"
|
||||
[blockLimit]="stateService.blockVSize"
|
||||
[orientation]="'top'"
|
||||
[flip]="false"
|
||||
|
||||
@@ -40,12 +40,14 @@
|
||||
<app-fee-rate unitClass=""></app-fee-rate>
|
||||
</div>
|
||||
</ng-template>
|
||||
<div [attr.data-cy]="'bitcoin-block-' + offset + '-index-' + i + '-total-fees'" *ngIf="showMiningInfo"
|
||||
<div [attr.data-cy]="'bitcoin-block-' + offset + '-index-' + i + '-total-fees'" *ngIf="showMiningInfo$ | async; else noMiningInfo"
|
||||
class="block-size">
|
||||
<app-amount [satoshis]="block.extras?.totalFees ?? 0" digitsInfo="1.2-3" [noFiat]="true"></app-amount>
|
||||
</div>
|
||||
<div [attr.data-cy]="'bitcoin-block-' + offset + '-index-' + i + 'block-size'" *ngIf="!showMiningInfo"
|
||||
<ng-template #noMiningInfo>
|
||||
<div [attr.data-cy]="'bitcoin-block-' + offset + '-index-' + i + 'block-size'"
|
||||
class="block-size" [innerHTML]="'‎' + (block.size | bytes: 2)"></div>
|
||||
</ng-template>
|
||||
<div [attr.data-cy]="'bitcoin-block-' + i + '-transactions'" class="transaction-count">
|
||||
<ng-container
|
||||
*ngTemplateOutlet="block.tx_count === 1 ? transactionsSingular : transactionsPlural; context: {$implicit: block.tx_count | number}"></ng-container>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef, Input, OnChanges, SimpleChanges } from '@angular/core';
|
||||
import { Observable, Subscription } from 'rxjs';
|
||||
import { BehaviorSubject, Observable, Subscription } from 'rxjs';
|
||||
import { StateService } from '../../services/state.service';
|
||||
import { specialBlocks } from '../../app.constants';
|
||||
import { BlockExtended } from '../../interfaces/node-api.interface';
|
||||
@@ -45,6 +45,7 @@ export class BlockchainBlocksComponent implements OnInit, OnChanges, OnDestroy {
|
||||
markBlockSubscription: Subscription;
|
||||
txConfirmedSubscription: Subscription;
|
||||
loadingBlocks$: Observable<boolean>;
|
||||
showMiningInfo$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
blockStyles = [];
|
||||
emptyBlockStyles = [];
|
||||
interval: any;
|
||||
@@ -54,7 +55,6 @@ export class BlockchainBlocksComponent implements OnInit, OnChanges, OnDestroy {
|
||||
arrowLeftPx = 30;
|
||||
blocksFilled = false;
|
||||
arrowTransition = '1s';
|
||||
showMiningInfo = false;
|
||||
timeLtrSubscription: Subscription;
|
||||
timeLtr: boolean;
|
||||
|
||||
@@ -80,8 +80,11 @@ export class BlockchainBlocksComponent implements OnInit, OnChanges, OnDestroy {
|
||||
}
|
||||
|
||||
enabledMiningInfoIfNeeded(url) {
|
||||
this.showMiningInfo = url.includes('/mining') || url.includes('/acceleration');
|
||||
this.cd.markForCheck(); // Need to update the view asap
|
||||
const urlParts = url.split('/');
|
||||
const onDashboard = ['','testnet','signet','mining','acceleration'].includes(urlParts[urlParts.length - 1]);
|
||||
if (onDashboard) { // Only update showMiningInfo if we are on the main, mining or acceleration dashboards
|
||||
this.stateService.showMiningInfo$.next(url.includes('/mining') || url.includes('/acceleration'));
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -90,6 +93,7 @@ export class BlockchainBlocksComponent implements OnInit, OnChanges, OnDestroy {
|
||||
if (['', 'testnet', 'signet'].includes(this.stateService.network)) {
|
||||
this.enabledMiningInfoIfNeeded(this.location.path());
|
||||
this.location.onUrlChange((url) => this.enabledMiningInfoIfNeeded(url));
|
||||
this.showMiningInfo$ = this.stateService.showMiningInfo$;
|
||||
}
|
||||
|
||||
this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => {
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
<div class="difficulty-stats">
|
||||
<div class="item">
|
||||
<div class="card-text bigger">
|
||||
<app-btc [satoshis]="312500000"></app-btc>
|
||||
<app-btc [satoshis]="nextSubsidy"></app-btc>
|
||||
</div>
|
||||
<div class="symbol">
|
||||
<span i18n="difficulty-box.new-subsidy">New subsidy</span>
|
||||
|
||||
@@ -62,6 +62,7 @@ export class DifficultyComponent implements OnInit {
|
||||
expectedIndex: number;
|
||||
difference: number;
|
||||
shapes: DiffShape[];
|
||||
nextSubsidy: number;
|
||||
|
||||
tooltipPosition = { x: 0, y: 0 };
|
||||
hoverSection: DiffShape | void;
|
||||
@@ -106,6 +107,7 @@ export class DifficultyComponent implements OnInit {
|
||||
const newEpochStart = Math.floor(this.stateService.latestBlockHeight / EPOCH_BLOCK_LENGTH) * EPOCH_BLOCK_LENGTH;
|
||||
const newExpectedHeight = Math.floor(newEpochStart + da.expectedBlocks);
|
||||
this.now = new Date().getTime();
|
||||
this.nextSubsidy = getNextBlockSubsidy(maxHeight);
|
||||
|
||||
if (blocksUntilHalving < da.remainingBlocks && !this.userSelectedMode) {
|
||||
this.mode = 'halving';
|
||||
@@ -233,3 +235,16 @@ export class DifficultyComponent implements OnInit {
|
||||
this.hoverSection = null;
|
||||
}
|
||||
}
|
||||
|
||||
function getNextBlockSubsidy(height: number): number {
|
||||
const halvings = Math.floor(height / 210_000) + 1;
|
||||
// Force block reward to zero when right shift is undefined.
|
||||
if (halvings >= 64) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let subsidy = BigInt(50 * 100_000_000);
|
||||
// Subsidy is cut in half every 210,000 blocks which will occur approximately every 4 years.
|
||||
subsidy >>= BigInt(halvings);
|
||||
return Number(subsidy);
|
||||
}
|
||||
@@ -66,7 +66,7 @@ export class FeeDistributionGraphComponent implements OnInit, OnChanges, OnDestr
|
||||
return;
|
||||
}
|
||||
const samples = [];
|
||||
const txs = this.transactions.filter(tx => !tx.acc).map(tx => { return { vsize: tx.vsize, rate: tx.rate || (tx.fee / tx.vsize) }; }).sort((a, b) => { return b.rate - a.rate; });
|
||||
const txs = this.transactions.map(tx => { return { vsize: tx.vsize, rate: tx.rate || (tx.fee / tx.vsize) }; }).sort((a, b) => { return b.rate - a.rate; });
|
||||
const maxBlockVSize = this.stateService.env.BLOCK_WEIGHT_UNITS / 4;
|
||||
const sampleInterval = maxBlockVSize / this.numSamples;
|
||||
let cumVSize = 0;
|
||||
|
||||
@@ -60,6 +60,7 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy {
|
||||
showMiningInfo = false;
|
||||
timeLtrSubscription: Subscription;
|
||||
timeLtr: boolean;
|
||||
showMiningInfoSubscription: Subscription;
|
||||
animateEntry: boolean = false;
|
||||
|
||||
blockOffset: number = 155;
|
||||
@@ -89,11 +90,6 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy {
|
||||
private location: Location,
|
||||
) { }
|
||||
|
||||
enabledMiningInfoIfNeeded(url) {
|
||||
this.showMiningInfo = url.includes('/mining') || url.includes('/acceleration');
|
||||
this.cd.markForCheck(); // Need to update the view asap
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.chainTip = this.stateService.latestBlockHeight;
|
||||
|
||||
@@ -102,8 +98,10 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy {
|
||||
this.widthChange.emit(this.mempoolWidth);
|
||||
|
||||
if (['', 'testnet', 'signet'].includes(this.stateService.network)) {
|
||||
this.enabledMiningInfoIfNeeded(this.location.path());
|
||||
this.location.onUrlChange((url) => this.enabledMiningInfoIfNeeded(url));
|
||||
this.showMiningInfoSubscription = this.stateService.showMiningInfo$.subscribe((showMiningInfo) => {
|
||||
this.showMiningInfo = showMiningInfo;
|
||||
this.cd.markForCheck();
|
||||
});
|
||||
}
|
||||
|
||||
this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => {
|
||||
@@ -269,6 +267,7 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy {
|
||||
this.chainTipSubscription.unsubscribe();
|
||||
this.keySubscription.unsubscribe();
|
||||
this.isTabHiddenSubscription.unsubscribe();
|
||||
this.showMiningInfoSubscription.unsubscribe();
|
||||
clearTimeout(this.resetTransitionTimeout);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ export class StartComponent implements OnInit, AfterViewChecked, OnDestroy {
|
||||
timeLtrSubscription: Subscription;
|
||||
timeLtr: boolean = this.stateService.timeLtr.value;
|
||||
chainTipSubscription: Subscription;
|
||||
chainTip: number = 100;
|
||||
chainTip: number = -1;
|
||||
tipIsSet: boolean = false;
|
||||
lastMark: MarkBlockState;
|
||||
markBlockSubscription: Subscription;
|
||||
|
||||
@@ -70,10 +70,10 @@
|
||||
<app-tx-features [tx]="tx"></app-tx-features>
|
||||
</td>
|
||||
</tr>
|
||||
<tr *ngIf="network === ''">
|
||||
<tr *ngIf="network === '' && auditStatus">
|
||||
<td class="td-width" i18n="transaction.audit">Audit</td>
|
||||
<td *ngIf="pool" class="wrap-cell">
|
||||
<ng-container *ngIf="auditStatus">
|
||||
<ng-container>
|
||||
<span *ngIf="auditStatus.coinbase; else expected" class="badge badge-primary mr-1" i18n="tx-features.tag.coinbase|Coinbase">Coinbase</span>
|
||||
<ng-template #expected><span *ngIf="auditStatus.expected; else seen" class="badge badge-success mr-1" i18n-ngbTooltip="Expected in block tooltip" ngbTooltip="This transaction was projected to be included in the block" placement="bottom" i18n="tx-features.tag.expected|Expected in Block">Expected in Block</span></ng-template>
|
||||
<ng-template #seen><span *ngIf="auditStatus.seen; else notSeen" class="badge badge-success mr-1" i18n-ngbTooltip="Seen in mempool tooltip" ngbTooltip="This transaction was seen in the mempool prior to mining" placement="bottom" i18n="tx-features.tag.seen|Seen in Mempool">Seen in Mempool</span></ng-template>
|
||||
|
||||
Reference in New Issue
Block a user