Bitcoin ABC 0.32.5
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 <coins.h>
8#include <crypto/muhash.h>
9#include <hash.h>
10#include <logging.h>
11#include <primitives/txid.h>
12#include <serialize.h>
13#include <util/check.h>
14#include <validation.h>
15
16#include <map>
17
18namespace kernel {
19CCoinsStats::CCoinsStats(int block_height, const BlockHash &block_hash)
20 : nHeight(block_height), hashBlock(block_hash) {}
21
22uint64_t GetBogoSize(const CScript &script_pub_key) {
23 return 32 /* txid */ + 4 /* vout index */ + 4 /* height + coinbase */ +
24 8 /* amount */ + 2 /* scriptPubKey len */ +
25 script_pub_key.size() /* scriptPubKey */;
26}
27
28DataStream TxOutSer(const COutPoint &outpoint, const Coin &coin) {
29 DataStream ss{};
30 ss << outpoint;
31 ss << static_cast<uint32_t>(coin.GetHeight() * 2 + coin.IsCoinBase());
32 ss << coin.GetTxOut();
33 return ss;
34}
35
48static void ApplyHash(HashWriter &ss, const TxId &txid,
49 const std::map<uint32_t, Coin> &outputs) {
50 for (auto it = outputs.begin(); it != outputs.end(); ++it) {
51 if (it == outputs.begin()) {
52 ss << txid;
53 ss << VARINT(it->second.GetHeight() * 2 + it->second.IsCoinBase());
54 }
55
56 ss << VARINT(it->first + 1);
57 ss << it->second.GetTxOut().scriptPubKey;
58 ss << VARINT_MODE(it->second.GetTxOut().nValue / SATOSHI,
60
61 if (it == std::prev(outputs.end())) {
62 ss << VARINT(0u);
63 }
64 }
65}
66
67static void ApplyHash(std::nullptr_t, const TxId &txid,
68 const std::map<uint32_t, Coin> &outputs) {}
69
70static void ApplyHash(MuHash3072 &muhash, const TxId &txid,
71 const std::map<uint32_t, Coin> &outputs) {
72 for (auto it = outputs.begin(); it != outputs.end(); ++it) {
73 COutPoint outpoint = COutPoint(txid, it->first);
74 Coin coin = it->second;
75 muhash.Insert(MakeUCharSpan(TxOutSer(outpoint, coin)));
76 }
77}
78
79static void ApplyStats(CCoinsStats &stats, const TxId &txid,
80 const std::map<uint32_t, Coin> &outputs) {
81 assert(!outputs.empty());
82 stats.nTransactions++;
83 for (auto it = outputs.begin(); it != outputs.end(); ++it) {
84 stats.nTransactionOutputs++;
85 if (stats.total_amount.has_value()) {
86 stats.total_amount =
87 (*stats.total_amount).CheckedAdd(it->second.GetTxOut().nValue);
88 }
89 stats.nBogoSize += GetBogoSize(it->second.GetTxOut().scriptPubKey);
90 }
91}
92
94template <typename T>
95static bool ComputeUTXOStats(CCoinsView *view, CCoinsStats &stats, T hash_obj,
96 const std::function<void()> &interruption_point) {
97 std::unique_ptr<CCoinsViewCursor> pcursor(view->Cursor());
98 assert(pcursor);
99
100 PrepareHash(hash_obj, stats);
101
102 TxId prevkey;
103 std::map<uint32_t, Coin> outputs;
104 while (pcursor->Valid()) {
105 interruption_point();
106 COutPoint key;
107 Coin coin;
108 if (pcursor->GetKey(key) && pcursor->GetValue(coin)) {
109 if (!outputs.empty() && key.GetTxId() != prevkey) {
110 ApplyStats(stats, prevkey, outputs);
111 ApplyHash(hash_obj, prevkey, outputs);
112 outputs.clear();
113 }
114 prevkey = key.GetTxId();
115 outputs[key.GetN()] = std::move(coin);
116 stats.coins_count++;
117 } else {
118 LogError("%s: unable to read value\n", __func__);
119 return false;
120 }
121 pcursor->Next();
122 }
123 if (!outputs.empty()) {
124 ApplyStats(stats, prevkey, outputs);
125 ApplyHash(hash_obj, prevkey, outputs);
126 }
127
128 FinalizeHash(hash_obj, stats);
129
130 stats.nDiskSize = view->EstimateSize();
131
132 return true;
133}
134
135std::optional<CCoinsStats>
137 node::BlockManager &blockman,
138 const std::function<void()> &interruption_point) {
139 CBlockIndex *pindex = WITH_LOCK(
140 ::cs_main, return blockman.LookupBlockIndex(view->GetBestBlock()));
141 CCoinsStats stats{Assert(pindex)->nHeight, pindex->GetBlockHash()};
142
143 bool success = [&]() -> bool {
144 switch (hash_type) {
146 HashWriter ss{};
147 return ComputeUTXOStats(view, stats, ss, interruption_point);
148 }
150 MuHash3072 muhash;
151 return ComputeUTXOStats(view, stats, muhash,
152 interruption_point);
153 }
155 return ComputeUTXOStats(view, stats, nullptr,
156 interruption_point);
157 }
158 } // no default case, so the compiler can warn about missing cases
159 assert(false);
160 }();
161
162 if (!success) {
163 return std::nullopt;
164 }
165 return stats;
166}
167
168// The legacy hash serializes the hashBlock
169static void PrepareHash(HashWriter &ss, const CCoinsStats &stats) {
170 ss << stats.hashBlock;
171}
172// MuHash does not need the prepare step
173static void PrepareHash(MuHash3072 &muhash, CCoinsStats &stats) {}
174static void PrepareHash(std::nullptr_t, CCoinsStats &stats) {}
175
176static void FinalizeHash(HashWriter &ss, CCoinsStats &stats) {
177 stats.hashSerialized = ss.GetHash();
178}
179static void FinalizeHash(MuHash3072 &muhash, CCoinsStats &stats) {
180 uint256 out;
181 muhash.Finalize(out);
182 stats.hashSerialized = out;
183}
184static void FinalizeHash(std::nullptr_t, CCoinsStats &stats) {}
185
186} // namespace kernel
static constexpr Amount SATOSHI
Definition: amount.h:148
#define Assert(val)
Identity function.
Definition: check.h:84
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: blockindex.h:25
BlockHash GetBlockHash() const
Definition: blockindex.h:130
Abstract view on the open txout dataset.
Definition: coins.h:305
virtual CCoinsViewCursor * Cursor() const
Get a cursor to iterate over the whole state.
Definition: coins.cpp:26
virtual BlockHash GetBestBlock() const
Retrieve the block hash whose state this CCoinsView currently represents.
Definition: coins.cpp:16
virtual size_t EstimateSize() const
Estimate database size (0 if not implemented)
Definition: coins.h:339
A UTXO entry.
Definition: coins.h:29
uint32_t GetHeight() const
Definition: coins.h:46
bool IsCoinBase() const
Definition: coins.h:47
CTxOut & GetTxOut()
Definition: coins.h:50
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:174
A writer stream (for serialization) that computes a 256-bit hash.
Definition: hash.h:100
uint256 GetHash()
Compute the double-SHA256 hash of all data written to this object.
Definition: hash.h:114
A class representing MuHash sets.
Definition: muhash.h:107
void Finalize(uint256 &out) noexcept
Definition: muhash.cpp:683
MuHash3072 & Insert(Span< const uint8_t > in) noexcept
Definition: muhash.cpp:706
Maintains a tree of blocks (stored in m_block_index) which is consulted to determine where the most-w...
Definition: blockstorage.h:107
CBlockIndex * LookupBlockIndex(const BlockHash &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
256-bit opaque blob.
Definition: uint256.h:129
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: cs_main.cpp:7
#define LogError(...)
Definition: logging.h:419
unsigned int nHeight
Definition: init.h:28
static void FinalizeHash(HashWriter &ss, CCoinsStats &stats)
Definition: coinstats.cpp:176
static void ApplyStats(CCoinsStats &stats, const TxId &txid, const std::map< uint32_t, Coin > &outputs)
Definition: coinstats.cpp:79
static void ApplyHash(HashWriter &ss, const TxId &txid, const std::map< uint32_t, Coin > &outputs)
Warning: be very careful when changing this! assumeutxo and UTXO snapshot validation commitments are ...
Definition: coinstats.cpp:48
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:95
CoinStatsHashType
Definition: coinstats.h:24
DataStream TxOutSer(const COutPoint &outpoint, const Coin &coin)
Definition: coinstats.cpp:28
static void PrepareHash(HashWriter &ss, const CCoinsStats &stats)
Definition: coinstats.cpp:169
uint64_t GetBogoSize(const CScript &script_pub_key)
Definition: coinstats.cpp:22
std::optional< T > CheckedAdd(const T i, const T j) noexcept
Definition: overflow.h:24
#define VARINT(obj)
Definition: serialize.h:643
#define VARINT_MODE(obj, mode)
Definition: serialize.h:642
@ NONNEGATIVE_SIGNED
constexpr auto MakeUCharSpan(V &&v) -> decltype(UCharSpanCast(Span{std::forward< V >(v)}))
Like the Span constructor, but for (const) uint8_t member types only.
Definition: span.h:350
A BlockHash is a unqiue identifier for a block.
Definition: blockhash.h:13
A TxId is the identifier of a transaction.
Definition: txid.h:14
uint64_t nDiskSize
Definition: coinstats.h:37
uint64_t coins_count
The number of coins contained.
Definition: coinstats.h:42
uint64_t nTransactions
Definition: coinstats.h:33
uint64_t nTransactionOutputs
Definition: coinstats.h:34
uint64_t nBogoSize
Definition: coinstats.h:35
BlockHash hashBlock
Definition: coinstats.h:32
uint256 hashSerialized
Definition: coinstats.h:36
std::optional< Amount > total_amount
The total amount, or nullopt if an overflow occurred calculating it.
Definition: coinstats.h:39
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:357
assert(!tx.IsCoinBase())