Bitcoin Core  22.99.0
P2P Digital Currency
coinstats.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2021 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include <node/coinstats.h>
7 
8 #include <coins.h>
9 #include <crypto/muhash.h>
10 #include <hash.h>
11 #include <index/coinstatsindex.h>
12 #include <serialize.h>
13 #include <uint256.h>
14 #include <util/overflow.h>
15 #include <util/system.h>
16 #include <validation.h>
17 
18 #include <map>
19 
20 namespace node {
21 // Database-independent metric indicating the UTXO set size
22 uint64_t GetBogoSize(const CScript& script_pub_key)
23 {
24  return 32 /* txid */ +
25  4 /* vout index */ +
26  4 /* height + coinbase */ +
27  8 /* amount */ +
28  2 /* scriptPubKey len */ +
29  script_pub_key.size() /* scriptPubKey */;
30 }
31 
32 CDataStream TxOutSer(const COutPoint& outpoint, const Coin& coin) {
34  ss << outpoint;
35  ss << static_cast<uint32_t>(coin.nHeight * 2 + coin.fCoinBase);
36  ss << coin.out;
37  return ss;
38 }
39 
52 static void ApplyHash(CHashWriter& ss, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
53 {
54  for (auto it = outputs.begin(); it != outputs.end(); ++it) {
55  if (it == outputs.begin()) {
56  ss << hash;
57  ss << VARINT(it->second.nHeight * 2 + it->second.fCoinBase ? 1u : 0u);
58  }
59 
60  ss << VARINT(it->first + 1);
61  ss << it->second.out.scriptPubKey;
62  ss << VARINT_MODE(it->second.out.nValue, VarIntMode::NONNEGATIVE_SIGNED);
63 
64  if (it == std::prev(outputs.end())) {
65  ss << VARINT(0u);
66  }
67  }
68 }
69 
70 static void ApplyHash(std::nullptr_t, const uint256& hash, const std::map<uint32_t, Coin>& outputs) {}
71 
72 static void ApplyHash(MuHash3072& muhash, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
73 {
74  for (auto it = outputs.begin(); it != outputs.end(); ++it) {
75  COutPoint outpoint = COutPoint(hash, it->first);
76  Coin coin = it->second;
77  muhash.Insert(MakeUCharSpan(TxOutSer(outpoint, coin)));
78  }
79 }
80 
81 static void ApplyStats(CCoinsStats& stats, const uint256& hash, const std::map<uint32_t, Coin>& outputs)
82 {
83  assert(!outputs.empty());
84  stats.nTransactions++;
85  for (auto it = outputs.begin(); it != outputs.end(); ++it) {
86  stats.nTransactionOutputs++;
87  if (stats.total_amount.has_value()) {
88  stats.total_amount = CheckedAdd(*stats.total_amount, it->second.out.nValue);
89  }
90  stats.nBogoSize += GetBogoSize(it->second.out.scriptPubKey);
91  }
92 }
93 
95 template <typename T>
96 static bool GetUTXOStats(CCoinsView* view, BlockManager& blockman, CCoinsStats& stats, T hash_obj, const std::function<void()>& interruption_point, const CBlockIndex* pindex)
97 {
98  std::unique_ptr<CCoinsViewCursor> pcursor(view->Cursor());
99  assert(pcursor);
100 
101  if (!pindex) {
102  LOCK(cs_main);
103  pindex = blockman.LookupBlockIndex(view->GetBestBlock());
104  }
105  stats.nHeight = Assert(pindex)->nHeight;
106  stats.hashBlock = pindex->GetBlockHash();
107 
108  // Use CoinStatsIndex if it is requested and available and a hash_type of Muhash or None was requested
110  stats.index_used = true;
111  return g_coin_stats_index->LookUpStats(pindex, stats);
112  }
113 
114  PrepareHash(hash_obj, stats);
115 
116  uint256 prevkey;
117  std::map<uint32_t, Coin> outputs;
118  while (pcursor->Valid()) {
119  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, prevkey, 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  return error("%s: unable to read value", __func__);
133  }
134  pcursor->Next();
135  }
136  if (!outputs.empty()) {
137  ApplyStats(stats, prevkey, outputs);
138  ApplyHash(hash_obj, prevkey, outputs);
139  }
140 
141  FinalizeHash(hash_obj, stats);
142 
143  stats.nDiskSize = view->EstimateSize();
144  return true;
145 }
146 
147 bool GetUTXOStats(CCoinsView* view, BlockManager& blockman, CCoinsStats& stats, const std::function<void()>& interruption_point, const CBlockIndex* pindex)
148 {
149  switch (stats.m_hash_type) {
152  return GetUTXOStats(view, blockman, stats, ss, interruption_point, pindex);
153  }
155  MuHash3072 muhash;
156  return GetUTXOStats(view, blockman, stats, muhash, interruption_point, pindex);
157  }
158  case(CoinStatsHashType::NONE): {
159  return GetUTXOStats(view, blockman, stats, nullptr, interruption_point, pindex);
160  }
161  } // no default case, so the compiler can warn about missing cases
162  assert(false);
163 }
164 
165 // The legacy hash serializes the hashBlock
166 static void PrepareHash(CHashWriter& ss, const CCoinsStats& stats)
167 {
168  ss << stats.hashBlock;
169 }
170 // MuHash does not need the prepare step
171 static void PrepareHash(MuHash3072& muhash, CCoinsStats& stats) {}
172 static void PrepareHash(std::nullptr_t, CCoinsStats& stats) {}
173 
174 static void FinalizeHash(CHashWriter& ss, CCoinsStats& stats)
175 {
176  stats.hashSerialized = ss.GetHash();
177 }
178 static void FinalizeHash(MuHash3072& muhash, CCoinsStats& stats)
179 {
180  uint256 out;
181  muhash.Finalize(out);
182  stats.hashSerialized = out;
183 }
184 static void FinalizeHash(std::nullptr_t, CCoinsStats& stats) {}
185 } // namespace node
node::GetUTXOStats
static bool GetUTXOStats(CCoinsView *view, BlockManager &blockman, CCoinsStats &stats, T hash_obj, const std::function< void()> &interruption_point, const CBlockIndex *pindex)
Calculate statistics about the unspent transaction output set.
Definition: coinstats.cpp:96
MakeUCharSpan
constexpr auto MakeUCharSpan(V &&v) -> decltype(UCharSpanCast(Span
Like the Span constructor, but for (const) unsigned char member types only.
Definition: span.h:280
assert
assert(!tx.IsCoinBase())
node::BlockManager::LookupBlockIndex
CBlockIndex * LookupBlockIndex(const uint256 &hash) const EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Definition: blockstorage.cpp:35
SER_DISK
@ SER_DISK
Definition: serialize.h:139
node::PrepareHash
static void PrepareHash(CHashWriter &ss, const CCoinsStats &stats)
Definition: coinstats.cpp:166
node::CCoinsStats
Definition: coinstats.h:30
node::CCoinsStats::hashSerialized
uint256 hashSerialized
Definition: coinstats.h:39
node::CCoinsStats::index_requested
bool index_requested
Signals if the coinstatsindex should be used (when available).
Definition: coinstats.h:48
node::CCoinsStats::nTransactionOutputs
uint64_t nTransactionOutputs
Definition: coinstats.h:37
COutPoint::hash
uint256 hash
Definition: transaction.h:29
VARINT_MODE
#define VARINT_MODE(obj, mode)
Definition: serialize.h:442
uint256.h
MuHash3072::Insert
MuHash3072 & Insert(Span< const unsigned char > in) noexcept
Definition: muhash.cpp:338
node::CoinStatsHashType::HASH_SERIALIZED
@ HASH_SERIALIZED
node::CCoinsStats::total_amount
std::optional< CAmount > total_amount
The total amount, or nullopt if an overflow occurred calculating it.
Definition: coinstats.h:42
node::CCoinsStats::nHeight
int nHeight
Definition: coinstats.h:34
VarIntMode::NONNEGATIVE_SIGNED
@ NONNEGATIVE_SIGNED
node::CoinStatsHashType::NONE
@ NONE
node::CCoinsStats::nBogoSize
uint64_t nBogoSize
Definition: coinstats.h:38
Coin::fCoinBase
unsigned int fCoinBase
whether containing transaction was a coinbase
Definition: coins.h:37
coinstatsindex.h
Assert
#define Assert(val)
Identity function.
Definition: check.h:57
node::CCoinsStats::coins_count
uint64_t coins_count
The number of coins contained.
Definition: coinstats.h:45
g_coin_stats_index
std::unique_ptr< CoinStatsIndex > g_coin_stats_index
The global UTXO set hash object.
Definition: coinstatsindex.cpp:100
node::TxOutSer
CDataStream TxOutSer(const COutPoint &outpoint, const Coin &coin)
Definition: coinstats.cpp:32
node::FinalizeHash
static void FinalizeHash(CHashWriter &ss, CCoinsStats &stats)
Definition: coinstats.cpp:174
CCoinsView
Abstract view on the open txout dataset.
Definition: coins.h:157
Coin::out
CTxOut out
unspent transaction output
Definition: coins.h:34
muhash.h
node::CCoinsStats::nDiskSize
uint64_t nDiskSize
Definition: coinstats.h:40
node::BlockManager
Maintains a tree of blocks (stored in m_block_index) which is consulted to determine where the most-w...
Definition: blockstorage.h:65
Coin
A UTXO entry.
Definition: coins.h:30
node::CCoinsStats::nTransactions
uint64_t nTransactions
Definition: coinstats.h:36
VARINT
#define VARINT(obj)
Definition: serialize.h:443
Coin::nHeight
uint32_t nHeight
at which height this containing transaction was included in the active block chain
Definition: coins.h:40
CheckedAdd
std::optional< T > CheckedAdd(const T i, const T j) noexcept
Definition: overflow.h:23
uint256
256-bit opaque blob.
Definition: uint256.h:124
MuHash3072::Finalize
void Finalize(uint256 &out) noexcept
Definition: muhash.cpp:313
CScript
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:405
CBlockIndex::GetBlockHash
uint256 GetBlockHash() const
Definition: chain.h:259
CCoinsView::EstimateSize
virtual size_t EstimateSize() const
Estimate database size (0 if not implemented)
Definition: coins.h:189
coins.h
CCoinsView::Cursor
virtual std::unique_ptr< CCoinsViewCursor > Cursor() const
Get a cursor to iterate over the whole state.
Definition: coins.cpp:17
coinstats.h
system.h
cs_main
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: validation.cpp:138
COutPoint::n
uint32_t n
Definition: transaction.h:30
LOCK
#define LOCK(cs)
Definition: sync.h:226
node::CCoinsStats::m_hash_type
const CoinStatsHashType m_hash_type
Which hash type to use.
Definition: coinstats.h:32
node::CoinStatsHashType::MUHASH
@ MUHASH
CHashWriter
A writer stream (for serialization) that computes a 256-bit hash.
Definition: hash.h:100
prevector::size
size_type size() const
Definition: prevector.h:282
node::GetBogoSize
uint64_t GetBogoSize(const CScript &script_pub_key)
Definition: coinstats.cpp:22
node::CCoinsStats::hashBlock
uint256 hashBlock
Definition: coinstats.h:35
node
Definition: init.h:22
serialize.h
CDataStream
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:184
COutPoint
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:26
error
bool error(const char *fmt, const Args &... args)
Definition: system.h:49
node::ApplyHash
static void ApplyHash(CHashWriter &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:52
CHashWriter::GetHash
uint256 GetHash()
Compute the double-SHA256 hash of all data written to this object.
Definition: hash.h:122
node::ApplyStats
static void ApplyStats(CCoinsStats &stats, const uint256 &hash, const std::map< uint32_t, Coin > &outputs)
Definition: coinstats.cpp:81
CBlockIndex
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: chain.h:148
CCoinsView::GetBestBlock
virtual uint256 GetBestBlock() const
Retrieve the block hash whose state this CCoinsView currently represents.
Definition: coins.cpp:14
node::CCoinsStats::index_used
bool index_used
Signals if the coinstatsindex was used to retrieve the statistics.
Definition: coinstats.h:50
overflow.h
SER_GETHASH
@ SER_GETHASH
Definition: serialize.h:140
MuHash3072
A class representing MuHash sets.
Definition: muhash.h:94
PROTOCOL_VERSION
static const int PROTOCOL_VERSION
network protocol versioning
Definition: version.h:12