diff --git a/src/rest.cpp b/src/rest.cpp --- a/src/rest.cpp +++ b/src/rest.cpp @@ -70,13 +70,32 @@ } /** - * Get the node context mempool. + * Get the node context. * - * Set the HTTP error and return nullptr if node context - * mempool is not found. + * @param[in] req The HTTP request, whose status code will be set if node + * context is not found. + * @returns Pointer to the node context or nullptr if not found. + */ +static NodeContext *GetNodeContext(const util::Ref &context, HTTPRequest *req) { + NodeContext *node = + context.Has() ? &context.Get() : nullptr; + if (!node) { + RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, + strprintf("%s:%d (%s)\n" + "Internal bug detected: Node context not found!\n" + "You may report this issue here: %s\n", + __FILE__, __LINE__, __func__, PACKAGE_BUGREPORT)); + return nullptr; + } + return node; +} + +/** + * Get the node context mempool. * - * @param[in] req the HTTP request - * return pointer to the mempool or nullptr if no mempool found + * @param[in] req The HTTP request, whose status code will be set if node + * context mempool is not found. + * @returns Pointer to the mempool or nullptr if no mempool found. */ static CTxMemPool *GetMemPool(const util::Ref &context, HTTPRequest *req) { NodeContext *node = @@ -421,10 +440,15 @@ g_txindex->BlockUntilSyncedToCurrentChain(); } - CTransactionRef tx; + const NodeContext *const node = GetNodeContext(context, req); + if (!node) { + return false; + } BlockHash hashBlock; - if (!GetTransaction(txid, tx, config.GetChainParams().GetConsensus(), - hashBlock)) { + const CTransactionRef tx = + GetTransaction(/* block_index */ nullptr, node->mempool, txid, + Params().GetConsensus(), hashBlock); + if (!tx) { return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); } diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -192,6 +192,8 @@ } .Check(request); + const NodeContext &node = EnsureNodeContext(request.context); + bool in_active_chain = true; TxId txid = TxId(ParseHashV(request.params[0], "parameter 1")); CBlockIndex *blockindex = nullptr; @@ -229,10 +231,10 @@ f_txindex_ready = g_txindex->BlockUntilSyncedToCurrentChain(); } - CTransactionRef tx; BlockHash hash_block; - if (!GetTransaction(txid, tx, params.GetConsensus(), hash_block, - blockindex)) { + const CTransactionRef tx = GetTransaction( + blockindex, node.mempool, txid, params.GetConsensus(), hash_block); + if (!tx) { std::string errmsg; if (blockindex) { if (!blockindex->nStatus.hasData()) { @@ -352,9 +354,10 @@ LOCK(cs_main); if (pblockindex == nullptr) { - CTransactionRef tx; - if (!GetTransaction(oneTxId, tx, params, hashBlock) || - hashBlock.IsNull()) { + const CTransactionRef tx = GetTransaction( + /* block_index */ nullptr, + /* mempool */ nullptr, oneTxId, Params().GetConsensus(), hashBlock); + if (!tx || hashBlock.IsNull()) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block"); } diff --git a/src/validation.h b/src/validation.h --- a/src/validation.h +++ b/src/validation.h @@ -233,12 +233,25 @@ void ThreadScriptCheck(int worker_num); /** - * Retrieve a transaction (from memory pool, or from disk, if possible). + * Return transaction from the block at block_index. + * If block_index is not provided, fall back to mempool. + * If mempool is not provided or the tx couldn't be found in mempool, fall back + * to g_txindex. + * + * @param[in] block_index The block to read from disk, or nullptr + * @param[in] mempool If block_index is not provided, look in the + * mempool, if provided + * @param[in] txid The txid + * @param[in] consensusParams The params + * @param[out] hashBlock The hash of block_index, if the tx was found via + * block_index + * @returns The tx if found, otherwise nullptr */ -bool GetTransaction(const TxId &txid, CTransactionRef &txOut, - const Consensus::Params ¶ms, BlockHash &hashBlock, - const CBlockIndex *const blockIndex = nullptr); - +CTransactionRef GetTransaction(const CBlockIndex *const block_index, + const CTxMemPool *const mempool, + const TxId &txid, + const Consensus::Params &consensusParams, + BlockHash &hashBlock); /** * Find the best known block, and make it the tip of the block chain * diff --git a/src/validation.cpp b/src/validation.cpp --- a/src/validation.cpp +++ b/src/validation.cpp @@ -793,40 +793,38 @@ bypass_limits, nAbsurdFee, test_accept); } -/** - * Return transaction in txOut, and if it was found inside a block, its hash is - * placed in hashBlock. If blockIndex is provided, the transaction is fetched - * from the corresponding block. - */ -bool GetTransaction(const TxId &txid, CTransactionRef &txOut, - const Consensus::Params ¶ms, BlockHash &hashBlock, - const CBlockIndex *const block_index) { +CTransactionRef GetTransaction(const CBlockIndex *const block_index, + const CTxMemPool *const mempool, + const TxId &txid, + const Consensus::Params &consensusParams, + BlockHash &hashBlock) { LOCK(cs_main); - if (block_index == nullptr) { - CTransactionRef ptx = g_mempool.get(txid); - if (ptx) { - txOut = ptx; - return true; - } - - if (g_txindex) { - return g_txindex->FindTx(txid, hashBlock, txOut); - } - } else { + if (block_index) { CBlock block; - if (ReadBlockFromDisk(block, block_index, params)) { + if (ReadBlockFromDisk(block, block_index, consensusParams)) { for (const auto &tx : block.vtx) { if (tx->GetId() == txid) { - txOut = tx; hashBlock = block_index->GetBlockHash(); - return true; + return tx; } } } + return nullptr; + } + if (mempool) { + CTransactionRef ptx = mempool->get(txid); + if (ptx) { + return ptx; + } } - - return false; + if (g_txindex) { + CTransactionRef tx; + if (g_txindex->FindTx(txid, hashBlock, tx)) { + return tx; + } + } + return nullptr; } //////////////////////////////////////////////////////////////////////////////