rpc: fix race condition in gettxoutsetinfo

Fix an assertion failure in gettxoutsetinfo (issue #34263) caused by
capturing the best block before releasing cs_main, then checking it
against a potentially newer best block in GetUTXOStats().

Remove the early pindex capture since ComputeUTXOStats() independently
fetches the current best block under lock. Use stats.hashBlock and
stats.nHeight (the actual computed values) instead of the potentially
stale pindex when building the response.
This commit is contained in:
w0xlt
2026-01-27 12:57:32 -08:00
parent f82d076771
commit 5e77072fa6

View File

@@ -1080,7 +1080,6 @@ static RPCHelpMan gettxoutsetinfo()
LOCK(::cs_main);
coins_view = &active_chainstate.CoinsDB();
blockman = &active_chainstate.m_blockman;
pindex = blockman->LookupBlockIndex(coins_view->GetBestBlock());
}
if (!request.params[1].isNull()) {
@@ -1104,7 +1103,7 @@ static RPCHelpMan gettxoutsetinfo()
// If a specific block was requested and the index has already synced past that height, we can return the
// data already even though the index is not fully synced yet.
if (pindex->nHeight > summary.best_block_height) {
if (pindex && pindex->nHeight > summary.best_block_height) {
throw JSONRPCError(RPC_INTERNAL_ERROR, strprintf("Unable to get data because coinstatsindex is still syncing. Current height: %d", summary.best_block_height));
}
}
@@ -1130,8 +1129,9 @@ static RPCHelpMan gettxoutsetinfo()
ret.pushKV("disk_size", stats.nDiskSize);
} else {
CCoinsStats prev_stats{};
if (pindex->nHeight > 0) {
const std::optional<CCoinsStats> maybe_prev_stats = GetUTXOStats(coins_view, *blockman, hash_type, node.rpc_interruption_point, pindex->pprev, index_requested);
if (stats.nHeight > 0) {
const CBlockIndex& block_index = *CHECK_NONFATAL(WITH_LOCK(::cs_main, return blockman->LookupBlockIndex(stats.hashBlock)));
const std::optional<CCoinsStats> maybe_prev_stats = GetUTXOStats(coins_view, *blockman, hash_type, node.rpc_interruption_point, block_index.pprev, index_requested);
if (!maybe_prev_stats) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set");
}