Refactor difficulty reindexing to process blocks in height order
This commit is contained in:
parent
e7e25e1632
commit
66d88abdc5
@ -15,6 +15,13 @@ import bitcoinApi from '../bitcoin/bitcoin-api-factory';
|
|||||||
import { IEsploraApi } from '../bitcoin/esplora-api.interface';
|
import { IEsploraApi } from '../bitcoin/esplora-api.interface';
|
||||||
import database from '../../database';
|
import database from '../../database';
|
||||||
|
|
||||||
|
interface DifficultyBlock {
|
||||||
|
timestamp: number,
|
||||||
|
height: number,
|
||||||
|
bits: number,
|
||||||
|
difficulty: number,
|
||||||
|
}
|
||||||
|
|
||||||
class Mining {
|
class Mining {
|
||||||
private blocksPriceIndexingRunning = false;
|
private blocksPriceIndexingRunning = false;
|
||||||
public lastHashrateIndexingDate: number | null = null;
|
public lastHashrateIndexingDate: number | null = null;
|
||||||
@ -421,6 +428,7 @@ class Mining {
|
|||||||
indexedHeights[height] = true;
|
indexedHeights[height] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// gets {time, height, difficulty, bits} of blocks in ascending order of height
|
||||||
const blocks: any = await BlocksRepository.$getBlocksDifficulty();
|
const blocks: any = await BlocksRepository.$getBlocksDifficulty();
|
||||||
const genesisBlock: IEsploraApi.Block = await bitcoinApi.$getBlock(await bitcoinApi.$getBlockHash(0));
|
const genesisBlock: IEsploraApi.Block = await bitcoinApi.$getBlock(await bitcoinApi.$getBlockHash(0));
|
||||||
let currentDifficulty = genesisBlock.difficulty;
|
let currentDifficulty = genesisBlock.difficulty;
|
||||||
@ -436,41 +444,45 @@ class Mining {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const oldestConsecutiveBlock = await BlocksRepository.$getOldestConsecutiveBlock();
|
if (!blocks?.length) {
|
||||||
if (config.MEMPOOL.INDEXING_BLOCKS_AMOUNT !== -1) {
|
// no blocks in database yet
|
||||||
currentBits = oldestConsecutiveBlock.bits;
|
return;
|
||||||
currentDifficulty = oldestConsecutiveBlock.difficulty;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const oldestConsecutiveBlock = this.getOldestConsecutiveBlock(blocks);
|
||||||
|
|
||||||
|
currentBits = oldestConsecutiveBlock.bits;
|
||||||
|
currentDifficulty = oldestConsecutiveBlock.difficulty;
|
||||||
|
|
||||||
let totalBlockChecked = 0;
|
let totalBlockChecked = 0;
|
||||||
let timer = new Date().getTime() / 1000;
|
let timer = new Date().getTime() / 1000;
|
||||||
|
|
||||||
for (const block of blocks) {
|
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 (block.bits !== currentBits) {
|
||||||
if (indexedHeights[block.height] === true) { // Already indexed
|
// skip if already indexed
|
||||||
if (block.height >= oldestConsecutiveBlock.height) {
|
if (indexedHeights[block.height] !== true) {
|
||||||
currentDifficulty = block.difficulty;
|
let adjustment = block.difficulty / currentDifficulty;
|
||||||
currentBits = block.bits;
|
adjustment = Math.round(adjustment * 1000000) / 1000000; // Remove float point noise
|
||||||
}
|
|
||||||
continue;
|
await DifficultyAdjustmentsRepository.$saveAdjustments({
|
||||||
|
time: block.time,
|
||||||
|
height: block.height,
|
||||||
|
difficulty: block.difficulty,
|
||||||
|
adjustment: adjustment,
|
||||||
|
});
|
||||||
|
|
||||||
|
totalIndexed++;
|
||||||
}
|
}
|
||||||
|
// update the current difficulty
|
||||||
let adjustment = block.difficulty / currentDifficulty;
|
currentDifficulty = block.difficulty;
|
||||||
adjustment = Math.round(adjustment * 1000000) / 1000000; // Remove float point noise
|
currentBits = block.bits;
|
||||||
|
}
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
totalBlockChecked++;
|
totalBlockChecked++;
|
||||||
const elapsedSeconds = Math.max(1, Math.round((new Date().getTime() / 1000) - timer));
|
const elapsedSeconds = Math.max(1, Math.round((new Date().getTime() / 1000) - timer));
|
||||||
@ -633,6 +645,17 @@ class Mining {
|
|||||||
default: return 86400 * scale;
|
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();
|
export default new Mining();
|
||||||
|
@ -541,7 +541,7 @@ class BlocksRepository {
|
|||||||
*/
|
*/
|
||||||
public async $getBlocksDifficulty(): Promise<object[]> {
|
public async $getBlocksDifficulty(): Promise<object[]> {
|
||||||
try {
|
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;
|
return rows;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.err('Cannot get blocks difficulty list from the db. Reason: ' + (e instanceof Error ? e.message : e));
|
logger.err('Cannot get blocks difficulty list from the db. Reason: ' + (e instanceof Error ? e.message : e));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user