Bitcoin Core  31.0.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>
12 #include <primitives/transaction.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 <map>
24 #include <memory>
25 #include <span>
26 #include <utility>
27 #include <version>
28 
29 namespace kernel {
30 
31 CCoinsStats::CCoinsStats(int block_height, const uint256& block_hash)
32  : nHeight(block_height),
33  hashBlock(block_hash) {}
34 
35 // Database-independent metric indicating the UTXO set size
36 uint64_t GetBogoSize(const CScript& script_pub_key)
37 {
38  return 32 /* txid */ +
39  4 /* vout index */ +
40  4 /* height + coinbase */ +
41  8 /* amount */ +
42  2 /* scriptPubKey len */ +
43  script_pub_key.size() /* scriptPubKey */;
44 }
45 
46 template <typename T>
47 static void TxOutSer(T& ss, const COutPoint& outpoint, const Coin& coin)
48 {
49  ss << outpoint;
50  ss << static_cast<uint32_t>((coin.nHeight << 1) + coin.fCoinBase);
51  ss << coin.out;
52 }
53 
54 static void ApplyCoinHash(HashWriter& ss, const COutPoint& outpoint, const Coin& coin)
55 {
56  TxOutSer(ss, outpoint, coin);
57 }
58 
59 void ApplyCoinHash(MuHash3072& muhash, const COutPoint& outpoint, const Coin& coin)
60 {
61  DataStream ss{};
62  TxOutSer(ss, outpoint, coin);
63  muhash.Insert(MakeUCharSpan(ss));
64 }
65 
66 void RemoveCoinHash(MuHash3072& muhash, const COutPoint& outpoint, const Coin& coin)
67 {
68  DataStream ss{};
69  TxOutSer(ss, outpoint, coin);
70  muhash.Remove(MakeUCharSpan(ss));
71 }
72 
73 static void ApplyCoinHash(std::nullptr_t, const COutPoint& outpoint, const Coin& coin) {}
74 
87 template <typename T>
88 static void ApplyHash(T& hash_obj, const Txid& hash, const std::map<uint32_t, Coin>& outputs)
89 {
90  for (auto it = outputs.begin(); it != outputs.end(); ++it) {
91  COutPoint outpoint = COutPoint(hash, it->first);
92  Coin coin = it->second;
93  ApplyCoinHash(hash_obj, outpoint, coin);
94  }
95 }
96 
97 static void ApplyStats(CCoinsStats& stats, const std::map<uint32_t, Coin>& outputs)
98 {
99  assert(!outputs.empty());
100  stats.nTransactions++;
101  for (auto it = outputs.begin(); it != outputs.end(); ++it) {
102  stats.nTransactionOutputs++;
103  if (stats.total_amount.has_value()) {
104  stats.total_amount = CheckedAdd(*stats.total_amount, it->second.out.nValue);
105  }
106  stats.nBogoSize += GetBogoSize(it->second.out.scriptPubKey);
107  }
108 }
109 
111 template <typename T>
112 static bool ComputeUTXOStats(CCoinsView* view, CCoinsStats& stats, T hash_obj, const std::function<void()>& interruption_point, std::unique_ptr<CCoinsViewCursor> pcursor)
113 {
114  assert(pcursor);
115 
116  Txid prevkey;
117  std::map<uint32_t, Coin> outputs;
118  while (pcursor->Valid()) {
119  if (interruption_point) interruption_point();
120  COutPoint key;
121  Coin coin;
122  if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
123  if (!outputs.empty() && key.hash != prevkey) {
124  ApplyStats(stats, outputs);
125  ApplyHash(hash_obj, prevkey, outputs);
126  outputs.clear();
127  }
128  prevkey = key.hash;
129  outputs[key.n] = std::move(coin);
130  stats.coins_count++;
131  } else {
132  LogError("%s: unable to read value\n", __func__);
133  return false;
134  }
135  pcursor->Next();
136  }
137  if (!outputs.empty()) {
138  ApplyStats(stats, outputs);
139  ApplyHash(hash_obj, prevkey, outputs);
140  }
141 
142  FinalizeHash(hash_obj, stats);
143 
144  stats.nDiskSize = view->EstimateSize();
145 
146  return true;
147 }
148 
149 std::optional<CCoinsStats> ComputeUTXOStats(CoinStatsHashType hash_type, CCoinsView* view, node::BlockManager& blockman, const std::function<void()>& interruption_point)
150 {
151  std::unique_ptr<CCoinsViewCursor> pcursor;
152  CBlockIndex* pindex;
153  {
154  LOCK(::cs_main);
155  pcursor = view->Cursor();
156  pindex = blockman.LookupBlockIndex(pcursor->GetBestBlock());
157  }
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, std::move(pcursor));
165  }
167  MuHash3072 muhash;
168  return ComputeUTXOStats(view, stats, muhash, interruption_point, std::move(pcursor));
169  }
170  case(CoinStatsHashType::NONE): {
171  return ComputeUTXOStats(view, stats, nullptr, interruption_point, std::move(pcursor));
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 static void FinalizeHash(HashWriter& ss, CCoinsStats& stats)
184 {
185  stats.hashSerialized = ss.GetHash();
186 }
187 static void FinalizeHash(MuHash3072& muhash, CCoinsStats& stats)
188 {
189  uint256 out;
190  muhash.Finalize(out);
191  stats.hashSerialized = out;
192 }
193 static void FinalizeHash(std::nullptr_t, CCoinsStats& stats) {}
194 
195 } // namespace kernel
uint256 GetHash()
Compute the double-SHA256 hash of all data written to this object.
Definition: hash.h:115
uint64_t nTransactions
Definition: coinstats.h:35
uint64_t GetBogoSize(const CScript &script_pub_key)
Definition: coinstats.cpp:36
constexpr auto MakeUCharSpan(const V &v) -> decltype(UCharSpanCast(std::span
Like the std::span constructor, but for (const) unsigned char member types only.
Definition: span.h:111
static void ApplyStats(CCoinsStats &stats, const std::map< uint32_t, Coin > &outputs)
Definition: coinstats.cpp:97
assert(!tx.IsCoinBase())
A UTXO entry.
Definition: coins.h:34
CTxOut out
unspent transaction output
Definition: coins.h:38
std::optional< CAmount > total_amount
The total amount, or nullopt if an overflow occurred calculating it.
Definition: coinstats.h:41
unsigned int fCoinBase
whether containing transaction was a coinbase
Definition: coins.h:41
uint64_t coins_count
The number of coins contained.
Definition: coinstats.h:44
void RemoveCoinHash(MuHash3072 &muhash, const COutPoint &outpoint, const Coin &coin)
Definition: coinstats.cpp:66
uint64_t nDiskSize
Definition: coinstats.h:39
CoinStatsHashType
Definition: coinstats.h:26
static void TxOutSer(T &ss, const COutPoint &outpoint, const Coin &coin)
Definition: coinstats.cpp:47
std::optional< T > CheckedAdd(const T i, const T j) noexcept
Definition: overflow.h:26
uint256 GetBlockHash() const
Definition: chain.h:198
uint32_t nHeight
at which height this containing transaction was included in the active block chain ...
Definition: coins.h:44
Abstract view on the open txout dataset.
Definition: coins.h:307
#define LOCK(cs)
Definition: sync.h:258
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:132
A writer stream (for serialization) that computes a 256-bit hash.
Definition: hash.h:100
Txid hash
Definition: transaction.h:31
uint32_t n
Definition: transaction.h:32
uint256 hashSerialized
Definition: coinstats.h:38
Maintains a tree of blocks (stored in m_block_index) which is consulted to determine where the most-w...
Definition: blockstorage.h:191
MuHash3072 & Insert(std::span< const unsigned char > in) noexcept
Definition: muhash.cpp:577
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:28
CBlockIndex * LookupBlockIndex(const uint256 &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
unsigned int nHeight
void Finalize(uint256 &out) noexcept
Definition: muhash.cpp:552
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:88
static void FinalizeHash(HashWriter &ss, CCoinsStats &stats)
Definition: coinstats.cpp:183
256-bit opaque blob.
Definition: uint256.h:195
virtual size_t EstimateSize() const
Estimate database size (0 if not implemented)
Definition: coins.h:342
The block chain is a tree shaped structure starting with the genesis block at the root...
Definition: chain.h:93
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:404
static bool ComputeUTXOStats(CCoinsView *view, CCoinsStats &stats, T hash_obj, const std::function< void()> &interruption_point, std::unique_ptr< CCoinsViewCursor > pcursor)
Calculate statistics about the unspent transaction output set.
Definition: coinstats.cpp:112
A class representing MuHash sets.
Definition: muhash.h:102
size_type size() const
Definition: prevector.h:247
virtual std::unique_ptr< CCoinsViewCursor > Cursor() const
Get a cursor to iterate over the whole state.
Definition: coins.cpp:26
MuHash3072 & Remove(std::span< const unsigned char > in) noexcept
Definition: muhash.cpp:582
uint64_t nBogoSize
Definition: coinstats.h:37
uint64_t nTransactionOutputs
Definition: coinstats.h:36
static void ApplyCoinHash(HashWriter &ss, const COutPoint &outpoint, const Coin &coin)
Definition: coinstats.cpp:54
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate...
Definition: cs_main.cpp:8
#define Assert(val)
Identity function.
Definition: check.h:113
#define LogError(...)
Definition: log.h:97