aboutsummaryrefslogtreecommitdiff
path: root/src/node
diff options
context:
space:
mode:
authorCarl Dong <contact@carldong.me>2022-02-16 14:11:19 -0500
committerCarl Dong <contact@carldong.me>2022-05-23 14:52:23 -0400
commit1352e410a5b84070279ff28399083cb3ab278593 (patch)
tree09eb4ce4455f98a8c1c875e4aefb697ead136245 /src/node
parent524463daf6a10b20a4e20116a68101a684929eda (diff)
downloadbitcoin-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/node')
-rw-r--r--src/node/coinstats.cpp71
-rw-r--r--src/node/coinstats.h3
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);
};
/**