diff --git a/src/node/coinstats.h b/src/node/coinstats.h --- a/src/node/coinstats.h +++ b/src/node/coinstats.h @@ -13,6 +13,7 @@ #include #include +class BlockManager; class CCoinsView; enum class CoinStatsHashType { @@ -36,7 +37,7 @@ }; //! Calculate statistics about the unspent transaction output set -bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats, +bool GetUTXOStats(CCoinsView *view, BlockManager &blockman, CCoinsStats &stats, const CoinStatsHashType hash_type, const std::function &interruption_point = {}); diff --git a/src/node/coinstats.cpp b/src/node/coinstats.cpp --- a/src/node/coinstats.cpp +++ b/src/node/coinstats.cpp @@ -85,7 +85,8 @@ //! Calculate statistics about the unspent transaction output set template -static bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats, T hash_obj, +static bool GetUTXOStats(CCoinsView *view, BlockManager &blockman, + CCoinsStats &stats, T hash_obj, const std::function &interruption_point) { stats = CCoinsStats(); std::unique_ptr pcursor(view->Cursor()); @@ -94,8 +95,10 @@ stats.hashBlock = pcursor->GetBestBlock(); { LOCK(cs_main); - const CBlockIndex *block = - g_chainman.m_blockman.LookupBlockIndex(stats.hashBlock); + assert(std::addressof(g_chainman.m_blockman) == + std::addressof(blockman)); + + const CBlockIndex *block = blockman.LookupBlockIndex(stats.hashBlock); stats.nHeight = Assert(block)->nHeight; } @@ -130,20 +133,22 @@ return true; } -bool GetUTXOStats(CCoinsView *view, CCoinsStats &stats, +bool GetUTXOStats(CCoinsView *view, BlockManager &blockman, CCoinsStats &stats, CoinStatsHashType hash_type, const std::function &interruption_point) { switch (hash_type) { case (CoinStatsHashType::HASH_SERIALIZED): { CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); - return GetUTXOStats(view, stats, ss, interruption_point); + return GetUTXOStats(view, blockman, stats, ss, interruption_point); } case (CoinStatsHashType::MUHASH): { MuHash3072 muhash; - return GetUTXOStats(view, stats, muhash, interruption_point); + return GetUTXOStats(view, blockman, stats, muhash, + interruption_point); } case (CoinStatsHashType::NONE): { - return GetUTXOStats(view, stats, nullptr, interruption_point); + return GetUTXOStats(view, blockman, stats, nullptr, + interruption_point); } } // 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 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1275,10 +1275,12 @@ : ParseHashType(request.params[0].get_str())}; CCoinsView *coins_view = - WITH_LOCK(cs_main, return &ChainstateActive().CoinsDB()); + WITH_LOCK(::cs_main, return &::ChainstateActive().CoinsDB()); NodeContext &node = EnsureNodeContext(request.context); - if (GetUTXOStats(coins_view, stats, hash_type, - node.rpc_interruption_point)) { + if (GetUTXOStats(coins_view, + WITH_LOCK(::cs_main, + return std::ref(g_chainman.m_blockman)), + stats, hash_type, node.rpc_interruption_point)) { ret.pushKV("height", int64_t(stats.nHeight)); ret.pushKV("bestblock", stats.hashBlock.GetHex()); ret.pushKV("transactions", int64_t(stats.nTransactions)); @@ -3044,7 +3046,8 @@ chainstate.ForceFlushStateToDisk(); - if (!GetUTXOStats(&chainstate.CoinsDB(), stats, CoinStatsHashType::NONE, + if (!GetUTXOStats(&chainstate.CoinsDB(), chainstate.m_blockman, stats, + CoinStatsHashType::NONE, node.rpc_interruption_point)) { throw JSONRPCError(RPC_INTERNAL_ERROR, "Unable to read UTXO set"); } diff --git a/src/test/fuzz/coins_view.cpp b/src/test/fuzz/coins_view.cpp --- a/src/test/fuzz/coins_view.cpp +++ b/src/test/fuzz/coins_view.cpp @@ -302,8 +302,11 @@ CCoinsStats stats; bool expected_code_path = false; try { - (void)GetUTXOStats(&coins_view_cache, stats, - CoinStatsHashType::HASH_SERIALIZED); + (void)GetUTXOStats( + &coins_view_cache, + WITH_LOCK(::cs_main, + return std::ref(g_chainman.m_blockman)), + stats, CoinStatsHashType::HASH_SERIALIZED); } catch (const std::logic_error &) { expected_code_path = true; } diff --git a/src/validation.cpp b/src/validation.cpp --- a/src/validation.cpp +++ b/src/validation.cpp @@ -6295,7 +6295,8 @@ CCoinsViewDB *snapshot_coinsdb = WITH_LOCK(::cs_main, return &snapshot_chainstate.CoinsDB()); - if (!GetUTXOStats(snapshot_coinsdb, stats, + if (!GetUTXOStats(snapshot_coinsdb, + WITH_LOCK(::cs_main, return std::ref(m_blockman)), stats, CoinStatsHashType::HASH_SERIALIZED, breakpoint_fnc)) { LogPrintf("[snapshot] failed to generate coins stats\n"); return false;