diff --git a/src/kernel/coinstats.cpp b/src/kernel/coinstats.cpp index d287ec4be6e..49b51d64f30 100644 --- a/src/kernel/coinstats.cpp +++ b/src/kernel/coinstats.cpp @@ -109,9 +109,8 @@ static void ApplyStats(CCoinsStats& stats, const std::map& outpu //! Calculate statistics about the unspent transaction output set template -static bool ComputeUTXOStats(CCoinsView* view, CCoinsStats& stats, T hash_obj, const std::function& interruption_point) +static bool ComputeUTXOStats(CCoinsView* view, CCoinsStats& stats, T hash_obj, const std::function& interruption_point, std::unique_ptr pcursor) { - std::unique_ptr pcursor(view->Cursor()); assert(pcursor); Txid prevkey; @@ -149,21 +148,27 @@ static bool ComputeUTXOStats(CCoinsView* view, CCoinsStats& stats, T hash_obj, c std::optional ComputeUTXOStats(CoinStatsHashType hash_type, CCoinsView* view, node::BlockManager& blockman, const std::function& interruption_point) { - CBlockIndex* pindex = WITH_LOCK(::cs_main, return blockman.LookupBlockIndex(view->GetBestBlock())); + std::unique_ptr pcursor; + CBlockIndex* pindex; + { + LOCK(::cs_main); + pcursor = view->Cursor(); + pindex = blockman.LookupBlockIndex(pcursor->GetBestBlock()); + } CCoinsStats stats{Assert(pindex)->nHeight, pindex->GetBlockHash()}; bool success = [&]() -> bool { switch (hash_type) { case(CoinStatsHashType::HASH_SERIALIZED): { HashWriter ss{}; - return ComputeUTXOStats(view, stats, ss, interruption_point); + return ComputeUTXOStats(view, stats, ss, interruption_point, std::move(pcursor)); } case(CoinStatsHashType::MUHASH): { MuHash3072 muhash; - return ComputeUTXOStats(view, stats, muhash, interruption_point); + return ComputeUTXOStats(view, stats, muhash, interruption_point, std::move(pcursor)); } case(CoinStatsHashType::NONE): { - return ComputeUTXOStats(view, stats, nullptr, interruption_point); + return ComputeUTXOStats(view, stats, nullptr, interruption_point, std::move(pcursor)); } } // no default case, so the compiler can warn about missing cases assert(false); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index af21e83f0d1..5f9885fdee2 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -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 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 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"); }