Correctly error handle getTransaction and set 404 status when not found.

This commit is contained in:
softsimon 2021-01-24 02:51:22 +07:00
parent fb41f58f7c
commit 5b268794af
No known key found for this signature in database
GPG Key ID: 488D7DCFB5A430D7
7 changed files with 55 additions and 55 deletions

View File

@ -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;

View File

@ -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();

View File

@ -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);
} }
} }
} }

View File

@ -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);
} }
} }

View File

@ -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 {

View File

@ -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;

View File

@ -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);