Bitcoin ABC  0.26.3
P2P Digital Currency
coinstats.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2019 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 <primitives/txid.h>
13 #include <serialize.h>
14 #include <util/check.h>
15 #include <util/system.h>
16 #include <validation.h>
17 
18 #include <map>
19 
20 namespace node {
21 uint64_t GetBogoSize(const CScript &script_pub_key) {
22  return 32 /* txid */ + 4 /* vout index */ + 4 /* height + coinbase */ +
23  8 /* amount */ + 2 /* scriptPubKey len */ +
24  script_pub_key.size() /* scriptPubKey */;
25 }
26 
27 CDataStream TxOutSer(const COutPoint &outpoint, const Coin &coin) {
29  ss << outpoint;
30  ss << static_cast<uint32_t>(coin.GetHeight() * 2 + coin.IsCoinBase());
31  ss << coin.GetTxOut();
32  return ss;
33 }
34 
47 static void ApplyHash(CHashWriter &ss, const TxId &txid,
48  const std::map<uint32_t, Coin> &outputs) {
49  for (auto it = outputs.begin(); it != outputs.end(); ++it) {
50  if (it == outputs.begin()) {
51  ss << txid;
52  ss << VARINT(it->second.GetHeight() * 2 + it->second.IsCoinBase());
53  }
54 
55  ss << VARINT(it->first + 1);
56  ss << it->second.GetTxOut().scriptPubKey;
57  ss << VARINT_MODE(it->second.GetTxOut().nValue / SATOSHI,
59 
60  if (it == std::prev(outputs.end())) {
61  ss << VARINT(0u);
62  }
63  }
64 }
65 
66 static void ApplyHash(std::nullptr_t, const TxId &txid,
67  const std::map<uint32_t, Coin> &outputs) {}
68 
69 static void ApplyHash(MuHash3072 &muhash, const TxId &txid,
70  const std::map<uint32_t, Coin> &outputs) {
71  for (auto it = outputs.begin(); it != outputs.end(); ++it) {
72  COutPoint outpoint = COutPoint(txid, it->first);
73  Coin coin = it->second;
74  muhash.Insert(MakeUCharSpan(TxOutSer(outpoint, coin)));
75  }
76 }
77 
78 static void ApplyStats(CCoinsStats &stats, const TxId &txid,
79  const std::map<uint32_t, Coin> &outputs) {
80  assert(!outputs.empty());
81  stats.nTransactions++;
82  for (auto it = outputs.begin(); it != outputs.end(); ++it) {
83  stats.nTransactionOutputs++;
84  stats.nTotalAmount += it->second.GetTxOut().nValue;
85  stats.nBogoSize += GetBogoSize(it->second.GetTxOut().scriptPubKey);
86  }
87 }
88 
90 template <typename T>
91 static bool GetUTXOStats(CCoinsView *view, BlockManager &blockman,
92  CCoinsStats &stats, T hash_obj,
93  const std::function<void()> &interruption_point,
94  const CBlockIndex *pindex) {
95  std::unique_ptr<CCoinsViewCursor> pcursor(view->Cursor());
96  assert(pcursor);
97 
98  if (!pindex) {
99  LOCK(cs_main);
100  pindex = blockman.LookupBlockIndex(view->GetBestBlock());
101  }
102  stats.nHeight = Assert(pindex)->nHeight;
103  stats.hashBlock = pindex->GetBlockHash();
104 
105  // Use CoinStatsIndex if it is requested and available and a hash_type of
106  // Muhash or None was requested
107  if ((stats.m_hash_type == CoinStatsHashType::MUHASH ||
110  stats.index_used = true;
111  return g_coin_stats_index->LookUpStats(pindex, stats);
112  }
113 
114  PrepareHash(hash_obj, stats);
115 
116  TxId 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.GetTxId() != prevkey) {
124  ApplyStats(stats, prevkey, outputs);
125  ApplyHash(hash_obj, prevkey, outputs);
126  outputs.clear();
127  }
128  prevkey = key.GetTxId();
129  outputs[key.GetN()] = 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,
148  const std::function<void()> &interruption_point,
149  const CBlockIndex *pindex) {
150  switch (stats.m_hash_type) {
153  return GetUTXOStats(view, blockman, stats, ss, interruption_point,
154  pindex);
155  }
156  case (CoinStatsHashType::MUHASH): {
157  MuHash3072 muhash;
158  return GetUTXOStats(view, blockman, stats, muhash,
159  interruption_point, pindex);
160  }
161  case (CoinStatsHashType::NONE): {
162  return GetUTXOStats(view, blockman, stats, nullptr,
163  interruption_point, pindex);
164  }
165  } // no default case, so the compiler can warn about missing cases
166  assert(false);
167 }
168 
169 // The legacy hash serializes the hashBlock
170 static void PrepareHash(CHashWriter &ss, const CCoinsStats &stats) {
171  ss << stats.hashBlock;
172 }
173 // MuHash does not need the prepare step
174 static void PrepareHash(MuHash3072 &muhash, CCoinsStats &stats) {}
175 static void PrepareHash(std::nullptr_t, CCoinsStats &stats) {}
176 
177 static void FinalizeHash(CHashWriter &ss, CCoinsStats &stats) {
178  stats.hashSerialized = ss.GetHash();
179 }
180 static void FinalizeHash(MuHash3072 &muhash, CCoinsStats &stats) {
181  uint256 out;
182  muhash.Finalize(out);
183  stats.hashSerialized = out;
184 }
185 static void FinalizeHash(std::nullptr_t, CCoinsStats &stats) {}
186 } // namespace node
static constexpr Amount SATOSHI
Definition: amount.h:153
RecursiveMutex cs_main
Global state.
Definition: validation.cpp:112
#define Assert(val)
Identity function.
Definition: check.h:56
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: blockindex.h:23
BlockHash GetBlockHash() const
Definition: blockindex.h:142
Abstract view on the open txout dataset.
Definition: coins.h:147
virtual CCoinsViewCursor * Cursor() const
Get a cursor to iterate over the whole state.
Definition: coins.cpp:25
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:180
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:197
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:123
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:22
uint32_t GetN() const
Definition: transaction.h:38
const TxId & GetTxId() const
Definition: transaction.h:37
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:431
A UTXO entry.
Definition: coins.h:27
uint32_t GetHeight() const
Definition: coins.h:44
bool IsCoinBase() const
Definition: coins.h:45
CTxOut & GetTxOut()
Definition: coins.h:48
A class representing MuHash sets.
Definition: muhash.h:96
void Finalize(uint256 &out) noexcept
Definition: muhash.cpp:353
MuHash3072 & Insert(Span< const uint8_t > in) noexcept
Definition: muhash.cpp:376
Maintains a tree of blocks (stored in m_block_index) which is consulted to determine where the most-w...
Definition: blockstorage.h:62
CBlockIndex * LookupBlockIndex(const BlockHash &hash) const EXCLUSIVE_LOCKS_REQUIRED(cs_main)
size_type size() const
Definition: prevector.h:386
256-bit opaque blob.
Definition: uint256.h:127
std::unique_ptr< CoinStatsIndex > g_coin_stats_index
The global UTXO set hash object.
Definition: init.h:28
static void FinalizeHash(CHashWriter &ss, CCoinsStats &stats)
Definition: coinstats.cpp:177
static void ApplyHash(CHashWriter &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:47
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:91
CDataStream TxOutSer(const COutPoint &outpoint, const Coin &coin)
Definition: coinstats.cpp:27
uint64_t GetBogoSize(const CScript &script_pub_key)
Definition: coinstats.cpp:21
static void PrepareHash(CHashWriter &ss, const CCoinsStats &stats)
Definition: coinstats.cpp:170
static void ApplyStats(CCoinsStats &stats, const TxId &txid, const std::map< uint32_t, Coin > &outputs)
Definition: coinstats.cpp:78
#define VARINT(obj)
Definition: serialize.h:597
#define VARINT_MODE(obj, mode)
Definition: serialize.h:596
@ NONNEGATIVE_SIGNED
@ SER_DISK
Definition: serialize.h:167
@ SER_GETHASH
Definition: serialize.h:168
constexpr auto MakeUCharSpan(V &&v) -> decltype(UCharSpanCast(MakeSpan(std::forward< V >(v))))
Like MakeSpan, but for (const) uint8_t member types only.
Definition: span.h:311
A TxId is the identifier of a transaction.
Definition: txid.h:14
Amount nTotalAmount
Definition: coinstats.h:40
uint64_t nBogoSize
Definition: coinstats.h:37
uint64_t nDiskSize
Definition: coinstats.h:39
CoinStatsHashType m_hash_type
Definition: coinstats.h:32
bool index_used
Signals if the coinstatsindex was used to retrieve the statistics.
Definition: coinstats.h:48
BlockHash hashBlock
Definition: coinstats.h:34
uint64_t nTransactions
Definition: coinstats.h:35
uint64_t nTransactionOutputs
Definition: coinstats.h:36
bool index_requested
Signals if the coinstatsindex should be used (when available).
Definition: coinstats.h:46
uint256 hashSerialized
Definition: coinstats.h:38
uint64_t coins_count
The number of coins contained.
Definition: coinstats.h:43
#define LOCK(cs)
Definition: sync.h:243
bool error(const char *fmt, const Args &...args)
Definition: system.h:46
assert(!tx.IsCoinBase())
static const int PROTOCOL_VERSION
network protocol versioning
Definition: version.h:11