Fetch block txs from mempool/electrs in bulk
This commit is contained in:
		
							parent
							
								
									81d1c0a4d5
								
							
						
					
					
						commit
						0ebfd6f017
					
				@ -8,6 +8,7 @@ export interface AbstractBitcoinApi {
 | 
				
			|||||||
  $getBlockHeightTip(): Promise<number>;
 | 
					  $getBlockHeightTip(): Promise<number>;
 | 
				
			||||||
  $getBlockHashTip(): Promise<string>;
 | 
					  $getBlockHashTip(): Promise<string>;
 | 
				
			||||||
  $getTxIdsForBlock(hash: string): Promise<string[]>;
 | 
					  $getTxIdsForBlock(hash: string): Promise<string[]>;
 | 
				
			||||||
 | 
					  $getTxsForBlock(hash: string): Promise<IEsploraApi.Transaction[]>;
 | 
				
			||||||
  $getBlockHash(height: number): Promise<string>;
 | 
					  $getBlockHash(height: number): Promise<string>;
 | 
				
			||||||
  $getBlockHeader(hash: string): Promise<string>;
 | 
					  $getBlockHeader(hash: string): Promise<string>;
 | 
				
			||||||
  $getBlock(hash: string): Promise<IEsploraApi.Block>;
 | 
					  $getBlock(hash: string): Promise<IEsploraApi.Block>;
 | 
				
			||||||
 | 
				
			|||||||
@ -81,6 +81,10 @@ class BitcoinApi implements AbstractBitcoinApi {
 | 
				
			|||||||
      .then((rpcBlock: IBitcoinApi.Block) => rpcBlock.tx);
 | 
					      .then((rpcBlock: IBitcoinApi.Block) => rpcBlock.tx);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  $getTxsForBlock(hash: string): Promise<IEsploraApi.Transaction[]> {
 | 
				
			||||||
 | 
					    throw new Error('Method getTxsForBlock not supported by the Bitcoin RPC API.');
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  $getRawBlock(hash: string): Promise<Buffer> {
 | 
					  $getRawBlock(hash: string): Promise<Buffer> {
 | 
				
			||||||
    return this.bitcoindClient.getBlock(hash, 0)
 | 
					    return this.bitcoindClient.getBlock(hash, 0)
 | 
				
			||||||
      .then((raw: string) => Buffer.from(raw, "hex"));
 | 
					      .then((raw: string) => Buffer.from(raw, "hex"));
 | 
				
			||||||
 | 
				
			|||||||
@ -89,6 +89,10 @@ class ElectrsApi implements AbstractBitcoinApi {
 | 
				
			|||||||
    return this.$queryWrapper<string[]>(config.ESPLORA.REST_API_URL + '/block/' + hash + '/txids');
 | 
					    return this.$queryWrapper<string[]>(config.ESPLORA.REST_API_URL + '/block/' + hash + '/txids');
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  $getTxsForBlock(hash: string): Promise<IEsploraApi.Transaction[]> {
 | 
				
			||||||
 | 
					    return this.$queryWrapper<IEsploraApi.Transaction[]>(config.ESPLORA.REST_API_URL + '/block/' + hash + '/txs');
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  $getBlockHash(height: number): Promise<string> {
 | 
					  $getBlockHash(height: number): Promise<string> {
 | 
				
			||||||
    return this.$queryWrapper<string>(config.ESPLORA.REST_API_URL + '/block-height/' + height);
 | 
					    return this.$queryWrapper<string>(config.ESPLORA.REST_API_URL + '/block-height/' + height);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -80,22 +80,30 @@ class Blocks {
 | 
				
			|||||||
    quiet: boolean = false,
 | 
					    quiet: boolean = false,
 | 
				
			||||||
    addMempoolData: boolean = false,
 | 
					    addMempoolData: boolean = false,
 | 
				
			||||||
  ): Promise<TransactionExtended[]> {
 | 
					  ): Promise<TransactionExtended[]> {
 | 
				
			||||||
    const transactions: TransactionExtended[] = [];
 | 
					    let transactions: TransactionExtended[] = [];
 | 
				
			||||||
    if (!txIds) {
 | 
					 | 
				
			||||||
      txIds = await bitcoinApi.$getTxIdsForBlock(blockHash);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const mempool = memPool.getMempool();
 | 
					    const mempool = memPool.getMempool();
 | 
				
			||||||
    let transactionsFound = 0;
 | 
					    let transactionsFound = 0;
 | 
				
			||||||
    let transactionsFetched = 0;
 | 
					    let transactionsFetched = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (config.MEMPOOL.BACKEND === 'esplora') {
 | 
				
			||||||
 | 
					      const rawTransactions = await bitcoinApi.$getTxsForBlock(blockHash);
 | 
				
			||||||
 | 
					      transactions = rawTransactions.map(tx => transactionUtils.extendTransaction(tx));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (!quiet) {
 | 
				
			||||||
 | 
					        logger.debug(`${transactions.length} fetched through backend service.`);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      if (!txIds) {
 | 
				
			||||||
 | 
					        txIds = await bitcoinApi.$getTxIdsForBlock(blockHash);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      for (let i = 0; i < txIds.length; i++) {
 | 
					      for (let i = 0; i < txIds.length; i++) {
 | 
				
			||||||
        if (mempool[txIds[i]]) {
 | 
					        if (mempool[txIds[i]]) {
 | 
				
			||||||
          // We update blocks before the mempool (index.ts), therefore we can
 | 
					          // We update blocks before the mempool (index.ts), therefore we can
 | 
				
			||||||
          // optimize here by directly fetching txs in the "outdated" mempool
 | 
					          // optimize here by directly fetching txs in the "outdated" mempool
 | 
				
			||||||
          transactions.push(mempool[txIds[i]]);
 | 
					          transactions.push(mempool[txIds[i]]);
 | 
				
			||||||
          transactionsFound++;
 | 
					          transactionsFound++;
 | 
				
			||||||
      } else if (config.MEMPOOL.BACKEND === 'esplora' || !memPool.hasPriority() || i === 0) {
 | 
					        } else if (!memPool.hasPriority() || i === 0) {
 | 
				
			||||||
          // Otherwise we fetch the tx data through backend services (esplora, electrum, core rpc...)
 | 
					          // Otherwise we fetch the tx data through backend services (esplora, electrum, core rpc...)
 | 
				
			||||||
          if (!quiet && (i % (Math.round((txIds.length) / 10)) === 0 || i + 1 === txIds.length)) { // Avoid log spam
 | 
					          if (!quiet && (i % (Math.round((txIds.length) / 10)) === 0 || i + 1 === txIds.length)) { // Avoid log spam
 | 
				
			||||||
            logger.debug(`Indexing tx ${i + 1} of ${txIds.length} in block #${blockHeight}`);
 | 
					            logger.debug(`Indexing tx ${i + 1} of ${txIds.length} in block #${blockHeight}`);
 | 
				
			||||||
@ -104,16 +112,6 @@ class Blocks {
 | 
				
			|||||||
            const tx = await transactionUtils.$getTransactionExtended(txIds[i], false, false, false, addMempoolData);
 | 
					            const tx = await transactionUtils.$getTransactionExtended(txIds[i], false, false, false, addMempoolData);
 | 
				
			||||||
            transactions.push(tx);
 | 
					            transactions.push(tx);
 | 
				
			||||||
            transactionsFetched++;
 | 
					            transactionsFetched++;
 | 
				
			||||||
        } catch (e) {
 | 
					 | 
				
			||||||
          try {
 | 
					 | 
				
			||||||
            if (config.MEMPOOL.BACKEND === 'esplora') {
 | 
					 | 
				
			||||||
              // Try again with core
 | 
					 | 
				
			||||||
              const tx = await transactionUtils.$getTransactionExtended(txIds[i], false, false, true, addMempoolData);
 | 
					 | 
				
			||||||
              transactions.push(tx);
 | 
					 | 
				
			||||||
              transactionsFetched++;
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
              throw e;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
          } catch (e) {
 | 
					          } catch (e) {
 | 
				
			||||||
            if (i === 0) {
 | 
					            if (i === 0) {
 | 
				
			||||||
              const msg = `Cannot fetch coinbase tx ${txIds[i]}. Reason: ` + (e instanceof Error ? e.message : e); 
 | 
					              const msg = `Cannot fetch coinbase tx ${txIds[i]}. Reason: ` + (e instanceof Error ? e.message : e); 
 | 
				
			||||||
@ -124,7 +122,6 @@ class Blocks {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (onlyCoinbase === true) {
 | 
					        if (onlyCoinbase === true) {
 | 
				
			||||||
          break; // Fetch the first transaction and exit
 | 
					          break; // Fetch the first transaction and exit
 | 
				
			||||||
@ -134,6 +131,7 @@ class Blocks {
 | 
				
			|||||||
      if (!quiet) {
 | 
					      if (!quiet) {
 | 
				
			||||||
        logger.debug(`${transactionsFound} of ${txIds.length} found in mempool. ${transactionsFetched} fetched through backend service.`);
 | 
					        logger.debug(`${transactionsFound} of ${txIds.length} found in mempool. ${transactionsFetched} fetched through backend service.`);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return transactions;
 | 
					    return transactions;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -53,7 +53,7 @@ class TransactionUtils {
 | 
				
			|||||||
    return (await this.$getTransactionExtended(txId, addPrevouts, lazyPrevouts, forceCore, true)) as MempoolTransactionExtended;
 | 
					    return (await this.$getTransactionExtended(txId, addPrevouts, lazyPrevouts, forceCore, true)) as MempoolTransactionExtended;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private extendTransaction(transaction: IEsploraApi.Transaction): TransactionExtended {
 | 
					  public extendTransaction(transaction: IEsploraApi.Transaction): TransactionExtended {
 | 
				
			||||||
    // @ts-ignore
 | 
					    // @ts-ignore
 | 
				
			||||||
    if (transaction.vsize) {
 | 
					    if (transaction.vsize) {
 | 
				
			||||||
      // @ts-ignore
 | 
					      // @ts-ignore
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user