Skip to content

Commit a1da180

Browse files
committed
Merge #19589: rpc: Avoid useless mempool query in gettxoutproof
fa5979d rpc: Avoid useless mempool query in gettxoutproof (MarcoFalke) fa1f7f2 rpc: Style fixups in gettxoutproof (MarcoFalke) Pull request description: `GetTransaction` implicitly and unconditionally asks the mempool global for a transaction. This is problematic for several reasons: * `gettxoutproof` is for on-chain txs only and asking the mempool for on-chain txs is confusing and minimally wasteful * Globals are confusing and make code harder to test with unit tests Fix both issues by passing in an optional mempool. This also helps with #19556 ACKs for top commit: hebasto: re-ACK fa5979d jnewbery: utACK fa5979d promag: Code review ACK fa5979d. Tree-SHA512: 048361b82abfcc40481181bd44f70cfc9e97d5d6356549df34bbe30b9de7a0a72d2207a3ad0279b21f06293509b284d8967f58ca7e716263a22b20aa4e7f9c54
2 parents b62fbf9 + fa5979d commit a1da180

File tree

4 files changed

+76
-48
lines changed

4 files changed

+76
-48
lines changed

src/rest.cpp

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,32 @@ static bool RESTERR(HTTPRequest* req, enum HTTPStatusCode status, std::string me
6868
}
6969

7070
/**
71-
* Get the node context mempool.
71+
* Get the node context.
7272
*
73-
* Set the HTTP error and return nullptr if node context
74-
* mempool is not found.
73+
* @param[in] req The HTTP request, whose status code will be set if node
74+
* context is not found.
75+
* @returns Pointer to the node context or nullptr if not found.
76+
*/
77+
static NodeContext* GetNodeContext(const util::Ref& context, HTTPRequest* req)
78+
{
79+
NodeContext* node = context.Has<NodeContext>() ? &context.Get<NodeContext>() : nullptr;
80+
if (!node) {
81+
RESTERR(req, HTTP_INTERNAL_SERVER_ERROR,
82+
strprintf("%s:%d (%s)\n"
83+
"Internal bug detected: Node context not found!\n"
84+
"You may report this issue here: %s\n",
85+
__FILE__, __LINE__, __func__, PACKAGE_BUGREPORT));
86+
return nullptr;
87+
}
88+
return node;
89+
}
90+
91+
/**
92+
* Get the node context mempool.
7593
*
76-
* @param[in] req the HTTP request
77-
* return pointer to the mempool or nullptr if no mempool found
94+
* @param[in] req The HTTP request, whose status code will be set if node
95+
* context mempool is not found.
96+
* @returns Pointer to the mempool or nullptr if no mempool found.
7897
*/
7998
static CTxMemPool* GetMemPool(const util::Ref& context, HTTPRequest* req)
8099
{
@@ -371,10 +390,13 @@ static bool rest_tx(const util::Ref& context, HTTPRequest* req, const std::strin
371390
g_txindex->BlockUntilSyncedToCurrentChain();
372391
}
373392

374-
CTransactionRef tx;
393+
const NodeContext* const node = GetNodeContext(context, req);
394+
if (!node) return false;
375395
uint256 hashBlock = uint256();
376-
if (!GetTransaction(hash, tx, Params().GetConsensus(), hashBlock))
396+
const CTransactionRef tx = GetTransaction(/* block_index */ nullptr, node->mempool, hash, Params().GetConsensus(), hashBlock);
397+
if (!tx) {
377398
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
399+
}
378400

379401
switch (rf) {
380402
case RetFormat::BINARY: {

src/rpc/rawtransaction.cpp

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,8 @@ static UniValue getrawtransaction(const JSONRPCRequest& request)
157157
},
158158
}.Check(request);
159159

160+
const NodeContext& node = EnsureNodeContext(request.context);
161+
160162
bool in_active_chain = true;
161163
uint256 hash = ParseHashV(request.params[0], "parameter 1");
162164
CBlockIndex* blockindex = nullptr;
@@ -188,9 +190,9 @@ static UniValue getrawtransaction(const JSONRPCRequest& request)
188190
f_txindex_ready = g_txindex->BlockUntilSyncedToCurrentChain();
189191
}
190192

191-
CTransactionRef tx;
192193
uint256 hash_block;
193-
if (!GetTransaction(hash, tx, Params().GetConsensus(), hash_block, blockindex)) {
194+
const CTransactionRef tx = GetTransaction(blockindex, node.mempool, hash, Params().GetConsensus(), hash_block);
195+
if (!tx) {
194196
std::string errmsg;
195197
if (blockindex) {
196198
if (!(blockindex->nStatus & BLOCK_HAVE_DATA)) {
@@ -245,10 +247,11 @@ static UniValue gettxoutproof(const JSONRPCRequest& request)
245247
for (unsigned int idx = 0; idx < txids.size(); idx++) {
246248
const UniValue& txid = txids[idx];
247249
uint256 hash(ParseHashV(txid, "txid"));
248-
if (setTxids.count(hash))
249-
throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated txid: ")+txid.get_str());
250-
setTxids.insert(hash);
251-
oneTxid = hash;
250+
if (setTxids.count(hash)) {
251+
throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated txid: ") + txid.get_str());
252+
}
253+
setTxids.insert(hash);
254+
oneTxid = hash;
252255
}
253256

254257
CBlockIndex* pblockindex = nullptr;
@@ -281,27 +284,31 @@ static UniValue gettxoutproof(const JSONRPCRequest& request)
281284

282285
LOCK(cs_main);
283286

284-
if (pblockindex == nullptr)
285-
{
286-
CTransactionRef tx;
287-
if (!GetTransaction(oneTxid, tx, Params().GetConsensus(), hashBlock) || hashBlock.IsNull())
287+
if (pblockindex == nullptr) {
288+
const CTransactionRef tx = GetTransaction(/* block_index */ nullptr, /* mempool */ nullptr, oneTxid, Params().GetConsensus(), hashBlock);
289+
if (!tx || hashBlock.IsNull()) {
288290
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not yet in block");
291+
}
289292
pblockindex = LookupBlockIndex(hashBlock);
290293
if (!pblockindex) {
291294
throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction index corrupt");
292295
}
293296
}
294297

295298
CBlock block;
296-
if(!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus()))
299+
if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) {
297300
throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
301+
}
298302

299303
unsigned int ntxFound = 0;
300-
for (const auto& tx : block.vtx)
301-
if (setTxids.count(tx->GetHash()))
304+
for (const auto& tx : block.vtx) {
305+
if (setTxids.count(tx->GetHash())) {
302306
ntxFound++;
303-
if (ntxFound != setTxids.size())
307+
}
308+
}
309+
if (ntxFound != setTxids.size()) {
304310
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Not all transactions found in specified or retrieved block");
311+
}
305312

306313
CDataStream ssMB(SER_NETWORK, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS);
307314
CMerkleBlock mb(block, setTxids);

src/validation.cpp

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,45 +1089,33 @@ bool AcceptToMemoryPool(CTxMemPool& pool, TxValidationState &state, const CTrans
10891089
return AcceptToMemoryPoolWithTime(chainparams, pool, state, tx, GetTime(), plTxnReplaced, bypass_limits, nAbsurdFee, test_accept);
10901090
}
10911091

1092-
/**
1093-
* Return transaction in txOut, and if it was found inside a block, its hash is placed in hashBlock.
1094-
* If blockIndex is provided, the transaction is fetched from the corresponding block.
1095-
*/
1096-
bool GetTransaction(const uint256& hash, CTransactionRef& txOut, const Consensus::Params& consensusParams, uint256& hashBlock, const CBlockIndex* const block_index)
1092+
CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMemPool* const mempool, const uint256& hash, const Consensus::Params& consensusParams, uint256& hashBlock)
10971093
{
10981094
LOCK(cs_main);
10991095

1100-
if (!block_index) {
1101-
CTransactionRef ptx = mempool.get(hash);
1102-
if (ptx) {
1103-
txOut = ptx;
1104-
return true;
1105-
}
1106-
1107-
if (g_txindex) {
1108-
return g_txindex->FindTx(hash, hashBlock, txOut);
1109-
}
1110-
} else {
1096+
if (block_index) {
11111097
CBlock block;
11121098
if (ReadBlockFromDisk(block, block_index, consensusParams)) {
11131099
for (const auto& tx : block.vtx) {
11141100
if (tx->GetHash() == hash) {
1115-
txOut = tx;
11161101
hashBlock = block_index->GetBlockHash();
1117-
return true;
1102+
return tx;
11181103
}
11191104
}
11201105
}
1106+
return nullptr;
11211107
}
1122-
1123-
return false;
1108+
if (mempool) {
1109+
CTransactionRef ptx = mempool->get(hash);
1110+
if (ptx) return ptx;
1111+
}
1112+
if (g_txindex) {
1113+
CTransactionRef tx;
1114+
if (g_txindex->FindTx(hash, hashBlock, tx)) return tx;
1115+
}
1116+
return nullptr;
11241117
}
11251118

1126-
1127-
1128-
1129-
1130-
11311119
//////////////////////////////////////////////////////////////////////////////
11321120
//
11331121
// CBlock and CBlockIndex

src/validation.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,19 @@ bool LoadGenesisBlock(const CChainParams& chainparams);
164164
void UnloadBlockIndex();
165165
/** Run an instance of the script checking thread */
166166
void ThreadScriptCheck(int worker_num);
167-
/** Retrieve a transaction (from memory pool, or from disk, if possible) */
168-
bool GetTransaction(const uint256& hash, CTransactionRef& tx, const Consensus::Params& params, uint256& hashBlock, const CBlockIndex* const blockIndex = nullptr);
167+
/**
168+
* Return transaction from the block at block_index.
169+
* If block_index is not provided, fall back to mempool.
170+
* If mempool is not provided or the tx couldn't be found in mempool, fall back to g_txindex.
171+
*
172+
* @param[in] block_index The block to read from disk, or nullptr
173+
* @param[in] mempool If block_index is not provided, look in the mempool, if provided
174+
* @param[in] hash The txid
175+
* @param[in] consensusParams The params
176+
* @param[out] hashBlock The hash of block_index, if the tx was found via block_index
177+
* @returns The tx if found, otherwise nullptr
178+
*/
179+
CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMemPool* const mempool, const uint256& hash, const Consensus::Params& consensusParams, uint256& hashBlock);
169180
/**
170181
* Find the best known block, and make it the tip of the block chain
171182
*

0 commit comments

Comments
 (0)