Merge pull request #3932 from mempool/mononaut/stale-blocks
Stale blocks
This commit is contained in:
commit
168cc9c1bf
@ -29,6 +29,7 @@ class BitcoinApi implements AbstractBitcoinApi {
|
|||||||
weight: block.weight,
|
weight: block.weight,
|
||||||
previousblockhash: block.previousblockhash,
|
previousblockhash: block.previousblockhash,
|
||||||
mediantime: block.mediantime,
|
mediantime: block.mediantime,
|
||||||
|
stale: block.confirmations === -1,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,6 +89,7 @@ export namespace IEsploraApi {
|
|||||||
weight: number;
|
weight: number;
|
||||||
previousblockhash: string;
|
previousblockhash: string;
|
||||||
mediantime: number;
|
mediantime: number;
|
||||||
|
stale: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Address {
|
export interface Address {
|
||||||
|
@ -656,10 +656,6 @@ class Blocks {
|
|||||||
const blockSummary: BlockSummary = this.summarizeBlockTransactions(block.id, cpfpSummary.transactions);
|
const blockSummary: BlockSummary = this.summarizeBlockTransactions(block.id, cpfpSummary.transactions);
|
||||||
this.updateTimerProgress(timer, `got block data for ${this.currentBlockHeight}`);
|
this.updateTimerProgress(timer, `got block data for ${this.currentBlockHeight}`);
|
||||||
|
|
||||||
// start async callbacks
|
|
||||||
this.updateTimerProgress(timer, `starting async callbacks for ${this.currentBlockHeight}`);
|
|
||||||
const callbackPromises = this.newAsyncBlockCallbacks.map((cb) => cb(blockExtended, txIds, transactions));
|
|
||||||
|
|
||||||
if (Common.indexingEnabled()) {
|
if (Common.indexingEnabled()) {
|
||||||
if (!fastForwarded) {
|
if (!fastForwarded) {
|
||||||
const lastBlock = await blocksRepository.$getBlockByHeight(blockExtended.height - 1);
|
const lastBlock = await blocksRepository.$getBlockByHeight(blockExtended.height - 1);
|
||||||
@ -671,9 +667,11 @@ class Blocks {
|
|||||||
await BlocksRepository.$deleteBlocksFrom(lastBlock.height - 10);
|
await BlocksRepository.$deleteBlocksFrom(lastBlock.height - 10);
|
||||||
await HashratesRepository.$deleteLastEntries();
|
await HashratesRepository.$deleteLastEntries();
|
||||||
await cpfpRepository.$deleteClustersFrom(lastBlock.height - 10);
|
await cpfpRepository.$deleteClustersFrom(lastBlock.height - 10);
|
||||||
|
this.blocks = this.blocks.slice(0, -10);
|
||||||
this.updateTimerProgress(timer, `rolled back chain divergence from ${this.currentBlockHeight}`);
|
this.updateTimerProgress(timer, `rolled back chain divergence from ${this.currentBlockHeight}`);
|
||||||
for (let i = 10; i >= 0; --i) {
|
for (let i = 10; i >= 0; --i) {
|
||||||
const newBlock = await this.$indexBlock(lastBlock.height - i);
|
const newBlock = await this.$indexBlock(lastBlock.height - i);
|
||||||
|
this.blocks.push(newBlock);
|
||||||
this.updateTimerProgress(timer, `reindexed block`);
|
this.updateTimerProgress(timer, `reindexed block`);
|
||||||
let cpfpSummary;
|
let cpfpSummary;
|
||||||
if (config.MEMPOOL.CPFP_INDEXING) {
|
if (config.MEMPOOL.CPFP_INDEXING) {
|
||||||
@ -722,6 +720,10 @@ class Blocks {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// start async callbacks
|
||||||
|
this.updateTimerProgress(timer, `starting async callbacks for ${this.currentBlockHeight}`);
|
||||||
|
const callbackPromises = this.newAsyncBlockCallbacks.map((cb) => cb(blockExtended, txIds, transactions));
|
||||||
|
|
||||||
if (block.height % 2016 === 0) {
|
if (block.height % 2016 === 0) {
|
||||||
if (Common.indexingEnabled()) {
|
if (Common.indexingEnabled()) {
|
||||||
await DifficultyAdjustmentsRepository.$saveAdjustments({
|
await DifficultyAdjustmentsRepository.$saveAdjustments({
|
||||||
@ -814,6 +816,16 @@ class Blocks {
|
|||||||
return blockExtended;
|
return blockExtended;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async $indexStaleBlock(hash: string): Promise<BlockExtended> {
|
||||||
|
const block: IEsploraApi.Block = await bitcoinCoreApi.$getBlock(hash);
|
||||||
|
const transactions = await this.$getTransactionsExtended(hash, block.height, true);
|
||||||
|
const blockExtended = await this.$getBlockExtended(block, transactions);
|
||||||
|
|
||||||
|
blockExtended.canonical = await bitcoinApi.$getBlockHash(block.height);
|
||||||
|
|
||||||
|
return blockExtended;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get one block by its hash
|
* Get one block by its hash
|
||||||
*/
|
*/
|
||||||
@ -831,7 +843,11 @@ class Blocks {
|
|||||||
|
|
||||||
// Bitcoin network, add our custom data on top
|
// Bitcoin network, add our custom data on top
|
||||||
const block: IEsploraApi.Block = await bitcoinCoreApi.$getBlock(hash);
|
const block: IEsploraApi.Block = await bitcoinCoreApi.$getBlock(hash);
|
||||||
return await this.$indexBlock(block.height);
|
if (block.stale) {
|
||||||
|
return await this.$indexStaleBlock(hash);
|
||||||
|
} else {
|
||||||
|
return await this.$indexBlock(block.height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async $getStrippedBlockTransactions(hash: string, skipMemoryCache = false,
|
public async $getStrippedBlockTransactions(hash: string, skipMemoryCache = false,
|
||||||
|
@ -227,6 +227,7 @@ export interface BlockExtension {
|
|||||||
*/
|
*/
|
||||||
export interface BlockExtended extends IEsploraApi.Block {
|
export interface BlockExtended extends IEsploraApi.Block {
|
||||||
extras: BlockExtension;
|
extras: BlockExtension;
|
||||||
|
canonical?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BlockSummary {
|
export interface BlockSummary {
|
||||||
|
@ -62,8 +62,7 @@ class BlocksAuditRepositories {
|
|||||||
public async $getBlockAudit(hash: string): Promise<any> {
|
public async $getBlockAudit(hash: string): Promise<any> {
|
||||||
try {
|
try {
|
||||||
const [rows]: any[] = await DB.query(
|
const [rows]: any[] = await DB.query(
|
||||||
`SELECT blocks.height, blocks.hash as id, UNIX_TIMESTAMP(blocks.blockTimestamp) as timestamp, blocks.size,
|
`SELECT blocks_audits.height, blocks_audits.hash as id, UNIX_TIMESTAMP(blocks_audits.time) as timestamp,
|
||||||
blocks.weight, blocks.tx_count,
|
|
||||||
template,
|
template,
|
||||||
missing_txs as missingTxs,
|
missing_txs as missingTxs,
|
||||||
added_txs as addedTxs,
|
added_txs as addedTxs,
|
||||||
@ -73,7 +72,6 @@ class BlocksAuditRepositories {
|
|||||||
expected_fees as expectedFees,
|
expected_fees as expectedFees,
|
||||||
expected_weight as expectedWeight
|
expected_weight as expectedWeight
|
||||||
FROM blocks_audits
|
FROM blocks_audits
|
||||||
JOIN blocks ON blocks.hash = blocks_audits.hash
|
|
||||||
JOIN blocks_templates ON blocks_templates.id = blocks_audits.hash
|
JOIN blocks_templates ON blocks_templates.id = blocks_audits.hash
|
||||||
WHERE blocks_audits.hash = "${hash}"
|
WHERE blocks_audits.hash = "${hash}"
|
||||||
`);
|
`);
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
<div class="container-xl" (window:resize)="onResize($event)">
|
<div class="container-xl" (window:resize)="onResize($event)">
|
||||||
|
|
||||||
<div class="title-block" [class.time-ltr]="timeLtr" id="block">
|
<div class="title-block" [class.time-ltr]="timeLtr" id="block">
|
||||||
|
<div *ngIf="block?.stale" class="alert alert-mempool" role="alert">
|
||||||
|
<span i18n="block.reorged|Block reorg" class="alert-text">This block does not belong to the main chain, it has been replaced by:</span>
|
||||||
|
<app-truncate [text]="block.canonical" [lastChars]="12" [link]="['/block/' | relativeUrl, block.canonical]" [maxWidth]="480"></app-truncate>
|
||||||
|
</div>
|
||||||
<h1>
|
<h1>
|
||||||
<ng-container *ngIf="blockHeight == null || blockHeight > 0; else genesis" i18n="shared.block-title">Block</ng-container>
|
<ng-container *ngIf="blockHeight == null || blockHeight > 0; else genesis" i18n="shared.block-title">Block</ng-container>
|
||||||
<ng-template #genesis i18n="@@2303359202781425764">Genesis</ng-template>
|
<ng-template #genesis i18n="@@2303359202781425764">Genesis</ng-template>
|
||||||
@ -23,6 +27,8 @@
|
|||||||
|
|
||||||
<div class="grow"></div>
|
<div class="grow"></div>
|
||||||
|
|
||||||
|
<button *ngIf="block?.stale" type="button" class="btn btn-sm btn-danger container-button" i18n="block.stale|Stale block state">Stale</button>
|
||||||
|
|
||||||
<button [routerLink]="['/' | relativeUrl]" class="btn btn-sm">✕</button>
|
<button [routerLink]="['/' | relativeUrl]" class="btn btn-sm">✕</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,3 +1,26 @@
|
|||||||
|
.title-block {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: baseline;
|
||||||
|
@media (min-width: 650px) {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
margin: 0rem;
|
||||||
|
margin-right: 15px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-mempool {
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container-button {
|
||||||
|
align-self: center;
|
||||||
|
margin-right: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.qr-wrapper {
|
.qr-wrapper {
|
||||||
background-color: #FFF;
|
background-color: #FFF;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
@ -120,6 +120,8 @@ export interface Block {
|
|||||||
size: number;
|
size: number;
|
||||||
weight: number;
|
weight: number;
|
||||||
previousblockhash: string;
|
previousblockhash: string;
|
||||||
|
stale?: boolean;
|
||||||
|
canonical?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Address {
|
export interface Address {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user