diff --git a/backend/src/api/bitcoin/bitcoin-api.interface.ts b/backend/src/api/bitcoin/bitcoin-api.interface.ts index 194beebee..018d30223 100644 --- a/backend/src/api/bitcoin/bitcoin-api.interface.ts +++ b/backend/src/api/bitcoin/bitcoin-api.interface.ts @@ -113,4 +113,46 @@ export namespace IBitcoinApi { status: 'invalid' | 'headers-only' | 'valid-headers' | 'valid-fork' | 'active'; } + export interface BlockchainInfo { + chain: number; // (string) current network name as defined in BIP70 (main, test, regtest) + blocks: number; // (numeric) the current number of blocks processed in the server + headers: number; // (numeric) the current number of headers we have validated + bestblockhash: string, // (string) the hash of the currently best block + difficulty: number; // (numeric) the current difficulty + mediantime: number; // (numeric) median time for the current best block + verificationprogress: number; // (numeric) estimate of verification progress [0..1] + initialblockdownload: boolean; // (bool) (debug information) estimate of whether this node is in Initial Block Download mode. + chainwork: string // (string) total amount of work in active chain, in hexadecimal + size_on_disk: number; // (numeric) the estimated size of the block and undo files on disk + pruned: number; // (boolean) if the blocks are subject to pruning + pruneheight: number; // (numeric) lowest-height complete block stored (only present if pruning is enabled) + automatic_pruning: number; // (boolean) whether automatic pruning is enabled (only present if pruning is enabled) + prune_target_size: number; // (numeric) the target size used by pruning (only present if automatic pruning is enabled) + softforks: SoftFork[]; // (array) status of softforks in progress + bip9_softforks: { [name: string]: Bip9SoftForks[] } // (object) status of BIP9 softforks in progress + warnings: string; // (string) any network and blockchain warnings. + } + + interface SoftFork { + id: string; // (string) name of softfork + version: number; // (numeric) block version + reject: { // (object) progress toward rejecting pre-softfork blocks + status: boolean; // (boolean) true if threshold reached + }, + } + interface Bip9SoftForks { + status: number; // (string) one of defined, started, locked_in, active, failed + bit: number; // (numeric) the bit (0-28) in the block version field used to signal this softfork (only for started status) + startTime: number; // (numeric) the minimum median time past of a block at which the bit gains its meaning + timeout: number; // (numeric) the median time past of a block at which the deployment is considered failed if not yet locked in + since: number; // (numeric) height of the first block to which the status applies + statistics: { // (object) numeric statistics about BIP9 signalling for a softfork (only for started status) + period: number; // (numeric) the length in blocks of the BIP9 signalling period + threshold: number; // (numeric) the number of blocks with the version bit set required to activate the feature + elapsed: number; // (numeric) the number of blocks elapsed since the beginning of the current period + count: number; // (numeric) the number of blocks with the version bit set in the current period + possible: boolean; // (boolean) returns false if there are not enough blocks left in this period to pass activation threshold + } + } + } diff --git a/backend/src/api/bitcoin/bitcoin-base.api.ts b/backend/src/api/bitcoin/bitcoin-base.api.ts index 2384c92e2..a447da5fe 100644 --- a/backend/src/api/bitcoin/bitcoin-base.api.ts +++ b/backend/src/api/bitcoin/bitcoin-base.api.ts @@ -40,6 +40,10 @@ class BitcoinBaseApi { } return this.bitcoindClient.getMempoolInfo(); } + + $getBlockchainInfo(): Promise { + return this.bitcoindClient.getBlockchainInfo(); + } } export default new BitcoinBaseApi(); diff --git a/backend/src/api/blocks.ts b/backend/src/api/blocks.ts index fbfcc2828..3bed19c14 100644 --- a/backend/src/api/blocks.ts +++ b/backend/src/api/blocks.ts @@ -6,6 +6,7 @@ import { BlockExtended, TransactionExtended } from '../mempool.interfaces'; import { Common } from './common'; import diskCache from './disk-cache'; import transactionUtils from './transaction-utils'; +import bitcoinBaseApi from './bitcoin/bitcoin-base.api'; class Blocks { private static INITIAL_BLOCK_AMOUNT = 8; @@ -45,15 +46,21 @@ class Blocks { } if (!this.lastDifficultyAdjustmentTime) { - const heightDiff = blockHeightTip % 2016; - const blockHash = await bitcoinApi.$getBlockHash(blockHeightTip - heightDiff); - const block = await bitcoinApi.$getBlock(blockHash); - this.lastDifficultyAdjustmentTime = block.timestamp; - this.currentDifficulty = block.difficulty; + const blockchainInfo = await bitcoinBaseApi.$getBlockchainInfo(); + if (blockchainInfo.blocks === blockchainInfo.headers) { + const heightDiff = blockHeightTip % 2016; + const blockHash = await bitcoinApi.$getBlockHash(blockHeightTip - heightDiff); + const block = await bitcoinApi.$getBlock(blockHash); + this.lastDifficultyAdjustmentTime = block.timestamp; + this.currentDifficulty = block.difficulty; - const previousPeriodBlockHash = await bitcoinApi.$getBlockHash(blockHeightTip - heightDiff - 2016); - const previousPeriodBlock = await bitcoinApi.$getBlock(previousPeriodBlockHash); - this.previousDifficultyRetarget = (block.difficulty - previousPeriodBlock.difficulty) / previousPeriodBlock.difficulty * 100; + const previousPeriodBlockHash = await bitcoinApi.$getBlockHash(blockHeightTip - heightDiff - 2016); + const previousPeriodBlock = await bitcoinApi.$getBlock(previousPeriodBlockHash); + this.previousDifficultyRetarget = (block.difficulty - previousPeriodBlock.difficulty) / previousPeriodBlock.difficulty * 100; + logger.debug(`Initial difficulty adjustment data set.`); + } else { + logger.debug(`Blockchain headers (${blockchainInfo.headers}) and blocks (${blockchainInfo.blocks}) not in sync. Waiting...`); + } } while (this.currentBlockHeight < blockHeightTip) {