From 66d88abdc585b9cb471c2f4dd4f72c58dd97af0f Mon Sep 17 00:00:00 2001 From: Mononaut Date: Sun, 26 Nov 2023 06:59:43 +0000 Subject: [PATCH] Refactor difficulty reindexing to process blocks in height order --- backend/src/api/mining/mining.ts | 77 +++++++++++++------- backend/src/repositories/BlocksRepository.ts | 2 +- 2 files changed, 51 insertions(+), 28 deletions(-) diff --git a/backend/src/api/mining/mining.ts b/backend/src/api/mining/mining.ts index d9d5995da..b23ad04c5 100644 --- a/backend/src/api/mining/mining.ts +++ b/backend/src/api/mining/mining.ts @@ -15,6 +15,13 @@ import bitcoinApi from '../bitcoin/bitcoin-api-factory'; import { IEsploraApi } from '../bitcoin/esplora-api.interface'; import database from '../../database'; +interface DifficultyBlock { + timestamp: number, + height: number, + bits: number, + difficulty: number, +} + class Mining { private blocksPriceIndexingRunning = false; public lastHashrateIndexingDate: number | null = null; @@ -421,6 +428,7 @@ class Mining { indexedHeights[height] = true; } + // gets {time, height, difficulty, bits} of blocks in ascending order of height const blocks: any = await BlocksRepository.$getBlocksDifficulty(); const genesisBlock: IEsploraApi.Block = await bitcoinApi.$getBlock(await bitcoinApi.$getBlockHash(0)); let currentDifficulty = genesisBlock.difficulty; @@ -436,41 +444,45 @@ class Mining { }); } - const oldestConsecutiveBlock = await BlocksRepository.$getOldestConsecutiveBlock(); - if (config.MEMPOOL.INDEXING_BLOCKS_AMOUNT !== -1) { - currentBits = oldestConsecutiveBlock.bits; - currentDifficulty = oldestConsecutiveBlock.difficulty; + if (!blocks?.length) { + // no blocks in database yet + return; } + const oldestConsecutiveBlock = this.getOldestConsecutiveBlock(blocks); + + currentBits = oldestConsecutiveBlock.bits; + currentDifficulty = oldestConsecutiveBlock.difficulty; + let totalBlockChecked = 0; let timer = new Date().getTime() / 1000; for (const block of blocks) { + // skip until the first block after the oldest consecutive block + if (block.height <= oldestConsecutiveBlock.height) { + continue; + } + + // difficulty has changed between two consecutive blocks! if (block.bits !== currentBits) { - if (indexedHeights[block.height] === true) { // Already indexed - if (block.height >= oldestConsecutiveBlock.height) { - currentDifficulty = block.difficulty; - currentBits = block.bits; - } - continue; + // skip if already indexed + if (indexedHeights[block.height] !== true) { + let adjustment = block.difficulty / currentDifficulty; + adjustment = Math.round(adjustment * 1000000) / 1000000; // Remove float point noise + + await DifficultyAdjustmentsRepository.$saveAdjustments({ + time: block.time, + height: block.height, + difficulty: block.difficulty, + adjustment: adjustment, + }); + + totalIndexed++; } - - let adjustment = block.difficulty / currentDifficulty; - adjustment = Math.round(adjustment * 1000000) / 1000000; // Remove float point noise - - await DifficultyAdjustmentsRepository.$saveAdjustments({ - time: block.time, - height: block.height, - difficulty: block.difficulty, - adjustment: adjustment, - }); - - totalIndexed++; - if (block.height >= oldestConsecutiveBlock.height) { - currentDifficulty = block.difficulty; - currentBits = block.bits; - } - } + // update the current difficulty + currentDifficulty = block.difficulty; + currentBits = block.bits; + } totalBlockChecked++; const elapsedSeconds = Math.max(1, Math.round((new Date().getTime() / 1000) - timer)); @@ -633,6 +645,17 @@ class Mining { default: return 86400 * scale; } } + + // Finds the oldest block in a consecutive chain back from the tip + // assumes `blocks` is sorted in ascending height order + private getOldestConsecutiveBlock(blocks: DifficultyBlock[]): DifficultyBlock { + for (let i = blocks.length - 1; i > 0; i--) { + if ((blocks[i].height - blocks[i - 1].height) > 1) { + return blocks[i]; + } + } + return blocks[0]; + } } export default new Mining(); diff --git a/backend/src/repositories/BlocksRepository.ts b/backend/src/repositories/BlocksRepository.ts index 0953f9b84..a798c40f8 100644 --- a/backend/src/repositories/BlocksRepository.ts +++ b/backend/src/repositories/BlocksRepository.ts @@ -541,7 +541,7 @@ class BlocksRepository { */ public async $getBlocksDifficulty(): Promise { try { - const [rows]: any[] = await DB.query(`SELECT UNIX_TIMESTAMP(blockTimestamp) as time, height, difficulty, bits FROM blocks`); + const [rows]: any[] = await DB.query(`SELECT UNIX_TIMESTAMP(blockTimestamp) as time, height, difficulty, bits FROM blocks ORDER BY height ASC`); return rows; } catch (e) { logger.err('Cannot get blocks difficulty list from the db. Reason: ' + (e instanceof Error ? e.message : e));