Don't get stuck fetching orphans

This commit is contained in:
Mononaut 2024-05-07 01:03:59 +00:00
parent d92bf14b50
commit 0990cfe072
No known key found for this signature in database
GPG Key ID: A3F058E41374C04E
2 changed files with 53 additions and 20 deletions

View File

@ -839,9 +839,12 @@ class Blocks {
} else { } else {
this.currentBlockHeight++; this.currentBlockHeight++;
logger.debug(`New block found (#${this.currentBlockHeight})!`); logger.debug(`New block found (#${this.currentBlockHeight})!`);
// skip updating the orphan block cache if we've fallen behind the chain tip
if (this.currentBlockHeight >= blockHeightTip - 2) {
this.updateTimerProgress(timer, `getting orphaned blocks for ${this.currentBlockHeight}`); this.updateTimerProgress(timer, `getting orphaned blocks for ${this.currentBlockHeight}`);
await chainTips.updateOrphanedBlocks(); await chainTips.updateOrphanedBlocks();
} }
}
this.updateTimerProgress(timer, `getting block data for ${this.currentBlockHeight}`); this.updateTimerProgress(timer, `getting block data for ${this.currentBlockHeight}`);
const blockHash = await bitcoinCoreApi.$getBlockHash(this.currentBlockHeight); const blockHash = await bitcoinCoreApi.$getBlockHash(this.currentBlockHeight);

View File

@ -12,32 +12,68 @@ export interface OrphanedBlock {
height: number; height: number;
hash: string; hash: string;
status: 'valid-fork' | 'valid-headers' | 'headers-only'; status: 'valid-fork' | 'valid-headers' | 'headers-only';
prevhash: string;
} }
class ChainTips { class ChainTips {
private chainTips: ChainTip[] = []; private chainTips: ChainTip[] = [];
private orphanedBlocks: OrphanedBlock[] = []; private orphanedBlocks: { [hash: string]: OrphanedBlock } = {};
private blockCache: { [hash: string]: OrphanedBlock } = {};
private orphansByHeight: { [height: number]: OrphanedBlock[] } = {};
public async updateOrphanedBlocks(): Promise<void> { public async updateOrphanedBlocks(): Promise<void> {
try { try {
this.chainTips = await bitcoinClient.getChainTips(); this.chainTips = await bitcoinClient.getChainTips();
this.orphanedBlocks = [];
const start = Date.now();
const breakAt = start + 10000;
let newOrphans = 0;
this.orphanedBlocks = {};
for (const chain of this.chainTips) { for (const chain of this.chainTips) {
if (chain.status === 'valid-fork' || chain.status === 'valid-headers') { if (chain.status === 'valid-fork' || chain.status === 'valid-headers') {
let block = await bitcoinClient.getBlock(chain.hash); const orphans: OrphanedBlock[] = [];
while (block && block.confirmations === -1) { let hash = chain.hash;
this.orphanedBlocks.push({ do {
let orphan = this.blockCache[hash];
if (!orphan) {
const block = await bitcoinClient.getBlock(hash);
if (block && block.confirmations === -1) {
newOrphans++;
orphan = {
height: block.height, height: block.height,
hash: block.hash, hash: block.hash,
status: chain.status status: chain.status,
}); prevhash: block.previousblockhash,
block = await bitcoinClient.getBlock(block.previousblockhash); };
this.blockCache[hash] = orphan;
} }
} }
if (orphan) {
orphans.push(orphan);
}
hash = orphan?.prevhash;
} while (hash && (Date.now() < breakAt));
for (const orphan of orphans) {
this.orphanedBlocks[orphan.hash] = orphan;
}
}
if (Date.now() >= breakAt) {
logger.debug(`Breaking orphaned blocks updater after 10s, will continue next block`);
break;
}
} }
logger.debug(`Updated orphaned blocks cache. Found ${this.orphanedBlocks.length} orphaned blocks`); this.orphansByHeight = {};
const allOrphans = Object.values(this.orphanedBlocks);
for (const orphan of allOrphans) {
if (!this.orphansByHeight[orphan.height]) {
this.orphansByHeight[orphan.height] = [];
}
this.orphansByHeight[orphan.height].push(orphan);
}
logger.debug(`Updated orphaned blocks cache. Fetched ${newOrphans} new orphaned blocks. Total ${allOrphans.length}`);
} catch (e) { } catch (e) {
logger.err(`Cannot get fetch orphaned blocks. Reason: ${e instanceof Error ? e.message : e}`); logger.err(`Cannot get fetch orphaned blocks. Reason: ${e instanceof Error ? e.message : e}`);
} }
@ -48,13 +84,7 @@ class ChainTips {
return []; return [];
} }
const orphans: OrphanedBlock[] = []; return this.orphansByHeight[height] || [];
for (const block of this.orphanedBlocks) {
if (block.height === height) {
orphans.push(block);
}
}
return orphans;
} }
} }