Bitcoin Core 28.99.0
P2P Digital Currency
coinstats.cpp
Go to the documentation of this file.
1// Copyright (c) 2022 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 <logging.h>
12#include <node/blockstorage.h>
14#include <script/script.h>
15#include <serialize.h>
16#include <span.h>
17#include <streams.h>
18#include <sync.h>
19#include <tinyformat.h>
20#include <uint256.h>
21#include <util/check.h>
22#include <util/overflow.h>
23#include <validation.h>
24
25#include <cassert>
26#include <iosfwd>
27#include <iterator>
28#include <map>
29#include <memory>
30#include <string>
31#include <utility>
32
33namespace kernel {
34
35CCoinsStats::CCoinsStats(int block_height, const uint256& block_hash)
36 : nHeight(block_height),
37 hashBlock(block_hash) {}
38
39// Database-independent metric indicating the UTXO set size
40uint64_t GetBogoSize(const CScript& script_pub_key)
41{
42 return 32 /* txid */ +
43 4 /* vout index */ +
44 4 /* height + coinbase */ +
45 8 /* amount */ +
46 2 /* scriptPubKey len */ +
47 script_pub_key.size() /* scriptPubKey */;
48}
49
50template <typename T>
51static void TxOutSer(T& ss, const COutPoint& outpoint, const Coin& coin)
52{
53 ss << outpoint;
54 ss << static_cast<uint32_t>((coin.nHeight << 1) + coin.fCoinBase);
55 ss << coin.out;
56}
57
58static void ApplyCoinHash(HashWriter& ss, const COutPoint& outpoint, const Coin& coin)
59{
60 TxOutSer(ss, outpoint, coin);
61}
62
63void ApplyCoinHash(MuHash3072& muhash, const COutPoint& outpoint, const Coin& coin)
64{
65 DataStream ss{};
66 TxOutSer(ss, outpoint, coin);
67 muhash.Insert(MakeUCharSpan(ss));
68}
69
70void RemoveCoinHash(MuHash3072& muhash, const COutPoint& outpoint, const Coin& coin)
71{
72 DataStream ss{};
73 TxOutSer(ss, outpoint, coin);
74 muhash.Remove(MakeUCharSpan(ss));
75}
76
77static void ApplyCoinHash(std::nullptr_t, const COutPoint& outpoint, const Coin& coin) {}
78
91template <typename T>
92static void ApplyHash(T& hash_obj, const Txid& hash, const std::map<uint32_t, Coin>& outputs)
93{
94 for (auto it = outputs.begin(); it != outputs.end(); ++it) {
95 COutPoint outpoint = COutPoint(hash, it->first);
96 Coin coin = it->second;
97 ApplyCoinHash(hash_obj, outpoint, coin);
98 }
99}
100
101static void ApplyStats(CCoinsStats& stats, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
102{
103 assert(!outputs.empty());
104 stats.nTransactions++;
105 for (auto it = outputs.begin(); it != outputs.end(); ++it) {
106 stats.nTransactionOutputs++;
107 if (stats.total_amount.has_value()) {
108 stats.total_amount = CheckedAdd(*stats.total_amount, it->second.out.nValue);
109 }
110 stats.nBogoSize += GetBogoSize(it->second.out.scriptPubKey);
111 }
112}
113
115template <typename T>
116static bool ComputeUTXOStats(CCoinsView* view, CCoinsStats& stats, T hash_obj, const std::function<void()>& interruption_point)
117{
118 std::unique_ptr<CCoinsViewCursor> pcursor(view->Cursor());
119 assert(pcursor);
120
121 Txid prevkey;
122 std::map<uint32_t, Coin> outputs;
123 while (pcursor->Valid()) {
124 if (interruption_point) interruption_point();
125 COutPoint key;
126 Coin coin;
127 if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
128 if (!outputs.empty() && key.hash != prevkey) {
129 ApplyStats(stats, prevkey, outputs);
130 ApplyHash(hash_obj, prevkey, outputs);
131 outputs.clear();
132 }
133 prevkey = key.hash;
134 outputs[key.n] = std::move(coin);
135 stats.coins_count++;
136 } else {
137 LogError("%s: unable to read value\n", __func__);
138 return false;
139 }
140 pcursor->Next();
141 }
142 if (!outputs.empty()) {
143 ApplyStats(stats, prevkey, outputs);
144 ApplyHash(hash_obj, prevkey, outputs);
145 }
146
147 FinalizeHash(hash_obj, stats);
148
149 stats.nDiskSize = view->EstimateSize();
150
151 return true;
152}
153
154std::optional<CCoinsStats> ComputeUTXOStats(CoinStatsHashType hash_type, CCoinsView* view, node::BlockManager& blockman, const std::function<void()>& interruption_point)
155{
156 CBlockIndex* pindex = WITH_LOCK(::cs_main, return blockman.LookupBlockIndex(view->GetBestBlock()));
157 CCoinsStats stats{Assert(pindex)->nHeight, pindex->GetBlockHash()};
158
159 bool success = [&]() -> bool {
160 switch (hash_type) {
162 HashWriter ss{};
163 return ComputeUTXOStats(view, stats, ss, interruption_point);
164 }
166 MuHash3072 muhash;
167 return ComputeUTXOStats(view, stats, muhash, interruption_point);
168 }
170 return ComputeUTXOStats(view, stats, nullptr, interruption_point);
171 }
172 } // no default case, so the compiler can warn about missing cases
173 assert(false);
174 }();
175
176 if (!success) {
177 return std::nullopt;
178 }
179 return stats;
180}
181
182static void FinalizeHash(HashWriter& ss, CCoinsStats& stats)
183{
184 stats.hashSerialized = ss.GetHash();
185}
186static void FinalizeHash(MuHash3072& muhash, CCoinsStats& stats)
187{
188 uint256 out;
189 muhash.Finalize(out);
190 stats.hashSerialized = out;
191}
192static void FinalizeHash(std::nullptr_t, CCoinsStats& stats) {}
193
194} // namespace kernel
#define Assert(val)
Identity function.
Definition: check.h:85
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: chain.h:141
uint256 GetBlockHash() const
Definition: chain.h:243
Abstract view on the open txout dataset.
Definition: coins.h:310
virtual size_t EstimateSize() const
Estimate database size (0 if not implemented)
Definition: coins.h:338
virtual std::unique_ptr< CCoinsViewCursor > Cursor() const
Get a cursor to iterate over the whole state.
Definition: coins.cpp:20
virtual uint256 GetBestBlock() const
Retrieve the block hash whose state this CCoinsView currently represents.
Definition: coins.cpp:17
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:415
A UTXO entry.
Definition: coins.h:33
CTxOut out
unspent transaction output
Definition: coins.h:36
uint32_t nHeight
at which height this containing transaction was included in the active block chain
Definition: coins.h:42
unsigned int fCoinBase
whether containing transaction was a coinbase
Definition: coins.h:39
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:147
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:91
void Finalize(uint256 &out) noexcept
Definition: muhash.cpp:314
MuHash3072 & Remove(Span< const unsigned char > in) noexcept
Definition: muhash.cpp:344
MuHash3072 & Insert(Span< const unsigned char > in) noexcept
Definition: muhash.cpp:339
Maintains a tree of blocks (stored in m_block_index) which is consulted to determine where the most-w...
Definition: blockstorage.h:136
CBlockIndex * LookupBlockIndex(const uint256 &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
size_type size() const
Definition: prevector.h:294
256-bit opaque blob.
Definition: uint256.h:190
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: logging.h:263
unsigned int nHeight
static void FinalizeHash(HashWriter &ss, CCoinsStats &stats)
Definition: coinstats.cpp:182
static void ApplyStats(CCoinsStats &stats, const uint256 &hash, const std::map< uint32_t, Coin > &outputs)
Definition: coinstats.cpp:101
void RemoveCoinHash(MuHash3072 &muhash, const COutPoint &outpoint, const Coin &coin)
Definition: coinstats.cpp:70
static bool ComputeUTXOStats(CCoinsView *view, CCoinsStats &stats, T hash_obj, const std::function< void()> &interruption_point)
Calculate statistics about the unspent transaction output set.
Definition: coinstats.cpp:116
CoinStatsHashType
Definition: coinstats.h:26
static void ApplyCoinHash(HashWriter &ss, const COutPoint &outpoint, const Coin &coin)
Definition: coinstats.cpp:58
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:92
uint64_t GetBogoSize(const CScript &script_pub_key)
Definition: coinstats.cpp:40
static void TxOutSer(T &ss, const COutPoint &outpoint, const Coin &coin)
Definition: coinstats.cpp:51
std::optional< T > CheckedAdd(const T i, const T j) noexcept
Definition: overflow.h:24
constexpr auto MakeUCharSpan(V &&v) -> decltype(UCharSpanCast(Span{std::forward< V >(v)}))
Like the Span constructor, but for (const) unsigned char member types only.
Definition: span.h:297
std::optional< CAmount > total_amount
The total amount, or nullopt if an overflow occurred calculating it.
Definition: coinstats.h:41
uint64_t nDiskSize
Definition: coinstats.h:39
uint64_t coins_count
The number of coins contained.
Definition: coinstats.h:44
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 WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:301
assert(!tx.IsCoinBase())