Correctly error handle getTransaction and set 404 status when not found.
This commit is contained in:
		
							parent
							
								
									fb41f58f7c
								
							
						
					
					
						commit
						5b268794af
					
				@ -5,7 +5,6 @@ import { AbstractBitcoinApi } from './bitcoin-api-abstract-factory';
 | 
				
			|||||||
import { IBitcoinApi } from './bitcoin-api.interface';
 | 
					import { IBitcoinApi } from './bitcoin-api.interface';
 | 
				
			||||||
import { IEsploraApi } from './esplora-api.interface';
 | 
					import { IEsploraApi } from './esplora-api.interface';
 | 
				
			||||||
import blocks from '../blocks';
 | 
					import blocks from '../blocks';
 | 
				
			||||||
import bitcoinBaseApi from './bitcoin-base.api';
 | 
					 | 
				
			||||||
import mempool from '../mempool';
 | 
					import mempool from '../mempool';
 | 
				
			||||||
import { TransactionExtended } from '../../mempool.interfaces';
 | 
					import { TransactionExtended } from '../../mempool.interfaces';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -202,12 +201,12 @@ class BitcoinApi implements AbstractBitcoinApi {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    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 this.$getRawMempoolVerbose();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (this.rawMempoolCache && this.rawMempoolCache[transaction.txid]) {
 | 
					    if (this.rawMempoolCache && this.rawMempoolCache[transaction.txid]) {
 | 
				
			||||||
      mempoolEntry = this.rawMempoolCache[transaction.txid];
 | 
					      mempoolEntry = this.rawMempoolCache[transaction.txid];
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      mempoolEntry = await bitcoinBaseApi.$getMempoolEntry(transaction.txid);
 | 
					      mempoolEntry = await this.$getMempoolEntry(transaction.txid);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    transaction.fee = mempoolEntry.fees.base * 100000000;
 | 
					    transaction.fee = mempoolEntry.fees.base * 100000000;
 | 
				
			||||||
    return transaction;
 | 
					    return transaction;
 | 
				
			||||||
@ -238,6 +237,14 @@ class BitcoinApi implements AbstractBitcoinApi {
 | 
				
			|||||||
    return this.bitcoindClient.validateAddress(address);
 | 
					    return this.bitcoindClient.validateAddress(address);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private $getMempoolEntry(txid: string): Promise<IBitcoinApi.MempoolEntry> {
 | 
				
			||||||
 | 
					    return this.bitcoindClient.getMempoolEntry(txid);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private $getRawMempoolVerbose(): Promise<IBitcoinApi.RawMempool> {
 | 
				
			||||||
 | 
					    return this.bitcoindClient.getRawMemPool(true);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  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;
 | 
				
			||||||
 | 
				
			|||||||
@ -40,19 +40,6 @@ class BitcoinBaseApi {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    return this.bitcoindClient.getMempoolInfo();
 | 
					    return this.bitcoindClient.getMempoolInfo();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					 | 
				
			||||||
  $getRawTransaction(txId: string): Promise<IBitcoinApi.Transaction> {
 | 
					 | 
				
			||||||
    return this.bitcoindClient.getRawTransaction(txId, true);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  $getMempoolEntry(txid: string): Promise<IBitcoinApi.MempoolEntry> {
 | 
					 | 
				
			||||||
    return this.bitcoindClient.getMempoolEntry(txid);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  $getRawMempoolVerbose(): Promise<IBitcoinApi.RawMempool> {
 | 
					 | 
				
			||||||
    return this.bitcoindClient.getRawMemPool(true);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default new BitcoinBaseApi();
 | 
					export default new BitcoinBaseApi();
 | 
				
			||||||
 | 
				
			|||||||
@ -73,11 +73,12 @@ class Blocks {
 | 
				
			|||||||
          let findCoinbaseTxTries = 0;
 | 
					          let findCoinbaseTxTries = 0;
 | 
				
			||||||
          // It takes Electrum Server a few seconds to index the transaction after a block is found
 | 
					          // It takes Electrum Server a few seconds to index the transaction after a block is found
 | 
				
			||||||
          while (findCoinbaseTxTries < 5 && !txFound) {
 | 
					          while (findCoinbaseTxTries < 5 && !txFound) {
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
              const tx = await transactionUtils.$getTransactionExtended(txIds[i]);
 | 
					              const tx = await transactionUtils.$getTransactionExtended(txIds[i]);
 | 
				
			||||||
            if (tx) {
 | 
					 | 
				
			||||||
              txFound = true;
 | 
					              txFound = true;
 | 
				
			||||||
              transactions.push(tx);
 | 
					              transactions.push(tx);
 | 
				
			||||||
            } else {
 | 
					            } catch (e) {
 | 
				
			||||||
 | 
					              logger.debug('Coinbase transaction fetch error: ' + e.message || e);
 | 
				
			||||||
              await Common.sleep(1000);
 | 
					              await Common.sleep(1000);
 | 
				
			||||||
              findCoinbaseTxTries++;
 | 
					              findCoinbaseTxTries++;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -88,9 +89,11 @@ class Blocks {
 | 
				
			|||||||
          transactionsFound++;
 | 
					          transactionsFound++;
 | 
				
			||||||
        } else if (config.MEMPOOL.BACKEND === 'esplora' || memPool.isInSync()) {
 | 
					        } else if (config.MEMPOOL.BACKEND === 'esplora' || memPool.isInSync()) {
 | 
				
			||||||
          logger.debug(`Fetching block tx ${i} of ${txIds.length}`);
 | 
					          logger.debug(`Fetching block tx ${i} of ${txIds.length}`);
 | 
				
			||||||
 | 
					          try {
 | 
				
			||||||
            const tx = await transactionUtils.$getTransactionExtended(txIds[i]);
 | 
					            const tx = await transactionUtils.$getTransactionExtended(txIds[i]);
 | 
				
			||||||
          if (tx) {
 | 
					 | 
				
			||||||
            transactions.push(tx);
 | 
					            transactions.push(tx);
 | 
				
			||||||
 | 
					          } catch (e) {
 | 
				
			||||||
 | 
					            logger.debug('Error fetching block tx: ' + e.message || e);
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
				
			|||||||
@ -103,8 +103,8 @@ class Mempool {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    for (const txid of transactions) {
 | 
					    for (const txid of transactions) {
 | 
				
			||||||
      if (!this.mempoolCache[txid]) {
 | 
					      if (!this.mempoolCache[txid]) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
          const transaction = await transactionUtils.$getTransactionExtended(txid, true);
 | 
					          const transaction = await transactionUtils.$getTransactionExtended(txid, true);
 | 
				
			||||||
        if (transaction) {
 | 
					 | 
				
			||||||
          this.mempoolCache[txid] = transaction;
 | 
					          this.mempoolCache[txid] = transaction;
 | 
				
			||||||
          txCount++;
 | 
					          txCount++;
 | 
				
			||||||
          if (this.inSync) {
 | 
					          if (this.inSync) {
 | 
				
			||||||
@ -121,8 +121,8 @@ class Mempool {
 | 
				
			|||||||
            logger.debug('Fetched transaction ' + txCount);
 | 
					            logger.debug('Fetched transaction ' + txCount);
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          newTransactions.push(transaction);
 | 
					          newTransactions.push(transaction);
 | 
				
			||||||
        } else {
 | 
					        } catch (e) {
 | 
				
			||||||
          logger.debug('Error finding transaction in mempool.');
 | 
					          logger.debug('Error finding transaction in mempool: ' + e.message || e);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -20,8 +20,7 @@ class TransactionUtils {
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public async $getTransactionExtended(txId: string, forceBitcoind = false, addPrevouts = false): Promise<TransactionExtended | null> {
 | 
					  public async $getTransactionExtended(txId: string, forceBitcoind = false, addPrevouts = false): Promise<TransactionExtended> {
 | 
				
			||||||
    try {
 | 
					 | 
				
			||||||
    let transaction: IEsploraApi.Transaction;
 | 
					    let transaction: IEsploraApi.Transaction;
 | 
				
			||||||
    if (forceBitcoind) {
 | 
					    if (forceBitcoind) {
 | 
				
			||||||
      transaction = await bitcoinApi.$getRawTransactionBitcoind(txId, false, addPrevouts);
 | 
					      transaction = await bitcoinApi.$getRawTransactionBitcoind(txId, false, addPrevouts);
 | 
				
			||||||
@ -29,11 +28,6 @@ class TransactionUtils {
 | 
				
			|||||||
      transaction = await bitcoinApi.$getRawTransaction(txId, false, addPrevouts);
 | 
					      transaction = await bitcoinApi.$getRawTransaction(txId, false, addPrevouts);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return this.extendTransaction(transaction);
 | 
					    return this.extendTransaction(transaction);
 | 
				
			||||||
    } catch (e) {
 | 
					 | 
				
			||||||
      logger.debug('getTransactionExtended error: ' + (e.message || e));
 | 
					 | 
				
			||||||
      logger.debug(JSON.stringify(e));
 | 
					 | 
				
			||||||
      return null;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private extendTransaction(transaction: IEsploraApi.Transaction): TransactionExtended {
 | 
					  private extendTransaction(transaction: IEsploraApi.Transaction): TransactionExtended {
 | 
				
			||||||
 | 
				
			|||||||
@ -219,9 +219,11 @@ class WebsocketHandler {
 | 
				
			|||||||
        const tx = newTransactions.find((t) => t.txid === client['track-mempool-tx']);
 | 
					        const tx = newTransactions.find((t) => t.txid === client['track-mempool-tx']);
 | 
				
			||||||
        if (tx) {
 | 
					        if (tx) {
 | 
				
			||||||
          if (config.MEMPOOL.BACKEND !== 'esplora') {
 | 
					          if (config.MEMPOOL.BACKEND !== 'esplora') {
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
              const fullTx = await transactionUtils.$getTransactionExtended(tx.txid, false, true);
 | 
					              const fullTx = await transactionUtils.$getTransactionExtended(tx.txid, false, true);
 | 
				
			||||||
            if (fullTx) {
 | 
					 | 
				
			||||||
              response['tx'] = fullTx;
 | 
					              response['tx'] = fullTx;
 | 
				
			||||||
 | 
					            } catch (e) {
 | 
				
			||||||
 | 
					              logger.debug('Error finding transaction in mempool: ' + e.message || e);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          } else {
 | 
					          } else {
 | 
				
			||||||
            response['tx'] = tx;
 | 
					            response['tx'] = tx;
 | 
				
			||||||
@ -237,9 +239,11 @@ class WebsocketHandler {
 | 
				
			|||||||
          const someVin = tx.vin.some((vin) => !!vin.prevout && vin.prevout.scriptpubkey_address === client['track-address']);
 | 
					          const someVin = tx.vin.some((vin) => !!vin.prevout && vin.prevout.scriptpubkey_address === client['track-address']);
 | 
				
			||||||
          if (someVin) {
 | 
					          if (someVin) {
 | 
				
			||||||
            if (config.MEMPOOL.BACKEND !== 'esplora') {
 | 
					            if (config.MEMPOOL.BACKEND !== 'esplora') {
 | 
				
			||||||
 | 
					              try {
 | 
				
			||||||
                const fullTx = await transactionUtils.$getTransactionExtended(tx.txid, false, true);
 | 
					                const fullTx = await transactionUtils.$getTransactionExtended(tx.txid, false, true);
 | 
				
			||||||
              if (fullTx) {
 | 
					 | 
				
			||||||
                foundTransactions.push(fullTx);
 | 
					                foundTransactions.push(fullTx);
 | 
				
			||||||
 | 
					              } catch (e) {
 | 
				
			||||||
 | 
					                logger.debug('Error finding transaction in mempool: ' + e.message || e);
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
              foundTransactions.push(tx);
 | 
					              foundTransactions.push(tx);
 | 
				
			||||||
@ -249,9 +253,11 @@ class WebsocketHandler {
 | 
				
			|||||||
          const someVout = tx.vout.some((vout) => vout.scriptpubkey_address === client['track-address']);
 | 
					          const someVout = tx.vout.some((vout) => vout.scriptpubkey_address === client['track-address']);
 | 
				
			||||||
          if (someVout) {
 | 
					          if (someVout) {
 | 
				
			||||||
            if (config.MEMPOOL.BACKEND !== 'esplora') {
 | 
					            if (config.MEMPOOL.BACKEND !== 'esplora') {
 | 
				
			||||||
 | 
					              try {
 | 
				
			||||||
                const fullTx = await transactionUtils.$getTransactionExtended(tx.txid, false, true);
 | 
					                const fullTx = await transactionUtils.$getTransactionExtended(tx.txid, false, true);
 | 
				
			||||||
              if (fullTx) {
 | 
					 | 
				
			||||||
                foundTransactions.push(fullTx);
 | 
					                foundTransactions.push(fullTx);
 | 
				
			||||||
 | 
					              } catch (e) {
 | 
				
			||||||
 | 
					                logger.debug('Error finding transaction in mempool: ' + e.message || e);
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
              foundTransactions.push(tx);
 | 
					              foundTransactions.push(tx);
 | 
				
			||||||
@ -298,9 +304,11 @@ class WebsocketHandler {
 | 
				
			|||||||
          if (client['track-tx'] === rbfTransaction) {
 | 
					          if (client['track-tx'] === rbfTransaction) {
 | 
				
			||||||
            const rbfTx = rbfTransactions[rbfTransaction];
 | 
					            const rbfTx = rbfTransactions[rbfTransaction];
 | 
				
			||||||
            if (config.MEMPOOL.BACKEND !== 'esplora') {
 | 
					            if (config.MEMPOOL.BACKEND !== 'esplora') {
 | 
				
			||||||
 | 
					              try {
 | 
				
			||||||
                const fullTx = await transactionUtils.$getTransactionExtended(rbfTransaction, false, true);
 | 
					                const fullTx = await transactionUtils.$getTransactionExtended(rbfTransaction, false, true);
 | 
				
			||||||
              if (fullTx) {
 | 
					 | 
				
			||||||
                response['rbfTransaction'] = fullTx;
 | 
					                response['rbfTransaction'] = fullTx;
 | 
				
			||||||
 | 
					              } catch (e) {
 | 
				
			||||||
 | 
					                logger.debug('Error finding transaction in mempool: ' + e.message || e);
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
              response['rbfTransaction'] = rbfTx;
 | 
					              response['rbfTransaction'] = rbfTx;
 | 
				
			||||||
 | 
				
			|||||||
@ -532,14 +532,13 @@ class Routes {
 | 
				
			|||||||
  public async getTransaction(req: Request, res: Response) {
 | 
					  public async getTransaction(req: Request, res: Response) {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      const transaction = await transactionUtils.$getTransactionExtended(req.params.txId, false, true);
 | 
					      const transaction = await transactionUtils.$getTransactionExtended(req.params.txId, false, true);
 | 
				
			||||||
 | 
					 | 
				
			||||||
      if (transaction) {
 | 
					 | 
				
			||||||
      res.json(transaction);
 | 
					      res.json(transaction);
 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        res.status(500).send('Error fetching transaction.');
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    } catch (e) {
 | 
					    } catch (e) {
 | 
				
			||||||
      res.status(500).send(e.message || e);
 | 
					      let statusCode = 500;
 | 
				
			||||||
 | 
					      if (e.message && e.message.indexOf('No such mempool or blockchain transaction') > -1) {
 | 
				
			||||||
 | 
					        statusCode = 404;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      res.status(statusCode).send(e.message || e);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -599,10 +598,12 @@ class Routes {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      const endIndex = Math.min(startingIndex + 10, txIds.length);
 | 
					      const endIndex = Math.min(startingIndex + 10, txIds.length);
 | 
				
			||||||
      for (let i = startingIndex; i < endIndex; i++) {
 | 
					      for (let i = startingIndex; i < endIndex; i++) {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
          const transaction = await transactionUtils.$getTransactionExtended(txIds[i], false, true);
 | 
					          const transaction = await transactionUtils.$getTransactionExtended(txIds[i], false, true);
 | 
				
			||||||
        if (transaction) {
 | 
					 | 
				
			||||||
          transactions.push(transaction);
 | 
					          transactions.push(transaction);
 | 
				
			||||||
          loadingIndicators.setProgress('blocktxs-' + req.params.hash, (i + 1) / endIndex * 100);
 | 
					          loadingIndicators.setProgress('blocktxs-' + req.params.hash, (i + 1) / endIndex * 100);
 | 
				
			||||||
 | 
					        } catch (e) {
 | 
				
			||||||
 | 
					          logger.debug('getBlockTransactions error: ' + e.message || e);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      res.json(transactions);
 | 
					      res.json(transactions);
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user