diff options
author | Carl Dong <contact@carldong.me> | 2022-02-16 14:11:19 -0500 |
---|---|---|
committer | Carl Dong <contact@carldong.me> | 2022-05-23 14:52:23 -0400 |
commit | 1352e410a5b84070279ff28399083cb3ab278593 (patch) | |
tree | 09eb4ce4455f98a8c1c875e4aefb697ead136245 /src | |
parent | 524463daf6a10b20a4e20116a68101a684929eda (diff) | |
download | bitcoin-1352e410a5b84070279ff28399083cb3ab278593.tar.xz |
coinstats: Separate hasher/index lookup codepaths
Split out ComputeUTXOStats and LookupUTXOStatsWithIndex from
GetUTXOStats, since the hashing and indexing codepaths are quite
disparate in practice.
Also allow add a constructor to CCoinsStats for it to be constructed
from a a block height and hash. This is used in both codepaths.
Also add a note in GetUTXOStats documenting a behaviour quirk that
predates this patchset.
[META] This allows the hashing codepath to be moved to a separate file
in a future commit, decoupling callers that only rely on the
hashing codepath from the indexing one. This is key for
libbitcoinkernel, which needs to have the hashing codepath for
AssumeUTXO, but does not wish to be coupled with indexes.
Diffstat (limited to 'src')
-rw-r--r-- | src/node/coinstats.cpp | 71 | ||||
-rw-r--r-- | src/node/coinstats.h | 3 |
2 files changed, 55 insertions, 19 deletions
diff --git a/src/node/coinstats.cpp b/src/node/coinstats.cpp index 8fc53fe172..26badd6eb2 100644 --- a/src/node/coinstats.cpp +++ b/src/node/coinstats.cpp @@ -19,6 +19,11 @@ #include <map> namespace node { + +CCoinsStats::CCoinsStats(int block_height, const uint256& block_hash) + : nHeight(block_height), + hashBlock(block_hash) {} + // Database-independent metric indicating the UTXO set size uint64_t GetBogoSize(const CScript& script_pub_key) { @@ -94,24 +99,11 @@ static void ApplyStats(CCoinsStats& stats, const uint256& hash, const std::map<u //! Calculate statistics about the unspent transaction output set template <typename T> -static bool GetUTXOStats(CCoinsView* view, BlockManager& blockman, CCoinsStats& stats, T hash_obj, const std::function<void()>& interruption_point, const CBlockIndex* pindex, CoinStatsHashType& hash_type, bool index_requested) +static bool ComputeUTXOStats(CCoinsView* view, CCoinsStats& stats, T hash_obj, const std::function<void()>& interruption_point) { std::unique_ptr<CCoinsViewCursor> pcursor(view->Cursor()); assert(pcursor); - if (!pindex) { - LOCK(cs_main); - pindex = blockman.LookupBlockIndex(view->GetBestBlock()); - } - stats.nHeight = Assert(pindex)->nHeight; - stats.hashBlock = pindex->GetBlockHash(); - - // Use CoinStatsIndex if it is requested and available and a hash_type of Muhash or None was requested - if ((hash_type == CoinStatsHashType::MUHASH || hash_type == CoinStatsHashType::NONE) && g_coin_stats_index && index_requested) { - stats.index_used = true; - return g_coin_stats_index->LookUpStats(pindex, stats); - } - PrepareHash(hash_obj, stats); uint256 prevkey; @@ -142,25 +134,27 @@ static bool GetUTXOStats(CCoinsView* view, BlockManager& blockman, CCoinsStats& FinalizeHash(hash_obj, stats); stats.nDiskSize = view->EstimateSize(); + return true; } -std::optional<CCoinsStats> GetUTXOStats(CCoinsView* view, BlockManager& blockman, CoinStatsHashType hash_type, const std::function<void()>& interruption_point, const CBlockIndex* pindex, bool index_requested) +std::optional<CCoinsStats> ComputeUTXOStats(CoinStatsHashType hash_type, CCoinsView* view, BlockManager& blockman, const std::function<void()>& interruption_point) { - CCoinsStats stats{}; + CBlockIndex* pindex = WITH_LOCK(::cs_main, return blockman.LookupBlockIndex(view->GetBestBlock())); + CCoinsStats stats{Assert(pindex)->nHeight, pindex->GetBlockHash()}; bool success = [&]() -> bool { switch (hash_type) { case(CoinStatsHashType::HASH_SERIALIZED): { CHashWriter ss(SER_GETHASH, PROTOCOL_VERSION); - return GetUTXOStats(view, blockman, stats, ss, interruption_point, pindex, hash_type, index_requested); + return ComputeUTXOStats(view, stats, ss, interruption_point); } case(CoinStatsHashType::MUHASH): { MuHash3072 muhash; - return GetUTXOStats(view, blockman, stats, muhash, interruption_point, pindex, hash_type, index_requested); + return ComputeUTXOStats(view, stats, muhash, interruption_point); } case(CoinStatsHashType::NONE): { - return GetUTXOStats(view, blockman, stats, nullptr, interruption_point, pindex, hash_type, index_requested); + return ComputeUTXOStats(view, stats, nullptr, interruption_point); } } // no default case, so the compiler can warn about missing cases assert(false); @@ -192,4 +186,43 @@ static void FinalizeHash(MuHash3072& muhash, CCoinsStats& stats) stats.hashSerialized = out; } static void FinalizeHash(std::nullptr_t, CCoinsStats& stats) {} + +std::optional<CCoinsStats> LookupUTXOStatsWithIndex(CoinStatsIndex& coin_stats_index, const CBlockIndex* pindex) +{ + CCoinsStats stats{Assert(pindex)->nHeight, pindex->GetBlockHash()}; + + stats.index_used = true; + if (!coin_stats_index.LookUpStats(pindex, stats)) { + return std::nullopt; + } + + return stats; +} + +std::optional<CCoinsStats> LookupUTXOStatsWithIndex(CoinStatsIndex& coin_stats_index, CCoinsView* view, BlockManager& blockman) +{ + CBlockIndex* pindex = WITH_LOCK(::cs_main, return blockman.LookupBlockIndex(view->GetBestBlock())); + + return LookupUTXOStatsWithIndex(coin_stats_index, pindex); +} + +std::optional<CCoinsStats> GetUTXOStats(CCoinsView* view, BlockManager& blockman, CoinStatsHashType hash_type, const std::function<void()>& interruption_point, const CBlockIndex* pindex, bool index_requested) +{ + // Use CoinStatsIndex if it is requested and available and a hash_type of Muhash or None was requested + if ((hash_type == CoinStatsHashType::MUHASH || hash_type == CoinStatsHashType::NONE) && g_coin_stats_index && index_requested) { + if (pindex) { + return LookupUTXOStatsWithIndex(*g_coin_stats_index, pindex); + } else { + return LookupUTXOStatsWithIndex(*g_coin_stats_index, view, blockman); + } + } + + // If the coinstats index isn't requested or is otherwise not usable, the + // pindex should either be null or equal to the view's best block. This is + // because without the coinstats index we can only get coinstats about the + // best block. + assert(!pindex || pindex->GetBlockHash() == view->GetBestBlock()); + + return ComputeUTXOStats(hash_type, view, blockman, interruption_point); +} } // namespace node diff --git a/src/node/coinstats.h b/src/node/coinstats.h index 36cbf19f29..d74d70deb2 100644 --- a/src/node/coinstats.h +++ b/src/node/coinstats.h @@ -64,6 +64,9 @@ struct CCoinsStats { CAmount total_unspendables_scripts{0}; //! Total cumulative amount of coins lost due to unclaimed miner rewards up to and including this block CAmount total_unspendables_unclaimed_rewards{0}; + + CCoinsStats() = default; + CCoinsStats(int block_height, const uint256& block_hash); }; /** |