Updates for general transaction and block fetching.
This commit is contained in:
		
							parent
							
								
									bb28a56622
								
							
						
					
					
						commit
						3c0fa71a10
					
				@ -6,6 +6,7 @@ import { IEsploraApi } from './esplora-api.interface';
 | 
				
			|||||||
import blocks from '../blocks';
 | 
					import blocks from '../blocks';
 | 
				
			||||||
import bitcoinBaseApi from './bitcoin-base.api';
 | 
					import bitcoinBaseApi from './bitcoin-base.api';
 | 
				
			||||||
import mempool from '../mempool';
 | 
					import mempool from '../mempool';
 | 
				
			||||||
 | 
					import { TransactionExtended } from '../../mempool.interfaces';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class BitcoinApi implements AbstractBitcoinApi {
 | 
					class BitcoinApi implements AbstractBitcoinApi {
 | 
				
			||||||
  private rawMempoolCache: IBitcoinApi.RawMempool | null = null;
 | 
					  private rawMempoolCache: IBitcoinApi.RawMempool | null = null;
 | 
				
			||||||
@ -32,6 +33,11 @@ class BitcoinApi implements AbstractBitcoinApi {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  $getRawTransaction(txId: string, skipConversion = false, addPrevout = false): Promise<IEsploraApi.Transaction> {
 | 
					  $getRawTransaction(txId: string, skipConversion = false, addPrevout = false): Promise<IEsploraApi.Transaction> {
 | 
				
			||||||
 | 
					    // If the transaction is in the mempool we also already fetched the fee, just prevouts are missing
 | 
				
			||||||
 | 
					    const txInMempool = mempool.getMempool()[txId];
 | 
				
			||||||
 | 
					    if (txInMempool && addPrevout) {
 | 
				
			||||||
 | 
					      return this.$addPrevouts(txInMempool);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    return this.bitcoindClient.getRawTransaction(txId, true)
 | 
					    return this.bitcoindClient.getRawTransaction(txId, true)
 | 
				
			||||||
      .then((transaction: IBitcoinApi.Transaction) => {
 | 
					      .then((transaction: IBitcoinApi.Transaction) => {
 | 
				
			||||||
        if (skipConversion) {
 | 
					        if (skipConversion) {
 | 
				
			||||||
@ -55,7 +61,12 @@ class BitcoinApi implements AbstractBitcoinApi {
 | 
				
			|||||||
    return this.bitcoindClient.getBlockHash(height);
 | 
					    return this.bitcoindClient.getBlockHash(height);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  $getBlock(hash: string): Promise<IEsploraApi.Block> {
 | 
					  async $getBlock(hash: string): Promise<IEsploraApi.Block> {
 | 
				
			||||||
 | 
					    const foundBlock = blocks.getBlocks().find((block) => block.id === hash);
 | 
				
			||||||
 | 
					    if (foundBlock) {
 | 
				
			||||||
 | 
					      return foundBlock;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return this.bitcoindClient.getBlock(hash)
 | 
					    return this.bitcoindClient.getBlock(hash)
 | 
				
			||||||
      .then((block: IBitcoinApi.Block) => this.convertBlock(block));
 | 
					      .then((block: IBitcoinApi.Block) => this.convertBlock(block));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -163,6 +174,9 @@ class BitcoinApi implements AbstractBitcoinApi {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private async $appendMempoolFeeData(transaction: IEsploraApi.Transaction): Promise<IEsploraApi.Transaction> {
 | 
					  private async $appendMempoolFeeData(transaction: IEsploraApi.Transaction): Promise<IEsploraApi.Transaction> {
 | 
				
			||||||
 | 
					    if (transaction.fee) {
 | 
				
			||||||
 | 
					      return transaction;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    let mempoolEntry: IBitcoinApi.MempoolEntry;
 | 
					    let mempoolEntry: IBitcoinApi.MempoolEntry;
 | 
				
			||||||
    if (!mempool.isInSync() && !this.rawMempoolCache) {
 | 
					    if (!mempool.isInSync() && !this.rawMempoolCache) {
 | 
				
			||||||
      this.rawMempoolCache = await bitcoinBaseApi.$getRawMempoolVerbose();
 | 
					      this.rawMempoolCache = await bitcoinBaseApi.$getRawMempoolVerbose();
 | 
				
			||||||
@ -176,6 +190,17 @@ class BitcoinApi implements AbstractBitcoinApi {
 | 
				
			|||||||
    return transaction;
 | 
					    return transaction;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  protected async $addPrevouts(transaction: TransactionExtended): Promise<TransactionExtended> {
 | 
				
			||||||
 | 
					    for (const vin of transaction.vin) {
 | 
				
			||||||
 | 
					      if (vin.prevout) {
 | 
				
			||||||
 | 
					        continue;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      const innerTx = await this.$getRawTransaction(vin.txid, false);
 | 
				
			||||||
 | 
					      vin.prevout = innerTx.vout[vin.vout];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return transaction;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private async $calculateFeeFromInputs(transaction: IEsploraApi.Transaction, addPrevout: boolean): Promise<IEsploraApi.Transaction> {
 | 
					  private async $calculateFeeFromInputs(transaction: IEsploraApi.Transaction, addPrevout: boolean): Promise<IEsploraApi.Transaction> {
 | 
				
			||||||
    if (transaction.vin[0].is_coinbase) {
 | 
					    if (transaction.vin[0].is_coinbase) {
 | 
				
			||||||
      transaction.fee = 0;
 | 
					      transaction.fee = 0;
 | 
				
			||||||
 | 
				
			|||||||
@ -8,6 +8,7 @@ import * as sha256 from 'crypto-js/sha256';
 | 
				
			|||||||
import * as hexEnc from 'crypto-js/enc-hex';
 | 
					import * as hexEnc from 'crypto-js/enc-hex';
 | 
				
			||||||
import BitcoinApi from './bitcoin-api';
 | 
					import BitcoinApi from './bitcoin-api';
 | 
				
			||||||
import bitcoinBaseApi from './bitcoin-base.api';
 | 
					import bitcoinBaseApi from './bitcoin-base.api';
 | 
				
			||||||
 | 
					import mempool from '../mempool';
 | 
				
			||||||
class BitcoindElectrsApi extends BitcoinApi implements AbstractBitcoinApi {
 | 
					class BitcoindElectrsApi extends BitcoinApi implements AbstractBitcoinApi {
 | 
				
			||||||
  private electrumClient: any;
 | 
					  private electrumClient: any;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -27,6 +28,10 @@ class BitcoindElectrsApi extends BitcoinApi implements AbstractBitcoinApi {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async $getRawTransaction(txId: string, skipConversion = false, addPrevout = false): Promise<IEsploraApi.Transaction> {
 | 
					  async $getRawTransaction(txId: string, skipConversion = false, addPrevout = false): Promise<IEsploraApi.Transaction> {
 | 
				
			||||||
 | 
					    const txInMempool = mempool.getMempool()[txId];
 | 
				
			||||||
 | 
					    if (txInMempool && addPrevout) {
 | 
				
			||||||
 | 
					      return this.$addPrevouts(txInMempool);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    const transaction: IBitcoinApi.Transaction = await this.electrumClient.blockchain_transaction_get(txId, true);
 | 
					    const transaction: IBitcoinApi.Transaction = await this.electrumClient.blockchain_transaction_get(txId, true);
 | 
				
			||||||
    if (!transaction) {
 | 
					    if (!transaction) {
 | 
				
			||||||
      throw new Error('Unable to get transaction: ' + txId);
 | 
					      throw new Error('Unable to get transaction: ' + txId);
 | 
				
			||||||
@ -93,7 +98,7 @@ class BitcoindElectrsApi extends BitcoinApi implements AbstractBitcoinApi {
 | 
				
			|||||||
    const history = await this.$getScriptHashHistory(addressInfo.scriptPubKey);
 | 
					    const history = await this.$getScriptHashHistory(addressInfo.scriptPubKey);
 | 
				
			||||||
    const transactions: IEsploraApi.Transaction[] = [];
 | 
					    const transactions: IEsploraApi.Transaction[] = [];
 | 
				
			||||||
    for (const h of history) {
 | 
					    for (const h of history) {
 | 
				
			||||||
      const tx = await this.$getRawTransaction(h.tx_hash);
 | 
					      const tx = await this.$getRawTransaction(h.tx_hash, false, true);
 | 
				
			||||||
      if (tx) {
 | 
					      if (tx) {
 | 
				
			||||||
        transactions.push(tx);
 | 
					        transactions.push(tx);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
				
			|||||||
@ -64,19 +64,28 @@ class Blocks {
 | 
				
			|||||||
      const txIds: string[] = await bitcoinApi.$getTxIdsForBlock(blockHash);
 | 
					      const txIds: string[] = await bitcoinApi.$getTxIdsForBlock(blockHash);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const mempool = memPool.getMempool();
 | 
					      const mempool = memPool.getMempool();
 | 
				
			||||||
      let found = 0;
 | 
					      let transactionsFound = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      for (let i = 0; i < txIds.length; i++) {
 | 
					      for (let i = 0; i < txIds.length; i++) {
 | 
				
			||||||
        // When using bitcoind, just fetch the coinbase tx for now
 | 
					        // When using bitcoind, just fetch the coinbase tx for now
 | 
				
			||||||
        if (config.MEMPOOL.BACKEND !== 'none' && i === 0) {
 | 
					        if (config.MEMPOOL.BACKEND !== 'none' && i === 0) {
 | 
				
			||||||
          const tx = await transactionUtils.$getTransactionExtended(txIds[i]);
 | 
					          let txFound = false;
 | 
				
			||||||
          if (tx) {
 | 
					          let findCoinbaseTxTries = 0;
 | 
				
			||||||
            transactions.push(tx);
 | 
					          // It takes Electrum Server a few seconds to index the transaction after a block is found
 | 
				
			||||||
 | 
					          while (findCoinbaseTxTries < 5 && !txFound) {
 | 
				
			||||||
 | 
					            const tx = await transactionUtils.$getTransactionExtended(txIds[i]);
 | 
				
			||||||
 | 
					            if (tx) {
 | 
				
			||||||
 | 
					              txFound = true;
 | 
				
			||||||
 | 
					              transactions.push(tx);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					              await Common.sleep(1000);
 | 
				
			||||||
 | 
					              findCoinbaseTxTries++;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (mempool[txIds[i]]) {
 | 
					        if (mempool[txIds[i]]) {
 | 
				
			||||||
          transactions.push(mempool[txIds[i]]);
 | 
					          transactions.push(mempool[txIds[i]]);
 | 
				
			||||||
          found++;
 | 
					          transactionsFound++;
 | 
				
			||||||
        } else if (config.MEMPOOL.BACKEND === 'esplora') {
 | 
					        } else if (config.MEMPOOL.BACKEND === 'esplora') {
 | 
				
			||||||
          logger.debug(`Fetching block tx ${i} of ${txIds.length}`);
 | 
					          logger.debug(`Fetching block tx ${i} of ${txIds.length}`);
 | 
				
			||||||
          const tx = await transactionUtils.$getTransactionExtended(txIds[i]);
 | 
					          const tx = await transactionUtils.$getTransactionExtended(txIds[i]);
 | 
				
			||||||
@ -86,11 +95,11 @@ class Blocks {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      logger.debug(`${found} of ${txIds.length} found in mempool. ${txIds.length - found} not found.`);
 | 
					      logger.debug(`${transactionsFound} of ${txIds.length} found in mempool. ${txIds.length - transactionsFound} not found.`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      const blockExtended: BlockExtended = Object.assign({}, block);
 | 
					      const blockExtended: BlockExtended = Object.assign({}, block);
 | 
				
			||||||
      blockExtended.reward = transactions[0].vout.reduce((acc, curr) => acc + curr.value, 0);
 | 
					      blockExtended.reward = transactions[0].vout.reduce((acc, curr) => acc + curr.value, 0);
 | 
				
			||||||
      blockExtended.coinbaseTx = this.stripCoinbaseTransaction(transactions[0]);
 | 
					      blockExtended.coinbaseTx = transactionUtils.stripCoinbaseTransaction(transactions[0]);
 | 
				
			||||||
      transactions.sort((a, b) => b.feePerVsize - a.feePerVsize);
 | 
					      transactions.sort((a, b) => b.feePerVsize - a.feePerVsize);
 | 
				
			||||||
      blockExtended.medianFee = transactions.length > 1 ? Common.median(transactions.map((tx) => tx.feePerVsize)) : 0;
 | 
					      blockExtended.medianFee = transactions.length > 1 ? Common.median(transactions.map((tx) => tx.feePerVsize)) : 0;
 | 
				
			||||||
      blockExtended.feeRange = transactions.length > 1 ? Common.getFeesInRange(transactions.slice(0, transactions.length - 1), 8) : [0, 0];
 | 
					      blockExtended.feeRange = transactions.length > 1 ? Common.getFeesInRange(transactions.slice(0, transactions.length - 1), 8) : [0, 0];
 | 
				
			||||||
@ -118,20 +127,6 @@ class Blocks {
 | 
				
			|||||||
  public getCurrentBlockHeight(): number {
 | 
					  public getCurrentBlockHeight(): number {
 | 
				
			||||||
    return this.currentBlockHeight;
 | 
					    return this.currentBlockHeight;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					 | 
				
			||||||
  private stripCoinbaseTransaction(tx: TransactionExtended): TransactionMinerInfo {
 | 
					 | 
				
			||||||
    return {
 | 
					 | 
				
			||||||
      vin: [{
 | 
					 | 
				
			||||||
        scriptsig: tx.vin[0].scriptsig || tx.vin[0]['coinbase']
 | 
					 | 
				
			||||||
      }],
 | 
					 | 
				
			||||||
      vout: tx.vout
 | 
					 | 
				
			||||||
        .map((vout) => ({
 | 
					 | 
				
			||||||
          scriptpubkey_address: vout.scriptpubkey_address,
 | 
					 | 
				
			||||||
          value: vout.value
 | 
					 | 
				
			||||||
        }))
 | 
					 | 
				
			||||||
        .filter((vout) => vout.value)
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default new Blocks();
 | 
					export default new Blocks();
 | 
				
			||||||
 | 
				
			|||||||
@ -56,4 +56,12 @@ export class Common {
 | 
				
			|||||||
      value: tx.vout.reduce((acc, vout) => acc + (vout.value ? vout.value : 0), 0),
 | 
					      value: tx.vout.reduce((acc, vout) => acc + (vout.value ? vout.value : 0), 0),
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static sleep(ms: number): Promise<void> {
 | 
				
			||||||
 | 
					    return new Promise((resolve) => {
 | 
				
			||||||
 | 
					       setTimeout(() => {
 | 
				
			||||||
 | 
					         resolve();
 | 
				
			||||||
 | 
					       }, ms);
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -6,27 +6,6 @@ import { IEsploraApi } from './bitcoin/esplora-api.interface';
 | 
				
			|||||||
class TransactionUtils {
 | 
					class TransactionUtils {
 | 
				
			||||||
  constructor() { }
 | 
					  constructor() { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public async $addPrevoutsToTransaction(transaction: TransactionExtended): Promise<TransactionExtended> {
 | 
					 | 
				
			||||||
    if (transaction.vin[0].is_coinbase) {
 | 
					 | 
				
			||||||
      return transaction;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    for (const vin of transaction.vin) {
 | 
					 | 
				
			||||||
      const innerTx = await bitcoinApi.$getRawTransaction(vin.txid);
 | 
					 | 
				
			||||||
      vin.prevout = innerTx.vout[vin.vout];
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return transaction;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public extendTransaction(transaction: IEsploraApi.Transaction): TransactionExtended {
 | 
					 | 
				
			||||||
    transaction['vsize'] = Math.round(transaction.weight / 4);
 | 
					 | 
				
			||||||
    transaction['feePerVsize'] = Math.max(1, (transaction.fee || 0) / (transaction.weight / 4));
 | 
					 | 
				
			||||||
    if (!transaction.status.confirmed) {
 | 
					 | 
				
			||||||
      transaction['firstSeen'] = Math.round((new Date().getTime() / 1000));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    // @ts-ignore
 | 
					 | 
				
			||||||
    return transaction;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  public stripCoinbaseTransaction(tx: TransactionExtended): TransactionMinerInfo {
 | 
					  public stripCoinbaseTransaction(tx: TransactionExtended): TransactionMinerInfo {
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
      vin: [{
 | 
					      vin: [{
 | 
				
			||||||
@ -41,10 +20,10 @@ class TransactionUtils {
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public async $getTransactionExtended(txId: string, inMempool = false, addPrevouts = false): Promise<TransactionExtended | null> {
 | 
					  public async $getTransactionExtended(txId: string, forceBitcoind = false, addPrevouts = false): Promise<TransactionExtended | null> {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      let transaction: IEsploraApi.Transaction;
 | 
					      let transaction: IEsploraApi.Transaction;
 | 
				
			||||||
      if (inMempool) {
 | 
					      if (forceBitcoind) {
 | 
				
			||||||
        transaction = await bitcoinApi.$getRawTransactionBitcoind(txId, false, addPrevouts);
 | 
					        transaction = await bitcoinApi.$getRawTransactionBitcoind(txId, false, addPrevouts);
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        transaction = await bitcoinApi.$getRawTransaction(txId, false, addPrevouts);
 | 
					        transaction = await bitcoinApi.$getRawTransaction(txId, false, addPrevouts);
 | 
				
			||||||
@ -52,11 +31,20 @@ class TransactionUtils {
 | 
				
			|||||||
      return this.extendTransaction(transaction);
 | 
					      return this.extendTransaction(transaction);
 | 
				
			||||||
    } catch (e) {
 | 
					    } catch (e) {
 | 
				
			||||||
      logger.debug('getTransactionExtended error: ' + (e.message || e));
 | 
					      logger.debug('getTransactionExtended error: ' + (e.message || e));
 | 
				
			||||||
      console.log(e);
 | 
					 | 
				
			||||||
      return null;
 | 
					      return null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private extendTransaction(transaction: IEsploraApi.Transaction): TransactionExtended {
 | 
				
			||||||
 | 
					    const transactionExtended: TransactionExtended = Object.assign({
 | 
				
			||||||
 | 
					      vsize: Math.round(transaction.weight / 4),
 | 
				
			||||||
 | 
					      feePerVsize: Math.max(1, (transaction.fee || 0) / (transaction.weight / 4)),
 | 
				
			||||||
 | 
					    }, transaction);
 | 
				
			||||||
 | 
					    if (!transaction.status.confirmed) {
 | 
				
			||||||
 | 
					      transactionExtended.firstSeen = Math.round((new Date().getTime() / 1000));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return transactionExtended;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default new TransactionUtils();
 | 
					export default new TransactionUtils();
 | 
				
			||||||
 | 
				
			|||||||
@ -528,13 +528,7 @@ class Routes {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  public async getTransaction(req: Request, res: Response) {
 | 
					  public async getTransaction(req: Request, res: Response) {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      let transaction: TransactionExtended | null;
 | 
					      const transaction = await transactionUtils.$getTransactionExtended(req.params.txId, false, true);
 | 
				
			||||||
      const txInMempool = mempool.getMempool()[req.params.txId];
 | 
					 | 
				
			||||||
      if (txInMempool) {
 | 
					 | 
				
			||||||
        transaction = txInMempool;
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        transaction = await transactionUtils.$getTransactionExtended(req.params.txId, false, true);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (transaction) {
 | 
					      if (transaction) {
 | 
				
			||||||
        res.json(transaction);
 | 
					        res.json(transaction);
 | 
				
			||||||
@ -563,8 +557,9 @@ class Routes {
 | 
				
			|||||||
    try {
 | 
					    try {
 | 
				
			||||||
      const txIds = await bitcoinApi.$getTxIdsForBlock(req.params.hash);
 | 
					      const txIds = await bitcoinApi.$getTxIdsForBlock(req.params.hash);
 | 
				
			||||||
      const transactions: TransactionExtended[] = [];
 | 
					      const transactions: TransactionExtended[] = [];
 | 
				
			||||||
 | 
					      const startingIndex = Math.max(0, parseInt(req.params.index, 10));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      for (let i = 0; i < Math.min(15, txIds.length); i++) {
 | 
					      for (let i = startingIndex; i < Math.min(startingIndex + 10, txIds.length); i++) {
 | 
				
			||||||
        const transaction = await transactionUtils.$getTransactionExtended(txIds[i], false, true);
 | 
					        const transaction = await transactionUtils.$getTransactionExtended(txIds[i], false, true);
 | 
				
			||||||
        if (transaction) {
 | 
					        if (transaction) {
 | 
				
			||||||
          transactions.push(transaction);
 | 
					          transactions.push(transaction);
 | 
				
			||||||
@ -577,7 +572,12 @@ class Routes {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public async getBlockHeight(req: Request, res: Response) {
 | 
					  public async getBlockHeight(req: Request, res: Response) {
 | 
				
			||||||
    res.status(404).send('Not implemented');
 | 
					    try {
 | 
				
			||||||
 | 
					      const blockHash = await bitcoinApi.$getBlockHash(parseInt(req.params.height, 10));
 | 
				
			||||||
 | 
					      res.send(blockHash);
 | 
				
			||||||
 | 
					    } catch (e) {
 | 
				
			||||||
 | 
					      res.status(500).send(e.message);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public async getAddress(req: Request, res: Response) {
 | 
					  public async getAddress(req: Request, res: Response) {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user