diff --git a/.env-sample b/.env-sample index 57210ba95..fa08d6460 100644 --- a/.env-sample +++ b/.env-sample @@ -110,6 +110,9 @@ # Default: 1024 #BTCEXP_OLD_SPACE_MAX_SIZE=2048 +# The number of recent blocks to search for transactions when txindex is disabled +#BTCEXP_NOTXINDEX_SEARCH_DEPTH=3 + # Show tools list in a sub-nav at top of screen # Default: true BTCEXP_UI_SHOW_TOOLS_SUBHEADER=true diff --git a/app/api/rpcApi.js b/app/api/rpcApi.js index e19e92698..7f16e4c42 100644 --- a/app/api/rpcApi.js +++ b/app/api/rpcApi.js @@ -224,7 +224,7 @@ function getAddress(address) { } function getRawTransaction(txid, blockhash) { - debugLog("getRawTransaction: %s", txid); + debugLog("getRawTransaction: %s %s", txid, blockhash); return new Promise(function(resolve, reject) { if (coins[config.coin].genesisCoinbaseTransactionIdsByNetwork[global.activeBlockchain] && txid == coins[config.coin].genesisCoinbaseTransactionIdsByNetwork[global.activeBlockchain]) { @@ -257,12 +257,48 @@ function getRawTransaction(txid, blockhash) { resolve(result); }).catch(function(err) { - reject(err); + if (global.getindexinfo && !global.getindexinfo.txindex && !blockhash) { + noTxIndexTransactionLookup(txid).then(resolve, reject); + } else { + reject(err); + } }); } }); } +async function noTxIndexTransactionLookup(txid) { + // Try looking up in wallet transactions + for (var wallet of await listWallets()) { + try { return await getWalletTransaction(wallet, txid); } + catch (_) {} + } + + // Try looking up in recent blocks + var tip_height = await getRpcDataWithParams({method:"getblockcount", parameters:[]}); + for (var height=tip_height; height>Math.max(tip_height - config.noTxIndexSearchDepth, 0); height--) { + var blockhash = await getRpcDataWithParams({method:"getblockhash", parameters:[height]}); + try { return await getRawTransaction(txid, blockhash); } + catch (_) {} + } + + throw new Error(`The requested tx ${txid} cannot be found in wallet transactions, mempool transactions and recently confirmed transactions`) +} + +function listWallets() { + return getRpcDataWithParams({method:"listwallets", parameters:[]}) +} + +async function getWalletTransaction(wallet, txid) { + global.rpcClient.wallet = wallet; + try { + return await getRpcDataWithParams({method:"gettransaction", parameters:[ txid, true, true ]}) + .then(wtx => ({ ...wtx, ...wtx.decoded, decoded: null })) + } finally { + global.rpcClient.wallet = null; + } +} + function getUtxo(txid, outputIndex) { debugLog("getUtxo: %s (%d)", txid, outputIndex); diff --git a/app/config.js b/app/config.js index cf11a3a26..daef33a03 100644 --- a/app/config.js +++ b/app/config.js @@ -92,6 +92,8 @@ module.exports = { rpcConcurrency: (process.env.BTCEXP_RPC_CONCURRENCY || 10), + noTxIndexSearchDepth: (+process.env.BTCEXP_NOTXINDEX_SEARCH_DEPTH || 3), + rpcBlacklist: process.env.BTCEXP_RPC_ALLOWALL.toLowerCase() == "true" ? [] : process.env.BTCEXP_RPC_BLACKLIST ? process.env.BTCEXP_RPC_BLACKLIST.split(',').filter(Boolean)