Bitcoin Core  24.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 <node/blockstorage.h>
12 #include <primitives/transaction.h>
13 #include <script/script.h>
14 #include <serialize.h>
15 #include <span.h>
16 #include <streams.h>
17 #include <sync.h>
18 #include <tinyformat.h>
19 #include <uint256.h>
20 #include <util/check.h>
21 #include <util/overflow.h>
22 #include <util/system.h>
23 #include <validation.h>
24 #include <version.h>
25 
26 #include <cassert>
27 #include <iosfwd>
28 #include <iterator>
29 #include <map>
30 #include <memory>
31 #include <string>
32 #include <utility>
33 
34 namespace kernel {
35 
36 CCoinsStats::CCoinsStats(int block_height, const uint256& block_hash)
37  : nHeight(block_height),
38  hashBlock(block_hash) {}
39 
40 // Database-independent metric indicating the UTXO set size
41 uint64_t GetBogoSize(const CScript& script_pub_key)
42 {
43  return 32 /* txid */ +
44  4 /* vout index */ +
45  4 /* height + coinbase */ +
46  8 /* amount */ +
47  2 /* scriptPubKey len */ +
48  script_pub_key.size() /* scriptPubKey */;
49 }
50 
51 DataStream TxOutSer(const COutPoint& outpoint, const Coin& coin)
52 {
53  DataStream ss{};
54  ss << outpoint;
55  ss << static_cast<uint32_t>(coin.nHeight * 2 + coin.fCoinBase);
56  ss << coin.out;
57  return ss;
58 }
59 
72 static void ApplyHash(HashWriter& ss, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
73 {
74  for (auto it = outputs.begin(); it != outputs.end(); ++it) {
75  if (it == outputs.begin()) {
76  ss << hash;
77  ss << VARINT(it->second.nHeight * 2 + it->second.fCoinBase ? 1u : 0u);
78  }
79 
80  ss << VARINT(it->first + 1);
81  ss << it->second.out.scriptPubKey;
82  ss << VARINT_MODE(it->second.out.nValue, VarIntMode::NONNEGATIVE_SIGNED);
83 
84  if (it == std::prev(outputs.end())) {
85  ss << VARINT(0u);
86  }
87  }
88 }
89 
90 static void ApplyHash(std::nullptr_t, const uint256& hash, const std::map<uint32_t, Coin>& outputs) {}
91 
92 static void ApplyHash(MuHash3072& muhash, const uint256& 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  muhash.Insert(MakeUCharSpan(TxOutSer(outpoint, coin)));
98  }
99 }
100 
101 static 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 
115 template <typename T>
116 static 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  PrepareHash(hash_obj, stats);
122 
123  uint256 prevkey;
124  std::map<uint32_t, Coin> outputs;
125  while (pcursor->Valid()) {
126  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, prevkey, 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  return error("%s: unable to read value", __func__);
140  }
141  pcursor->Next();
142  }
143  if (!outputs.empty()) {
144  ApplyStats(stats, prevkey, outputs);
145  ApplyHash(hash_obj, prevkey, outputs);
146  }
147 
148  FinalizeHash(hash_obj, stats);
149 
150  stats.nDiskSize = view->EstimateSize();
151 
152  return true;
153 }
154 
155 std::optional<CCoinsStats> ComputeUTXOStats(CoinStatsHashType hash_type, CCoinsView* view, node::BlockManager& blockman, const std::function<void()>& interruption_point)
156 {
157  CBlockIndex* pindex = WITH_LOCK(::cs_main, return blockman.LookupBlockIndex(view->GetBestBlock()));
158  CCoinsStats stats{Assert(pindex)->nHeight, pindex->GetBlockHash()};
159 
160  bool success = [&]() -> bool {
161  switch (hash_type) {
163  HashWriter ss{};
164  return ComputeUTXOStats(view, stats, ss, interruption_point);
165  }
167  MuHash3072 muhash;
168  return ComputeUTXOStats(view, stats, muhash, interruption_point);
169  }
170  case(CoinStatsHashType::NONE): {
171  return ComputeUTXOStats(view, stats, nullptr, interruption_point);
172  }
173  } // no default case, so the compiler can warn about missing cases
174  assert(false);
175  }();
176 
177  if (!success) {
178  return std::nullopt;
179  }
180  return stats;
181 }
182 
183 // The legacy hash serializes the hashBlock
184 static void PrepareHash(HashWriter& ss, const CCoinsStats& stats)
185 {
186  ss << stats.hashBlock;
187 }
188 // MuHash does not need the prepare step
189 static void PrepareHash(MuHash3072& muhash, CCoinsStats& stats) {}
190 static void PrepareHash(std::nullptr_t, CCoinsStats& stats) {}
191 
192 static void FinalizeHash(HashWriter& ss, CCoinsStats& stats)
193 {
194  stats.hashSerialized = ss.GetHash();
195 }
196 static void FinalizeHash(MuHash3072& muhash, CCoinsStats& stats)
197 {
198  uint256 out;
199  muhash.Finalize(out);
200  stats.hashSerialized = out;
201 }
202 static void FinalizeHash(std::nullptr_t, CCoinsStats& stats) {}
203 
204 } // namespace kernel
#define Assert(val)
Identity function.
Definition: check.h:73
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: chain.h:151
uint256 GetBlockHash() const
Definition: chain.h:259
Abstract view on the open txout dataset.
Definition: coins.h:157
virtual size_t EstimateSize() const
Estimate database size (0 if not implemented)
Definition: coins.h:188
virtual std::unique_ptr< CCoinsViewCursor > Cursor() const
Get a cursor to iterate over the whole state.
Definition: coins.cpp:17
virtual uint256 GetBestBlock() const
Retrieve the block hash whose state this CCoinsView currently represents.
Definition: coins.cpp:14
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:36
uint32_t n
Definition: transaction.h:39
uint256 hash
Definition: transaction.h:38
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:411
A UTXO entry.
Definition: coins.h:31
CTxOut out
unspent transaction output
Definition: coins.h:34
uint32_t nHeight
at which height this containing transaction was included in the active block chain
Definition: coins.h:40
unsigned int fCoinBase
whether containing transaction was a coinbase
Definition: coins.h:37
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:186
A writer stream (for serialization) that computes a 256-bit hash.
Definition: hash.h:102
uint256 GetHash()
Compute the double-SHA256 hash of all data written to this object.
Definition: hash.h:116
A class representing MuHash sets.
Definition: muhash.h:95
void Finalize(uint256 &out) noexcept
Definition: muhash.cpp:313
MuHash3072 & Insert(Span< const unsigned char > in) noexcept
Definition: muhash.cpp:338
Maintains a tree of blocks (stored in m_block_index) which is consulted to determine where the most-w...
Definition: blockstorage.h:81
CBlockIndex * LookupBlockIndex(const uint256 &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
size_type size() const
Definition: prevector.h:284
256-bit opaque blob.
Definition: uint256.h:119
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: cs_main.cpp:7
unsigned int nHeight
static void FinalizeHash(HashWriter &ss, CCoinsStats &stats)
Definition: coinstats.cpp:192
static void ApplyStats(CCoinsStats &stats, const uint256 &hash, const std::map< uint32_t, Coin > &outputs)
Definition: coinstats.cpp:101
static void ApplyHash(HashWriter &ss, const uint256 &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:72
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:25
DataStream TxOutSer(const COutPoint &outpoint, const Coin &coin)
Definition: coinstats.cpp:51
static void PrepareHash(HashWriter &ss, const CCoinsStats &stats)
Definition: coinstats.cpp:184
uint64_t GetBogoSize(const CScript &script_pub_key)
Definition: coinstats.cpp:41
std::optional< T > CheckedAdd(const T i, const T j) noexcept
Definition: overflow.h:24
#define VARINT(obj)
Definition: serialize.h:436
#define VARINT_MODE(obj, mode)
Definition: serialize.h:435
@ NONNEGATIVE_SIGNED
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:285
std::optional< CAmount > total_amount
The total amount, or nullopt if an overflow occurred calculating it.
Definition: coinstats.h:40
uint64_t nDiskSize
Definition: coinstats.h:38
uint64_t coins_count
The number of coins contained.
Definition: coinstats.h:43
uint64_t nTransactions
Definition: coinstats.h:34
uint64_t nTransactionOutputs
Definition: coinstats.h:35
uint64_t nBogoSize
Definition: coinstats.h:36
uint256 hashSerialized
Definition: coinstats.h:37
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:302
bool error(const char *fmt, const Args &... args)
Definition: system.h:48
assert(!tx.IsCoinBase())