mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-09-13 06:04:42 +02:00
rpc: avoid quadratic prevout resolution
`gettxspendingprevout` erases each mempool result from its worklist while holding `mempool.cs`, shifting the remaining requests every time and making the pass quadratic when it resolves many requests. Collect unresolved requests in a reserved worklist so the mempool pass is linear and the compiler can verify the lock requirement on `GetConflictTx`. Co-authored-by: Andrew Toth <andrewstoth@gmail.com>
This commit is contained in:
@@ -1020,32 +1020,32 @@ static RPCMethod gettxspendingprevout()
|
||||
std::vector<UniValue> results(output_params.size());
|
||||
|
||||
// Search the mempool first
|
||||
std::vector<Entry> unresolved;
|
||||
unresolved.reserve(prevouts_to_process.size());
|
||||
{
|
||||
const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
|
||||
LOCK(mempool.cs);
|
||||
|
||||
// Make the result if the spending tx appears in the mempool or this is a mempool_only request
|
||||
for (auto it = prevouts_to_process.begin(); it != prevouts_to_process.end(); ) {
|
||||
const CTransaction* spending_tx{mempool.GetConflictTx(it->outpoint)};
|
||||
for (const auto& prevout : prevouts_to_process) {
|
||||
const auto* spending_tx{mempool.GetConflictTx(prevout.outpoint)};
|
||||
|
||||
// If the outpoint is not spent in the mempool and this is not a mempool-only
|
||||
// request, we cannot answer it yet.
|
||||
if (!spending_tx && !mempool_only) {
|
||||
++it;
|
||||
continue;
|
||||
unresolved.push_back(prevout);
|
||||
} else {
|
||||
results[prevout.request_index] = make_output(prevout, spending_tx);
|
||||
}
|
||||
|
||||
results[it->request_index] = make_output(*it, spending_tx);
|
||||
it = prevouts_to_process.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
// mempool_only requests resolve every outpoint above, so only other requests reach the index.
|
||||
if (!prevouts_to_process.empty() && (!g_txospenderindex || !g_txospenderindex->BlockUntilSyncedToCurrentChain())) {
|
||||
if (!unresolved.empty() && (!g_txospenderindex || !g_txospenderindex->BlockUntilSyncedToCurrentChain())) {
|
||||
throw JSONRPCError(RPC_MISC_ERROR, "Mempool lacks a relevant spend, and txospenderindex is unavailable.");
|
||||
}
|
||||
|
||||
for (const auto& prevout : prevouts_to_process) {
|
||||
for (const auto& prevout : unresolved) {
|
||||
const auto spender{g_txospenderindex->FindSpender(prevout.outpoint)};
|
||||
if (!spender) {
|
||||
throw JSONRPCError(RPC_MISC_ERROR, spender.error());
|
||||
|
||||
Reference in New Issue
Block a user