Bitcoin Core 31.99.0
P2P Digital Currency
coinstats.cpp
Go to the documentation of this file.
1// Copyright (c) 2022-present The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#include <kernel/coinstats.h>
6
7#include <chain.h>
8#include <coins.h>
9#include <crypto/muhash.h>
10#include <hash.h>
11#include <node/blockstorage.h>
13#include <script/script.h>
14#include <span.h>
15#include <streams.h>
16#include <sync.h>
17#include <uint256.h>
18#include <util/check.h>
19#include <util/log.h>
20#include <util/overflow.h>
21#include <validation.h>
22
23#include <cstddef>
24#include <map>
25#include <memory>
26#include <utility>
27
28namespace kernel {
29
30CCoinsStats::CCoinsStats(int block_height, const uint256& block_hash)
31 : nHeight(block_height),
32 hashBlock(block_hash) {}
33
34// Database-independent metric indicating the UTXO set size
35uint64_t GetBogoSize(const CScript& script_pub_key)
36{
37 return 32 /* txid */ +
38 4 /* vout index */ +
39 4 /* height + coinbase */ +
40 8 /* amount */ +
41 2 /* scriptPubKey len */ +
42 script_pub_key.size() /* scriptPubKey */;
43}
44
45template <typename T>
46static void TxOutSer(T& ss, const COutPoint& outpoint, const Coin& coin)
47{
48 ss << outpoint;
49 ss << ((uint32_t{coin.nHeight} << 1) | uint32_t{coin.fCoinBase});
50 ss << coin.out;
51}
52
53static void ApplyCoinHash(HashWriter& ss, const COutPoint& outpoint, const Coin& coin)
54{
55 TxOutSer(ss, outpoint, coin);
56}
57
58void ApplyCoinHash(MuHash3072& muhash, const COutPoint& outpoint, const Coin& coin)
59{
60 DataStream ss{};
61 TxOutSer(ss, outpoint, coin);
62 muhash.Insert(MakeUCharSpan(ss));
63}
64
65void RemoveCoinHash(MuHash3072& muhash, const COutPoint& outpoint, const Coin& coin)
66{
67 DataStream ss{};
68 TxOutSer(ss, outpoint, coin);
69 muhash.Remove(MakeUCharSpan(ss));
70}
71
72static void ApplyCoinHash(std::nullptr_t, const COutPoint& outpoint, const Coin& coin) {}
73
86template <typename T>
87static void ApplyHash(T& hash_obj, const Txid& hash, const std::map<uint32_t, Coin>& outputs)
88{
89 for (auto it = outputs.begin(); it != outputs.end(); ++it) {
90 COutPoint outpoint = COutPoint(hash, it->first);
91 Coin coin = it->second;
92 ApplyCoinHash(hash_obj, outpoint, coin);
93 }
94}
95
96static void ApplyStats(CCoinsStats& stats, const std::map<uint32_t, Coin>& outputs)
97{
98 assert(!outputs.empty());
99 stats.nTransactions++;
100 for (auto it = outputs.begin(); it != outputs.end(); ++it) {
101 stats.nTransactionOutputs++;
102 if (stats.total_amount.has_value()) {
103 stats.total_amount = CheckedAdd(*stats.total_amount, it->second.out.nValue);
104 }
105 stats.nBogoSize += GetBogoSize(it->second.out.scriptPubKey);
106 }
107}
108
110template <typename T>
111static std::optional<CCoinsStats> ComputeUTXOStats(T hash_obj, CCoinsView* view, node::BlockManager& blockman, const std::function<void()>& interruption_point)
112{
113 std::unique_ptr<CCoinsViewCursor> pcursor;
114 CBlockIndex* pindex;
115 {
117 pcursor = view->Cursor();
118 pindex = blockman.LookupBlockIndex(pcursor->GetBestBlock());
119 }
120 assert(pcursor);
121 CCoinsStats stats{Assert(pindex)->nHeight, pindex->GetBlockHash()};
122
123 Txid prevkey;
124 std::map<uint32_t, Coin> outputs;
125 while (pcursor->Valid()) {
126 if (interruption_point) interruption_point();
127 COutPoint key;
128 Coin coin;
129 if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
130 if (!outputs.empty() && key.hash != prevkey) {
131 ApplyStats(stats, outputs);
132 ApplyHash(hash_obj, prevkey, outputs);
133 outputs.clear();
134 }
135 prevkey = key.hash;
136 outputs[key.n] = std::move(coin);
137 stats.coins_count++;
138 } else {
139 LogError("%s: unable to read value\n", __func__);
140 return std::nullopt;
141 }
142 pcursor->Next();
143 }
144 if (!outputs.empty()) {
145 ApplyStats(stats, outputs);
146 ApplyHash(hash_obj, prevkey, outputs);
147 }
148
149 FinalizeHash(hash_obj, stats);
150
151 stats.nDiskSize = view->EstimateSize();
152 return stats;
153}
154
155std::optional<CCoinsStats> ComputeUTXOStats(CoinStatsHashType hash_type, CCoinsView* view, node::BlockManager& blockman, const std::function<void()>& interruption_point)
156{
157 return [&]() -> std::optional<CCoinsStats> {
158 switch (hash_type) {
160 HashWriter ss{};
161 return ComputeUTXOStats(ss, view, blockman, interruption_point);
162 }
164 MuHash3072 muhash;
165 return ComputeUTXOStats(muhash, view, blockman, interruption_point);
166 }
168 return ComputeUTXOStats(nullptr, view, blockman, interruption_point);
169 }
170 } // no default case, so the compiler can warn about missing cases
171 assert(false);
172 }();
173}
174
175static void FinalizeHash(HashWriter& ss, CCoinsStats& stats)
176{
177 stats.hashSerialized = ss.GetHash();
178}
179static void FinalizeHash(MuHash3072& muhash, CCoinsStats& stats)
180{
181 uint256 out;
182 muhash.Finalize(out);
183 stats.hashSerialized = out;
184}
185static void FinalizeHash(std::nullptr_t, CCoinsStats& stats) {}
186
187} // namespace kernel
#define Assert(val)
Identity function.
Definition: check.h:116
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: chain.h:94
uint256 GetBlockHash() const
Definition: chain.h:198
Pure abstract view on the open txout dataset.
Definition: coins.h:308
virtual size_t EstimateSize() const =0
Estimate database size.
virtual std::unique_ptr< CCoinsViewCursor > Cursor() const =0
Get a cursor to iterate over the whole state. Implementations may return nullptr.
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:29
uint32_t n
Definition: transaction.h:32
Txid hash
Definition: transaction.h:31
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:405
A UTXO entry.
Definition: coins.h:35
CTxOut out
unspent transaction output
Definition: coins.h:38
bool fCoinBase
whether containing transaction was a coinbase
Definition: coins.h:41
uint32_t nHeight
at which height this containing transaction was included in the active block chain
Definition: coins.h:44
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:165
A writer stream (for serialization) that computes a 256-bit hash.
Definition: hash.h:101
uint256 GetHash()
Compute the double-SHA256 hash of all data written to this object.
Definition: hash.h:115
A class representing MuHash sets.
Definition: muhash.h:103
void Finalize(uint256 &out) noexcept
Definition: muhash.cpp:552
MuHash3072 & Insert(std::span< const unsigned char > in) noexcept
Definition: muhash.cpp:577
MuHash3072 & Remove(std::span< const unsigned char > in) noexcept
Definition: muhash.cpp:582
Maintains a tree of blocks (stored in m_block_index) which is consulted to determine where the most-w...
Definition: blockstorage.h:194
CBlockIndex * LookupBlockIndex(const uint256 &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
size_type size() const
Definition: prevector.h:247
256-bit opaque blob.
Definition: uint256.h:196
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: cs_main.cpp:8
#define LogError(...)
Definition: log.h:105
unsigned int nHeight
static void FinalizeHash(HashWriter &ss, CCoinsStats &stats)
Definition: coinstats.cpp:175
static void ApplyStats(CCoinsStats &stats, const std::map< uint32_t, Coin > &outputs)
Definition: coinstats.cpp:96
void RemoveCoinHash(MuHash3072 &muhash, const COutPoint &outpoint, const Coin &coin)
Definition: coinstats.cpp:65
CoinStatsHashType
Definition: coinstats.h:26
static void ApplyCoinHash(HashWriter &ss, const COutPoint &outpoint, const Coin &coin)
Definition: coinstats.cpp:53
static void ApplyHash(T &hash_obj, const Txid &hash, const std::map< uint32_t, Coin > &outputs)
Warning: be very careful when changing this! assumeutxo and UTXO snapshot validation commitments are ...
Definition: coinstats.cpp:87
static std::optional< CCoinsStats > ComputeUTXOStats(T hash_obj, CCoinsView *view, node::BlockManager &blockman, const std::function< void()> &interruption_point)
Calculate statistics about the unspent transaction output set.
Definition: coinstats.cpp:111
uint64_t GetBogoSize(const CScript &script_pub_key)
Definition: coinstats.cpp:35
static void TxOutSer(T &ss, const COutPoint &outpoint, const Coin &coin)
Definition: coinstats.cpp:46
std::optional< T > CheckedAdd(const T i, const T j) noexcept
Definition: overflow.h:28
constexpr auto MakeUCharSpan(const V &v) -> decltype(UCharSpanCast(std::span{v}))
Like the std::span constructor, but for (const) unsigned char member types only.
Definition: span.h:111
std::optional< CAmount > total_amount
The total amount, or nullopt if an overflow occurred calculating it.
Definition: coinstats.h:41
uint64_t nTransactions
Definition: coinstats.h:35
uint64_t nTransactionOutputs
Definition: coinstats.h:36
uint64_t nBogoSize
Definition: coinstats.h:37
uint256 hashSerialized
Definition: coinstats.h:38
#define LOCK(cs)
Definition: sync.h:268
assert(!tx.IsCoinBase())