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,8 +843,12 @@ 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); | ||||||
|  |     if (block.stale) { | ||||||
|  |       return await this.$indexStaleBlock(hash); | ||||||
|  |     } else { | ||||||
|       return await this.$indexBlock(block.height); |       return await this.$indexBlock(block.height); | ||||||
|     } |     } | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|   public async $getStrippedBlockTransactions(hash: string, skipMemoryCache = false, |   public async $getStrippedBlockTransactions(hash: string, skipMemoryCache = false, | ||||||
|     skipDBLookup = false, cpfpSummary?: CpfpSummary, blockHeight?: number): Promise<TransactionStripped[]> |     skipDBLookup = false, cpfpSummary?: CpfpSummary, blockHeight?: number): Promise<TransactionStripped[]> | ||||||
|  | |||||||
| @ -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