2020-12-20 22:36:36 +07:00
import config from '../config' ;
import bitcoinApi from './bitcoin/bitcoin-api-factory' ;
2020-10-13 15:27:52 +07:00
import logger from '../logger' ;
2020-02-23 19:16:50 +07:00
import memPool from './mempool' ;
2022-01-05 15:41:14 +09:00
import { BlockExtended , PoolTag , TransactionExtended , TransactionMinerInfo } from '../mempool.interfaces' ;
2020-05-24 16:29:30 +07:00
import { Common } from './common' ;
2020-10-27 00:05:06 +07:00
import diskCache from './disk-cache' ;
2020-12-21 23:08:34 +07:00
import transactionUtils from './transaction-utils' ;
2021-09-15 01:47:24 +04:00
import bitcoinClient from './bitcoin/bitcoin-client' ;
2022-01-05 15:41:14 +09:00
import { IEsploraApi } from './bitcoin/esplora-api.interface' ;
import poolsRepository from '../repositories/PoolsRepository' ;
import blocksRepository from '../repositories/BlocksRepository' ;
2022-02-08 15:47:43 +09:00
import loadingIndicators from './loading-indicators' ;
2022-03-13 11:38:45 +01:00
import BitcoinApi from './bitcoin/bitcoin-api' ;
2019-07-21 17:59:47 +03:00
class Blocks {
2020-12-28 04:47:22 +07:00
private blocks : BlockExtended [ ] = [ ] ;
2019-08-29 01:17:31 +02:00
private currentBlockHeight = 0 ;
2021-07-23 14:35:04 +03:00
private currentDifficulty = 0 ;
2020-09-21 19:41:12 +07:00
private lastDifficultyAdjustmentTime = 0 ;
2021-07-23 14:35:04 +03:00
private previousDifficultyRetarget = 0 ;
2020-12-28 04:47:22 +07:00
private newBlockCallbacks : ( ( block : BlockExtended , txIds : string [ ] , transactions : TransactionExtended [ ] ) = > void ) [ ] = [ ] ;
2022-01-24 19:57:54 +09:00
private blockIndexingStarted = false ;
2022-02-21 17:34:07 +09:00
public blockIndexingCompleted = false ;
2019-08-29 01:17:31 +02:00
2020-02-16 22:15:07 +07:00
constructor ( ) { }
2019-07-21 17:59:47 +03:00
2020-12-28 04:47:22 +07:00
public getBlocks ( ) : BlockExtended [ ] {
2019-07-21 17:59:47 +03:00
return this . blocks ;
}
2020-12-28 04:47:22 +07:00
public setBlocks ( blocks : BlockExtended [ ] ) {
2020-02-29 21:52:04 +07:00
this . blocks = blocks ;
}
2020-12-28 04:47:22 +07:00
public setNewBlockCallback ( fn : ( block : BlockExtended , txIds : string [ ] , transactions : TransactionExtended [ ] ) = > void ) {
2020-09-27 17:21:18 +07:00
this . newBlockCallbacks . push ( fn ) ;
2019-07-21 17:59:47 +03:00
}
2022-01-05 15:41:14 +09:00
/ * *
* Return the list of transaction for a block
* @param blockHash
* @param blockHeight
* @param onlyCoinbase - Set to true if you only need the coinbase transaction
* @returns Promise < TransactionExtended [ ] >
* /
2022-02-10 23:02:12 +09:00
private async $getTransactionsExtended (
blockHash : string ,
blockHeight : number ,
onlyCoinbase : boolean ,
quiet : boolean = false ,
) : Promise < TransactionExtended [ ] > {
2022-01-05 15:41:14 +09:00
const transactions : TransactionExtended [ ] = [ ] ;
const txIds : string [ ] = await bitcoinApi . $getTxIdsForBlock ( blockHash ) ;
const mempool = memPool . getMempool ( ) ;
let transactionsFound = 0 ;
let transactionsFetched = 0 ;
for ( let i = 0 ; i < txIds . length ; i ++ ) {
if ( mempool [ txIds [ i ] ] ) {
// We update blocks before the mempool (index.ts), therefore we can
// optimize here by directly fetching txs in the "outdated" mempool
transactions . push ( mempool [ txIds [ i ] ] ) ;
transactionsFound ++ ;
2022-02-11 21:25:58 +09:00
} else if ( config . MEMPOOL . BACKEND === 'esplora' || ! memPool . hasPriority ( ) || i === 0 ) {
2022-01-05 15:41:14 +09:00
// Otherwise we fetch the tx data through backend services (esplora, electrum, core rpc...)
2022-02-10 23:02:12 +09:00
if ( ! quiet && ( i % ( Math . round ( ( txIds . length ) / 10 ) ) === 0 || i + 1 === txIds . length ) ) { // Avoid log spam
2022-01-05 15:41:14 +09:00
logger . debug ( ` Indexing tx ${ i + 1 } of ${ txIds . length } in block # ${ blockHeight } ` ) ;
}
try {
const tx = await transactionUtils . $getTransactionExtended ( txIds [ i ] ) ;
transactions . push ( tx ) ;
transactionsFetched ++ ;
} catch ( e ) {
logger . debug ( 'Error fetching block tx: ' + ( e instanceof Error ? e.message : e ) ) ;
if ( i === 0 ) {
throw new Error ( 'Failed to fetch Coinbase transaction: ' + txIds [ i ] ) ;
}
}
}
if ( onlyCoinbase === true ) {
break ; // Fetch the first transaction and exit
}
}
transactions . forEach ( ( tx ) = > {
if ( ! tx . cpfpChecked ) {
Common . setRelativesAndGetCpfpInfo ( tx , mempool ) ; // Child Pay For Parent
}
} ) ;
2022-02-10 23:02:12 +09:00
if ( ! quiet ) {
logger . debug ( ` ${ transactionsFound } of ${ txIds . length } found in mempool. ${ transactionsFetched } fetched through backend service. ` ) ;
}
2022-01-05 15:41:14 +09:00
return transactions ;
}
/ * *
* Return a block with additional data ( reward , coinbase , fees . . . )
* @param block
* @param transactions
* @returns BlockExtended
* /
2022-03-13 11:38:45 +01:00
private async $getBlockExtended ( block : IEsploraApi.Block , transactions : TransactionExtended [ ] ) : Promise < BlockExtended > {
const blockExtended : BlockExtended = Object . assign ( { extras : { } } , block ) ;
2022-02-08 15:47:43 +09:00
blockExtended . extras . reward = transactions [ 0 ] . vout . reduce ( ( acc , curr ) = > acc + curr . value , 0 ) ;
blockExtended . extras . coinbaseTx = transactionUtils . stripCoinbaseTransaction ( transactions [ 0 ] ) ;
2022-03-16 12:10:18 +01:00
blockExtended . extras . coinbaseRaw = blockExtended . extras . coinbaseTx . vin [ 0 ] . scriptsig ;
2022-03-11 14:54:34 +01:00
if ( block . height === 0 ) {
2022-03-13 11:38:45 +01:00
blockExtended . extras . medianFee = 0 ; // 50th percentiles
blockExtended . extras . feeRange = [ 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ;
blockExtended . extras . totalFees = 0 ;
blockExtended . extras . avgFee = 0 ;
blockExtended . extras . avgFeeRate = 0 ;
} else {
2022-03-15 20:57:27 +01:00
const stats = await bitcoinClient . getBlockStats ( block . id , [
'feerate_percentiles' , 'minfeerate' , 'maxfeerate' , 'totalfee' , 'avgfee' , 'avgfeerate'
] ) ;
2022-03-11 14:54:34 +01:00
blockExtended . extras . medianFee = stats . feerate_percentiles [ 2 ] ; // 50th percentiles
2022-03-13 11:38:45 +01:00
blockExtended . extras . feeRange = [ stats . minfeerate , stats . feerate_percentiles , stats . maxfeerate ] . flat ( ) ;
blockExtended . extras . totalFees = stats . totalfee ;
blockExtended . extras . avgFee = stats . avgfee ;
blockExtended . extras . avgFeeRate = stats . avgfeerate ;
}
2022-01-05 15:41:14 +09:00
2022-02-15 16:02:30 +09:00
if ( Common . indexingEnabled ( ) ) {
2022-02-08 15:47:43 +09:00
let pool : PoolTag ;
if ( blockExtended . extras ? . coinbaseTx !== undefined ) {
pool = await this . $findBlockMiner ( blockExtended . extras ? . coinbaseTx ) ;
} else {
pool = await poolsRepository . $getUnknownPool ( ) ;
}
2022-02-10 10:25:14 +09:00
blockExtended . extras . pool = {
id : pool.id ,
name : pool.name
} ;
2022-02-08 15:47:43 +09:00
}
2022-01-05 15:41:14 +09:00
return blockExtended ;
}
/ * *
* Try to find which miner found the block
* @param txMinerInfo
* @returns
* /
2022-01-20 17:20:02 +09:00
private async $findBlockMiner ( txMinerInfo : TransactionMinerInfo | undefined ) : Promise < PoolTag > {
2022-01-25 18:33:46 +09:00
if ( txMinerInfo === undefined || txMinerInfo . vout . length < 1 ) {
2022-01-06 19:59:33 +09:00
return await poolsRepository . $getUnknownPool ( ) ;
2022-01-05 15:41:14 +09:00
}
const asciiScriptSig = transactionUtils . hex2ascii ( txMinerInfo . vin [ 0 ] . scriptsig ) ;
const address = txMinerInfo . vout [ 0 ] . scriptpubkey_address ;
const pools : PoolTag [ ] = await poolsRepository . $getPools ( ) ;
for ( let i = 0 ; i < pools . length ; ++ i ) {
if ( address !== undefined ) {
2022-01-20 17:20:02 +09:00
const addresses : string [ ] = JSON . parse ( pools [ i ] . addresses ) ;
2022-01-05 15:41:14 +09:00
if ( addresses . indexOf ( address ) !== - 1 ) {
return pools [ i ] ;
}
}
2022-01-20 17:20:02 +09:00
const regexes : string [ ] = JSON . parse ( pools [ i ] . regexes ) ;
2022-01-05 15:41:14 +09:00
for ( let y = 0 ; y < regexes . length ; ++ y ) {
2022-01-20 17:20:02 +09:00
const match = asciiScriptSig . match ( regexes [ y ] ) ;
2022-01-05 15:41:14 +09:00
if ( match !== null ) {
return pools [ i ] ;
}
}
}
2022-01-06 19:59:33 +09:00
return await poolsRepository . $getUnknownPool ( ) ;
2022-01-05 15:41:14 +09:00
}
/ * *
2022-03-06 12:47:16 +01:00
* [ INDEXING ] Index all blocks metadata for the mining dashboard
2022-01-05 15:41:14 +09:00
* /
public async $generateBlockDatabase() {
2022-02-19 20:45:02 +09:00
if ( this . blockIndexingStarted ) {
2022-01-21 00:08:51 +09:00
return ;
}
2022-01-24 19:57:54 +09:00
const blockchainInfo = await bitcoinClient . getBlockchainInfo ( ) ;
2022-02-08 15:47:43 +09:00
if ( blockchainInfo . blocks !== blockchainInfo . headers ) { // Wait for node to sync
2022-01-24 19:57:54 +09:00
return ;
}
this . blockIndexingStarted = true ;
2022-01-24 15:36:30 +09:00
try {
2022-01-24 19:57:54 +09:00
let currentBlockHeight = blockchainInfo . blocks ;
2022-01-25 18:33:46 +09:00
let indexingBlockAmount = config . MEMPOOL . INDEXING_BLOCKS_AMOUNT ;
if ( indexingBlockAmount <= - 1 ) {
indexingBlockAmount = currentBlockHeight + 1 ;
}
const lastBlockToIndex = Math . max ( 0 , currentBlockHeight - indexingBlockAmount + 1 ) ;
2022-01-24 15:36:30 +09:00
2022-01-24 17:43:11 +09:00
logger . info ( ` Indexing blocks from # ${ currentBlockHeight } to # ${ lastBlockToIndex } ` ) ;
2022-01-24 15:36:30 +09:00
const chunkSize = 10000 ;
2022-02-17 13:10:04 +09:00
let totaIndexed = await blocksRepository . $blockCount ( null , null ) ;
2022-02-16 21:20:28 +09:00
let indexedThisRun = 0 ;
2022-03-10 14:21:11 +01:00
const startedAt = new Date ( ) . getTime ( ) / 1000 ;
let timer = new Date ( ) . getTime ( ) / 1000 ;
2022-01-24 17:43:11 +09:00
while ( currentBlockHeight >= lastBlockToIndex ) {
const endBlock = Math . max ( 0 , lastBlockToIndex , currentBlockHeight - chunkSize + 1 ) ;
2022-01-24 15:36:30 +09:00
const missingBlockHeights : number [ ] = await blocksRepository . $getMissingBlocksBetweenHeights (
currentBlockHeight , endBlock ) ;
if ( missingBlockHeights . length <= 0 ) {
2022-01-24 17:43:11 +09:00
logger . debug ( ` No missing blocks between # ${ currentBlockHeight } to # ${ endBlock } ` ) ;
2022-01-24 15:36:30 +09:00
currentBlockHeight -= chunkSize ;
continue ;
}
2022-01-18 17:37:04 +09:00
2022-01-24 17:43:11 +09:00
logger . debug ( ` Indexing ${ missingBlockHeights . length } blocks from # ${ currentBlockHeight } to # ${ endBlock } ` ) ;
2022-01-24 15:36:30 +09:00
for ( const blockHeight of missingBlockHeights ) {
2022-01-24 17:43:11 +09:00
if ( blockHeight < lastBlockToIndex ) {
break ;
}
2022-03-05 15:50:48 +01:00
++ indexedThisRun ;
2022-03-10 14:23:29 +01:00
++ totaIndexed ;
2022-03-10 14:21:11 +01:00
const elapsedSeconds = Math . max ( 1 , Math . round ( ( new Date ( ) . getTime ( ) / 1000 ) - timer ) ) ;
if ( elapsedSeconds > 5 || blockHeight === lastBlockToIndex ) {
const runningFor = Math . max ( 1 , Math . round ( ( new Date ( ) . getTime ( ) / 1000 ) - startedAt ) ) ;
2022-03-05 15:50:48 +01:00
const blockPerSeconds = Math . max ( 1 , Math . round ( indexedThisRun / elapsedSeconds ) ) ;
const progress = Math . round ( totaIndexed / indexingBlockAmount * 100 ) ;
const timeLeft = Math . round ( ( indexingBlockAmount - totaIndexed ) / blockPerSeconds ) ;
2022-03-10 14:21:11 +01:00
logger . debug ( ` Indexing block # ${ blockHeight } | ~ ${ blockPerSeconds } blocks/sec | total: ${ totaIndexed } / ${ indexingBlockAmount } ( ${ progress } %) | elapsed: ${ runningFor } seconds | left: ~ ${ timeLeft } seconds ` ) ;
timer = new Date ( ) . getTime ( ) / 1000 ;
indexedThisRun = 0 ;
2022-03-10 14:23:29 +01:00
}
2022-03-05 15:50:48 +01:00
const blockHash = await bitcoinApi . $getBlockHash ( blockHeight ) ;
2022-03-13 11:38:45 +01:00
const block = BitcoinApi . convertBlock ( await bitcoinClient . getBlock ( blockHash ) ) ;
2022-03-05 15:50:48 +01:00
const transactions = await this . $getTransactionsExtended ( blockHash , block . height , true , true ) ;
const blockExtended = await this . $getBlockExtended ( block , transactions ) ;
await blocksRepository . $saveBlockInDatabase ( blockExtended ) ;
2022-01-18 17:37:04 +09:00
}
2022-01-24 15:36:30 +09:00
currentBlockHeight -= chunkSize ;
}
2022-01-24 17:43:11 +09:00
logger . info ( 'Block indexing completed' ) ;
2022-01-24 15:36:30 +09:00
} catch ( e ) {
2022-03-05 15:50:48 +01:00
logger . err ( 'An error occured in $generateBlockDatabase(). Trying again later. ' + e ) ;
this . blockIndexingStarted = false ;
return ;
2022-01-05 15:41:14 +09:00
}
2022-02-21 17:34:07 +09:00
this . blockIndexingCompleted = true ;
2022-01-05 15:41:14 +09:00
}
2020-10-18 21:47:47 +07:00
public async $updateBlocks() {
2020-12-21 23:08:34 +07:00
const blockHeightTip = await bitcoinApi . $getBlockHeightTip ( ) ;
2019-07-21 17:59:47 +03:00
2020-10-18 21:47:47 +07:00
if ( this . blocks . length === 0 ) {
2022-01-19 16:58:56 +01:00
this . currentBlockHeight = Math . max ( blockHeightTip - config . MEMPOOL . INITIAL_BLOCKS_AMOUNT , - 1 ) ;
2020-10-18 21:47:47 +07:00
} else {
this . currentBlockHeight = this . blocks [ this . blocks . length - 1 ] . height ;
}
2021-07-31 17:56:10 +03:00
if ( blockHeightTip - this . currentBlockHeight > config . MEMPOOL . INITIAL_BLOCKS_AMOUNT * 2 ) {
logger . info ( ` ${ blockHeightTip - this . currentBlockHeight } blocks since tip. Fast forwarding to the ${ config . MEMPOOL . INITIAL_BLOCKS_AMOUNT } recent blocks ` ) ;
this . currentBlockHeight = blockHeightTip - config . MEMPOOL . INITIAL_BLOCKS_AMOUNT ;
2020-10-18 21:47:47 +07:00
}
if ( ! this . lastDifficultyAdjustmentTime ) {
2021-09-15 01:47:24 +04:00
const blockchainInfo = await bitcoinClient . getBlockchainInfo ( ) ;
2021-08-01 15:49:26 +03:00
if ( blockchainInfo . blocks === blockchainInfo . headers ) {
const heightDiff = blockHeightTip % 2016 ;
const blockHash = await bitcoinApi . $getBlockHash ( blockHeightTip - heightDiff ) ;
2022-03-13 11:38:45 +01:00
const block = BitcoinApi . convertBlock ( await bitcoinClient . getBlock ( blockHash ) ) ;
2021-08-01 15:49:26 +03:00
this . lastDifficultyAdjustmentTime = block . timestamp ;
this . currentDifficulty = block . difficulty ;
2022-03-09 11:51:36 +01:00
if ( blockHeightTip >= 2016 ) {
2022-01-19 16:58:56 +01:00
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. ` ) ;
}
2021-08-01 15:49:26 +03:00
} else {
logger . debug ( ` Blockchain headers ( ${ blockchainInfo . headers } ) and blocks ( ${ blockchainInfo . blocks } ) not in sync. Waiting... ` ) ;
}
2020-10-18 21:47:47 +07:00
}
while ( this . currentBlockHeight < blockHeightTip ) {
2022-01-19 16:58:56 +01:00
if ( this . currentBlockHeight < blockHeightTip - config . MEMPOOL . INITIAL_BLOCKS_AMOUNT ) {
2020-10-18 21:47:47 +07:00
this . currentBlockHeight = blockHeightTip ;
2019-07-21 17:59:47 +03:00
} else {
2020-10-18 21:47:47 +07:00
this . currentBlockHeight ++ ;
logger . debug ( ` New block found (# ${ this . currentBlockHeight } )! ` ) ;
2019-07-21 17:59:47 +03:00
}
2020-12-21 23:08:34 +07:00
const blockHash = await bitcoinApi . $getBlockHash ( this . currentBlockHeight ) ;
2022-03-13 11:38:45 +01:00
const block = BitcoinApi . convertBlock ( await bitcoinClient . getBlock ( blockHash ) ) ;
2020-12-21 23:08:34 +07:00
const txIds : string [ ] = await bitcoinApi . $getTxIdsForBlock ( blockHash ) ;
2022-01-05 15:41:14 +09:00
const transactions = await this . $getTransactionsExtended ( blockHash , block . height , false ) ;
2022-02-08 15:47:43 +09:00
const blockExtended : BlockExtended = await this . $getBlockExtended ( block , transactions ) ;
2022-02-15 16:02:30 +09:00
if ( Common . indexingEnabled ( ) ) {
2022-02-08 15:47:43 +09:00
await blocksRepository . $saveBlockInDatabase ( blockExtended ) ;
2022-01-21 00:08:51 +09:00
}
2020-09-21 19:41:12 +07:00
2020-10-18 21:47:47 +07:00
if ( block . height % 2016 === 0 ) {
2021-07-23 14:35:04 +03:00
this . previousDifficultyRetarget = ( block . difficulty - this . currentDifficulty ) / this . currentDifficulty * 100 ;
2020-10-18 21:47:47 +07:00
this . lastDifficultyAdjustmentTime = block . timestamp ;
2021-07-23 14:35:04 +03:00
this . currentDifficulty = block . difficulty ;
2020-10-18 21:47:47 +07:00
}
2019-07-21 17:59:47 +03:00
2020-12-28 04:47:22 +07:00
this . blocks . push ( blockExtended ) ;
2021-07-31 17:56:10 +03:00
if ( this . blocks . length > config . MEMPOOL . INITIAL_BLOCKS_AMOUNT * 4 ) {
this . blocks = this . blocks . slice ( - config . MEMPOOL . INITIAL_BLOCKS_AMOUNT * 4 ) ;
2019-07-21 17:59:47 +03:00
}
2020-10-18 21:47:47 +07:00
if ( this . newBlockCallbacks . length ) {
2020-12-28 04:47:22 +07:00
this . newBlockCallbacks . forEach ( ( cb ) = > cb ( blockExtended , txIds , transactions ) ) ;
2020-10-18 21:47:47 +07:00
}
2022-02-11 21:25:58 +09:00
if ( ! memPool . hasPriority ( ) ) {
2021-01-22 23:20:39 +07:00
diskCache . $saveCacheToDisk ( ) ;
}
2019-08-29 01:17:31 +02:00
}
}
2020-05-24 22:45:45 +07:00
2022-02-08 15:47:43 +09:00
/ * *
* Index a block if it ' s missing from the database . Returns the block after indexing
* /
2022-03-13 11:38:45 +01:00
public async $indexBlock ( height : number ) : Promise < BlockExtended > {
2022-02-08 15:47:43 +09:00
const dbBlock = await blocksRepository . $getBlockByHeight ( height ) ;
if ( dbBlock != null ) {
return this . prepareBlock ( dbBlock ) ;
}
const blockHash = await bitcoinApi . $getBlockHash ( height ) ;
2022-03-13 11:38:45 +01:00
const block = BitcoinApi . convertBlock ( await bitcoinClient . getBlock ( blockHash ) ) ;
2022-02-08 15:47:43 +09:00
const transactions = await this . $getTransactionsExtended ( blockHash , block . height , true ) ;
const blockExtended = await this . $getBlockExtended ( block , transactions ) ;
await blocksRepository . $saveBlockInDatabase ( blockExtended ) ;
2022-03-11 14:54:34 +01:00
return this . prepareBlock ( blockExtended ) ;
2022-02-08 15:47:43 +09:00
}
2022-03-10 18:35:37 +01:00
public async $getBlocksExtras ( fromHeight : number , limit : number = 15 ) : Promise < BlockExtended [ ] > {
2022-03-11 14:54:34 +01:00
// Note - This API is breaking if indexing is not available. For now it is okay because we only
// use it for the mining pages, and mining pages should not be available if indexing is turned off.
// I'll need to fix it before we refactor the block(s) related pages
2022-02-08 15:47:43 +09:00
try {
loadingIndicators . setProgress ( 'blocks' , 0 ) ;
let currentHeight = fromHeight ? fromHeight : this.getCurrentBlockHeight ( ) ;
const returnBlocks : BlockExtended [ ] = [ ] ;
if ( currentHeight < 0 ) {
return returnBlocks ;
}
// Check if block height exist in local cache to skip the hash lookup
const blockByHeight = this . getBlocks ( ) . find ( ( b ) = > b . height === currentHeight ) ;
let startFromHash : string | null = null ;
if ( blockByHeight ) {
startFromHash = blockByHeight . id ;
} else {
startFromHash = await bitcoinApi . $getBlockHash ( currentHeight ) ;
}
let nextHash = startFromHash ;
2022-03-10 18:35:37 +01:00
for ( let i = 0 ; i < limit && currentHeight >= 0 ; i ++ ) {
2022-02-08 15:47:43 +09:00
let block = this . getBlocks ( ) . find ( ( b ) = > b . height === currentHeight ) ;
2022-02-15 16:02:30 +09:00
if ( ! block && Common . indexingEnabled ( ) ) {
2022-03-11 14:54:34 +01:00
block = await this . $indexBlock ( currentHeight ) ;
2022-02-08 15:47:43 +09:00
} else if ( ! block ) {
block = this . prepareBlock ( await bitcoinApi . $getBlock ( nextHash ) ) ;
}
returnBlocks . push ( block ) ;
nextHash = block . previousblockhash ;
loadingIndicators . setProgress ( 'blocks' , i / 10 * 100 ) ;
currentHeight -- ;
}
return returnBlocks ;
} catch ( e ) {
loadingIndicators . setProgress ( 'blocks' , 100 ) ;
throw e ;
}
}
private prepareBlock ( block : any ) : BlockExtended {
return < BlockExtended > {
id : block.id ? ? block . hash , // hash for indexed block
2022-03-11 14:54:34 +01:00
timestamp : block.timestamp ? ? block . blockTimestamp , // blockTimestamp for indexed block
height : block.height ,
version : block.version ,
bits : block.bits ,
nonce : block.nonce ,
difficulty : block.difficulty ,
merkle_root : block.merkle_root ,
tx_count : block.tx_count ,
size : block.size ,
weight : block.weight ,
previousblockhash : block.previousblockhash ,
2022-02-08 15:47:43 +09:00
extras : {
2022-03-15 23:33:51 +01:00
coinbaseRaw : block.coinbase_raw ? ? block . extras . coinbaseRaw ,
2022-03-11 14:54:34 +01:00
medianFee : block.medianFee ? ? block . median_fee ? ? block . extras ? . medianFee ,
feeRange : block.feeRange ? ? block . fee_range ? ? block ? . extras ? . feeSpan ,
reward : block.reward ? ? block ? . extras ? . reward ,
totalFees : block.totalFees ? ? block ? . fees ? ? block ? . extras . totalFees ,
2022-02-08 15:47:43 +09:00
pool : block?.extras?.pool ? ? ( block ? . pool_id ? {
2022-03-11 14:54:34 +01:00
id : block.pool_id ,
name : block.pool_name ,
2022-02-08 15:47:43 +09:00
} : undefined ) ,
}
} ;
}
2020-09-21 19:41:12 +07:00
public getLastDifficultyAdjustmentTime ( ) : number {
return this . lastDifficultyAdjustmentTime ;
}
2021-07-23 14:35:04 +03:00
public getPreviousDifficultyRetarget ( ) : number {
return this . previousDifficultyRetarget ;
}
2020-12-21 23:08:34 +07:00
public getCurrentBlockHeight ( ) : number {
return this . currentBlockHeight ;
}
2019-07-21 17:59:47 +03:00
}
export default new Blocks ( ) ;