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 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();
 | 
			
		||||
 | 
			
		||||
@ -541,7 +541,7 @@ class BlocksRepository {
 | 
			
		||||
   */
 | 
			
		||||
  public async $getBlocksDifficulty(): Promise<object[]> {
 | 
			
		||||
    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));
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user