Bitcoin Core 22.99.0
P2P Digital Currency
coinstatsindex.cpp
Go to the documentation of this file.
1// Copyright (c) 2020-2021 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 <chainparams.h>
6#include <coins.h>
7#include <crypto/muhash.h>
9#include <node/blockstorage.h>
10#include <serialize.h>
11#include <txdb.h>
12#include <undo.h>
13#include <validation.h>
14
15static constexpr uint8_t DB_BLOCK_HASH{'s'};
16static constexpr uint8_t DB_BLOCK_HEIGHT{'t'};
17static constexpr uint8_t DB_MUHASH{'M'};
18
19namespace {
20
21struct DBVal {
22 uint256 muhash;
23 uint64_t transaction_output_count;
24 uint64_t bogo_size;
25 CAmount total_amount;
26 CAmount total_subsidy;
27 CAmount total_unspendable_amount;
28 CAmount total_prevout_spent_amount;
29 CAmount total_new_outputs_ex_coinbase_amount;
30 CAmount total_coinbase_amount;
31 CAmount total_unspendables_genesis_block;
32 CAmount total_unspendables_bip30;
33 CAmount total_unspendables_scripts;
34 CAmount total_unspendables_unclaimed_rewards;
35
36 SERIALIZE_METHODS(DBVal, obj)
37 {
38 READWRITE(obj.muhash);
39 READWRITE(obj.transaction_output_count);
40 READWRITE(obj.bogo_size);
41 READWRITE(obj.total_amount);
42 READWRITE(obj.total_subsidy);
43 READWRITE(obj.total_unspendable_amount);
44 READWRITE(obj.total_prevout_spent_amount);
45 READWRITE(obj.total_new_outputs_ex_coinbase_amount);
46 READWRITE(obj.total_coinbase_amount);
47 READWRITE(obj.total_unspendables_genesis_block);
48 READWRITE(obj.total_unspendables_bip30);
49 READWRITE(obj.total_unspendables_scripts);
50 READWRITE(obj.total_unspendables_unclaimed_rewards);
51 }
52};
53
54struct DBHeightKey {
55 int height;
56
57 explicit DBHeightKey(int height_in) : height(height_in) {}
58
59 template <typename Stream>
60 void Serialize(Stream& s) const
61 {
63 ser_writedata32be(s, height);
64 }
65
66 template <typename Stream>
67 void Unserialize(Stream& s)
68 {
69 const uint8_t prefix{ser_readdata8(s)};
70 if (prefix != DB_BLOCK_HEIGHT) {
71 throw std::ios_base::failure("Invalid format for coinstatsindex DB height key");
72 }
73 height = ser_readdata32be(s);
74 }
75};
76
77struct DBHashKey {
78 uint256 block_hash;
79
80 explicit DBHashKey(const uint256& hash_in) : block_hash(hash_in) {}
81
82 SERIALIZE_METHODS(DBHashKey, obj)
83 {
84 uint8_t prefix{DB_BLOCK_HASH};
86 if (prefix != DB_BLOCK_HASH) {
87 throw std::ios_base::failure("Invalid format for coinstatsindex DB hash key");
88 }
89
90 READWRITE(obj.block_hash);
91 }
92};
93
94}; // namespace
95
96std::unique_ptr<CoinStatsIndex> g_coin_stats_index;
97
98CoinStatsIndex::CoinStatsIndex(size_t n_cache_size, bool f_memory, bool f_wipe)
99{
100 fs::path path{gArgs.GetDataDirNet() / "indexes" / "coinstats"};
101 fs::create_directories(path);
102
103 m_db = std::make_unique<CoinStatsIndex::DB>(path / "db", n_cache_size, f_memory, f_wipe);
104}
105
106bool CoinStatsIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
107{
108 CBlockUndo block_undo;
109 const CAmount block_subsidy{GetBlockSubsidy(pindex->nHeight, Params().GetConsensus())};
110 m_total_subsidy += block_subsidy;
111
112 // Ignore genesis block
113 if (pindex->nHeight > 0) {
114 if (!UndoReadFromDisk(block_undo, pindex)) {
115 return false;
116 }
117
118 std::pair<uint256, DBVal> read_out;
119 if (!m_db->Read(DBHeightKey(pindex->nHeight - 1), read_out)) {
120 return false;
121 }
122
123 uint256 expected_block_hash{pindex->pprev->GetBlockHash()};
124 if (read_out.first != expected_block_hash) {
125 LogPrintf("WARNING: previous block header belongs to unexpected block %s; expected %s\n",
126 read_out.first.ToString(), expected_block_hash.ToString());
127
128 if (!m_db->Read(DBHashKey(expected_block_hash), read_out)) {
129 return error("%s: previous block header not found; expected %s",
130 __func__, expected_block_hash.ToString());
131 }
132 }
133
134 // TODO: Deduplicate BIP30 related code
135 bool is_bip30_block{(pindex->nHeight == 91722 && pindex->GetBlockHash() == uint256S("0x00000000000271a2dc26e7667f8419f2e15416dc6955e5a6c6cdf3f2574dd08e")) ||
136 (pindex->nHeight == 91812 && pindex->GetBlockHash() == uint256S("0x00000000000af0aed4792b1acee3d966af36cf5def14935db8de83d6f9306f2f"))};
137
138 // Add the new utxos created from the block
139 for (size_t i = 0; i < block.vtx.size(); ++i) {
140 const auto& tx{block.vtx.at(i)};
141
142 // Skip duplicate txid coinbase transactions (BIP30).
143 if (is_bip30_block && tx->IsCoinBase()) {
144 m_total_unspendable_amount += block_subsidy;
145 m_total_unspendables_bip30 += block_subsidy;
146 continue;
147 }
148
149 for (uint32_t j = 0; j < tx->vout.size(); ++j) {
150 const CTxOut& out{tx->vout[j]};
151 Coin coin{out, pindex->nHeight, tx->IsCoinBase()};
152 COutPoint outpoint{tx->GetHash(), j};
153
154 // Skip unspendable coins
155 if (coin.out.scriptPubKey.IsUnspendable()) {
156 m_total_unspendable_amount += coin.out.nValue;
157 m_total_unspendables_scripts += coin.out.nValue;
158 continue;
159 }
160
161 m_muhash.Insert(MakeUCharSpan(TxOutSer(outpoint, coin)));
162
163 if (tx->IsCoinBase()) {
164 m_total_coinbase_amount += coin.out.nValue;
165 } else {
167 }
168
170 m_total_amount += coin.out.nValue;
171 m_bogo_size += GetBogoSize(coin.out.scriptPubKey);
172 }
173
174 // The coinbase tx has no undo data since no former output is spent
175 if (!tx->IsCoinBase()) {
176 const auto& tx_undo{block_undo.vtxundo.at(i - 1)};
177
178 for (size_t j = 0; j < tx_undo.vprevout.size(); ++j) {
179 Coin coin{tx_undo.vprevout[j]};
180 COutPoint outpoint{tx->vin[j].prevout.hash, tx->vin[j].prevout.n};
181
182 m_muhash.Remove(MakeUCharSpan(TxOutSer(outpoint, coin)));
183
184 m_total_prevout_spent_amount += coin.out.nValue;
185
187 m_total_amount -= coin.out.nValue;
188 m_bogo_size -= GetBogoSize(coin.out.scriptPubKey);
189 }
190 }
191 }
192 } else {
193 // genesis block
194 m_total_unspendable_amount += block_subsidy;
195 m_total_unspendables_genesis_block += block_subsidy;
196 }
197
198 // If spent prevouts + block subsidy are still a higher amount than
199 // new outputs + coinbase + current unspendable amount this means
200 // the miner did not claim the full block reward. Unclaimed block
201 // rewards are also unspendable.
203 m_total_unspendable_amount += unclaimed_rewards;
204 m_total_unspendables_unclaimed_rewards += unclaimed_rewards;
205
206 std::pair<uint256, DBVal> value;
207 value.first = pindex->GetBlockHash();
208 value.second.transaction_output_count = m_transaction_output_count;
209 value.second.bogo_size = m_bogo_size;
210 value.second.total_amount = m_total_amount;
211 value.second.total_subsidy = m_total_subsidy;
212 value.second.total_unspendable_amount = m_total_unspendable_amount;
213 value.second.total_prevout_spent_amount = m_total_prevout_spent_amount;
214 value.second.total_new_outputs_ex_coinbase_amount = m_total_new_outputs_ex_coinbase_amount;
215 value.second.total_coinbase_amount = m_total_coinbase_amount;
216 value.second.total_unspendables_genesis_block = m_total_unspendables_genesis_block;
217 value.second.total_unspendables_bip30 = m_total_unspendables_bip30;
218 value.second.total_unspendables_scripts = m_total_unspendables_scripts;
219 value.second.total_unspendables_unclaimed_rewards = m_total_unspendables_unclaimed_rewards;
220
221 uint256 out;
222 m_muhash.Finalize(out);
223 value.second.muhash = out;
224
225 CDBBatch batch(*m_db);
226 batch.Write(DBHeightKey(pindex->nHeight), value);
227 batch.Write(DB_MUHASH, m_muhash);
228 return m_db->WriteBatch(batch);
229}
230
232 const std::string& index_name,
233 int start_height, int stop_height)
234{
235 DBHeightKey key{start_height};
236 db_it.Seek(key);
237
238 for (int height = start_height; height <= stop_height; ++height) {
239 if (!db_it.GetKey(key) || key.height != height) {
240 return error("%s: unexpected key in %s: expected (%c, %d)",
241 __func__, index_name, DB_BLOCK_HEIGHT, height);
242 }
243
244 std::pair<uint256, DBVal> value;
245 if (!db_it.GetValue(value)) {
246 return error("%s: unable to read value in %s at key (%c, %d)",
247 __func__, index_name, DB_BLOCK_HEIGHT, height);
248 }
249
250 batch.Write(DBHashKey(value.first), std::move(value.second));
251
252 db_it.Next();
253 }
254 return true;
255}
256
257bool CoinStatsIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip)
258{
259 assert(current_tip->GetAncestor(new_tip->nHeight) == new_tip);
260
261 CDBBatch batch(*m_db);
262 std::unique_ptr<CDBIterator> db_it(m_db->NewIterator());
263
264 // During a reorg, we need to copy all hash digests for blocks that are
265 // getting disconnected from the height index to the hash index so we can
266 // still find them when the height index entries are overwritten.
267 if (!CopyHeightIndexToHashIndex(*db_it, batch, m_name, new_tip->nHeight, current_tip->nHeight)) {
268 return false;
269 }
270
271 if (!m_db->WriteBatch(batch)) return false;
272
273 {
274 LOCK(cs_main);
276 const auto& consensus_params{Params().GetConsensus()};
277
278 do {
279 CBlock block;
280
281 if (!ReadBlockFromDisk(block, iter_tip, consensus_params)) {
282 return error("%s: Failed to read block %s from disk",
283 __func__, iter_tip->GetBlockHash().ToString());
284 }
285
286 ReverseBlock(block, iter_tip);
287
288 iter_tip = iter_tip->GetAncestor(iter_tip->nHeight - 1);
289 } while (new_tip != iter_tip);
290 }
291
292 return BaseIndex::Rewind(current_tip, new_tip);
293}
294
295static bool LookUpOne(const CDBWrapper& db, const CBlockIndex* block_index, DBVal& result)
296{
297 // First check if the result is stored under the height index and the value
298 // there matches the block hash. This should be the case if the block is on
299 // the active chain.
300 std::pair<uint256, DBVal> read_out;
301 if (!db.Read(DBHeightKey(block_index->nHeight), read_out)) {
302 return false;
303 }
304 if (read_out.first == block_index->GetBlockHash()) {
305 result = std::move(read_out.second);
306 return true;
307 }
308
309 // If value at the height index corresponds to an different block, the
310 // result will be stored in the hash index.
311 return db.Read(DBHashKey(block_index->GetBlockHash()), result);
312}
313
314bool CoinStatsIndex::LookUpStats(const CBlockIndex* block_index, CCoinsStats& coins_stats) const
315{
316 DBVal entry;
317 if (!LookUpOne(*m_db, block_index, entry)) {
318 return false;
319 }
320
321 coins_stats.hashSerialized = entry.muhash;
322 coins_stats.nTransactionOutputs = entry.transaction_output_count;
323 coins_stats.nBogoSize = entry.bogo_size;
324 coins_stats.nTotalAmount = entry.total_amount;
325 coins_stats.total_subsidy = entry.total_subsidy;
326 coins_stats.total_unspendable_amount = entry.total_unspendable_amount;
327 coins_stats.total_prevout_spent_amount = entry.total_prevout_spent_amount;
328 coins_stats.total_new_outputs_ex_coinbase_amount = entry.total_new_outputs_ex_coinbase_amount;
329 coins_stats.total_coinbase_amount = entry.total_coinbase_amount;
330 coins_stats.total_unspendables_genesis_block = entry.total_unspendables_genesis_block;
331 coins_stats.total_unspendables_bip30 = entry.total_unspendables_bip30;
332 coins_stats.total_unspendables_scripts = entry.total_unspendables_scripts;
333 coins_stats.total_unspendables_unclaimed_rewards = entry.total_unspendables_unclaimed_rewards;
334
335 return true;
336}
337
339{
340 if (!m_db->Read(DB_MUHASH, m_muhash)) {
341 // Check that the cause of the read failure is that the key does not
342 // exist. Any other errors indicate database corruption or a disk
343 // failure, and starting the index would cause further corruption.
344 if (m_db->Exists(DB_MUHASH)) {
345 return error("%s: Cannot read current %s state; index may be corrupted",
346 __func__, GetName());
347 }
348 }
349
350 if (!BaseIndex::Init()) return false;
351
352 const CBlockIndex* pindex{CurrentIndex()};
353
354 if (pindex) {
355 DBVal entry;
356 if (!LookUpOne(*m_db, pindex, entry)) {
357 return false;
358 }
359
360 m_transaction_output_count = entry.transaction_output_count;
361 m_bogo_size = entry.bogo_size;
362 m_total_amount = entry.total_amount;
363 m_total_subsidy = entry.total_subsidy;
364 m_total_unspendable_amount = entry.total_unspendable_amount;
365 m_total_prevout_spent_amount = entry.total_prevout_spent_amount;
366 m_total_new_outputs_ex_coinbase_amount = entry.total_new_outputs_ex_coinbase_amount;
367 m_total_coinbase_amount = entry.total_coinbase_amount;
368 m_total_unspendables_genesis_block = entry.total_unspendables_genesis_block;
369 m_total_unspendables_bip30 = entry.total_unspendables_bip30;
370 m_total_unspendables_scripts = entry.total_unspendables_scripts;
371 m_total_unspendables_unclaimed_rewards = entry.total_unspendables_unclaimed_rewards;
372 }
373
374 return true;
375}
376
377// Reverse a single block as part of a reorg
378bool CoinStatsIndex::ReverseBlock(const CBlock& block, const CBlockIndex* pindex)
379{
380 CBlockUndo block_undo;
381 std::pair<uint256, DBVal> read_out;
382
383 const CAmount block_subsidy{GetBlockSubsidy(pindex->nHeight, Params().GetConsensus())};
384 m_total_subsidy -= block_subsidy;
385
386 // Ignore genesis block
387 if (pindex->nHeight > 0) {
388 if (!UndoReadFromDisk(block_undo, pindex)) {
389 return false;
390 }
391
392 if (!m_db->Read(DBHeightKey(pindex->nHeight - 1), read_out)) {
393 return false;
394 }
395
396 uint256 expected_block_hash{pindex->pprev->GetBlockHash()};
397 if (read_out.first != expected_block_hash) {
398 LogPrintf("WARNING: previous block header belongs to unexpected block %s; expected %s\n",
399 read_out.first.ToString(), expected_block_hash.ToString());
400
401 if (!m_db->Read(DBHashKey(expected_block_hash), read_out)) {
402 return error("%s: previous block header not found; expected %s",
403 __func__, expected_block_hash.ToString());
404 }
405 }
406 }
407
408 // Remove the new UTXOs that were created from the block
409 for (size_t i = 0; i < block.vtx.size(); ++i) {
410 const auto& tx{block.vtx.at(i)};
411
412 for (uint32_t j = 0; j < tx->vout.size(); ++j) {
413 const CTxOut& out{tx->vout[j]};
414 COutPoint outpoint{tx->GetHash(), j};
415 Coin coin{out, pindex->nHeight, tx->IsCoinBase()};
416
417 // Skip unspendable coins
418 if (coin.out.scriptPubKey.IsUnspendable()) {
419 m_total_unspendable_amount -= coin.out.nValue;
420 m_total_unspendables_scripts -= coin.out.nValue;
421 continue;
422 }
423
424 m_muhash.Remove(MakeUCharSpan(TxOutSer(outpoint, coin)));
425
426 if (tx->IsCoinBase()) {
427 m_total_coinbase_amount -= coin.out.nValue;
428 } else {
430 }
431
433 m_total_amount -= coin.out.nValue;
434 m_bogo_size -= GetBogoSize(coin.out.scriptPubKey);
435 }
436
437 // The coinbase tx has no undo data since no former output is spent
438 if (!tx->IsCoinBase()) {
439 const auto& tx_undo{block_undo.vtxundo.at(i - 1)};
440
441 for (size_t j = 0; j < tx_undo.vprevout.size(); ++j) {
442 Coin coin{tx_undo.vprevout[j]};
443 COutPoint outpoint{tx->vin[j].prevout.hash, tx->vin[j].prevout.n};
444
445 m_muhash.Insert(MakeUCharSpan(TxOutSer(outpoint, coin)));
446
447 m_total_prevout_spent_amount -= coin.out.nValue;
448
450 m_total_amount += coin.out.nValue;
451 m_bogo_size += GetBogoSize(coin.out.scriptPubKey);
452 }
453 }
454 }
455
457 m_total_unspendable_amount -= unclaimed_rewards;
458 m_total_unspendables_unclaimed_rewards -= unclaimed_rewards;
459
460 // Check that the rolled back internal values are consistent with the DB read out
461 uint256 out;
462 m_muhash.Finalize(out);
463 Assert(read_out.second.muhash == out);
464
465 Assert(m_transaction_output_count == read_out.second.transaction_output_count);
466 Assert(m_total_amount == read_out.second.total_amount);
467 Assert(m_bogo_size == read_out.second.bogo_size);
468 Assert(m_total_subsidy == read_out.second.total_subsidy);
469 Assert(m_total_unspendable_amount == read_out.second.total_unspendable_amount);
470 Assert(m_total_prevout_spent_amount == read_out.second.total_prevout_spent_amount);
471 Assert(m_total_new_outputs_ex_coinbase_amount == read_out.second.total_new_outputs_ex_coinbase_amount);
472 Assert(m_total_coinbase_amount == read_out.second.total_coinbase_amount);
473 Assert(m_total_unspendables_genesis_block == read_out.second.total_unspendables_genesis_block);
474 Assert(m_total_unspendables_bip30 == read_out.second.total_unspendables_bip30);
475 Assert(m_total_unspendables_scripts == read_out.second.total_unspendables_scripts);
476 Assert(m_total_unspendables_unclaimed_rewards == read_out.second.total_unspendables_unclaimed_rewards);
477
478 return m_db->Write(DB_MUHASH, m_muhash);
479}
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: validation.cpp:118
bool UndoReadFromDisk(CBlockUndo &blockundo, const CBlockIndex *pindex)
bool ReadBlockFromDisk(CBlock &block, const FlatFilePos &pos, const Consensus::Params &consensusParams)
Functions for disk access for blocks.
const CChainParams & Params()
Return the currently selected parameters.
#define Assert(val)
Identity function.
Definition: check.h:57
const fs::path & GetDataDirNet() const
Get data directory path with appended network identifier.
Definition: system.h:288
virtual bool Init()
Initialize internal state from the database and block index.
Definition: base.cpp:56
CChainState * m_chainstate
Definition: base.h:79
const CBlockIndex * CurrentIndex()
Definition: base.h:85
virtual bool Rewind(const CBlockIndex *current_tip, const CBlockIndex *new_tip)
Rewind index to an earlier chain tip during a chain reorg.
Definition: base.cpp:213
CBlockIndex * LookupBlockIndex(const uint256 &hash) const EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Definition: validation.cpp:150
Definition: block.h:63
std::vector< CTransactionRef > vtx
Definition: block.h:66
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: chain.h:146
CBlockIndex * pprev
pointer to the index of the predecessor of this block
Definition: chain.h:152
uint256 GetBlockHash() const
Definition: chain.h:254
CBlockIndex * GetAncestor(int height)
Efficiently find an ancestor of this block.
Definition: chain.cpp:111
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: chain.h:158
Undo information for a CBlock.
Definition: undo.h:64
std::vector< CTxUndo > vtxundo
Definition: undo.h:66
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:82
BlockManager & m_blockman
Reference to a BlockManager instance which itself is shared across all CChainState instances.
Definition: validation.h:583
Batch of changes queued to be written to a CDBWrapper.
Definition: dbwrapper.h:48
void Write(const K &key, const V &value)
Definition: dbwrapper.h:73
bool GetValue(V &value)
Definition: dbwrapper.h:158
bool GetKey(K &key)
Definition: dbwrapper.h:147
void Seek(const K &key)
Definition: dbwrapper.h:137
void Next()
Definition: dbwrapper.cpp:240
bool Read(const K &key, V &value) const
Definition: dbwrapper.h:231
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:27
uint256 hash
Definition: transaction.h:29
An output of a transaction.
Definition: transaction.h:129
A UTXO entry.
Definition: coins.h:31
CAmount m_total_subsidy
const char * GetName() const override
Get the name of the index for display in logs.
CAmount m_total_unspendables_genesis_block
bool LookUpStats(const CBlockIndex *block_index, CCoinsStats &coins_stats) const
CAmount m_total_unspendable_amount
CAmount m_total_new_outputs_ex_coinbase_amount
CAmount m_total_unspendables_scripts
CAmount m_total_amount
uint64_t m_bogo_size
uint64_t m_transaction_output_count
bool Rewind(const CBlockIndex *current_tip, const CBlockIndex *new_tip) override
Rewind index to an earlier chain tip during a chain reorg.
CAmount m_total_prevout_spent_amount
bool ReverseBlock(const CBlock &block, const CBlockIndex *pindex)
MuHash3072 m_muhash
std::unique_ptr< BaseIndex::DB > m_db
CoinStatsIndex(size_t n_cache_size, bool f_memory=false, bool f_wipe=false)
std::string m_name
bool WriteBlock(const CBlock &block, const CBlockIndex *pindex) override
Write update index entries for a newly connected block.
CAmount m_total_coinbase_amount
CAmount m_total_unspendables_bip30
CAmount m_total_unspendables_unclaimed_rewards
bool Init() override
Initialize internal state from the database and block index.
void Finalize(uint256 &out) noexcept
Definition: muhash.cpp:313
MuHash3072 & Remove(Span< const unsigned char > in) noexcept
Definition: muhash.cpp:343
MuHash3072 & Insert(Span< const unsigned char > in) noexcept
Definition: muhash.cpp:338
Path class wrapper to prepare application code for transition from boost::filesystem library to std::...
Definition: fs.h:34
256-bit opaque blob.
Definition: uint256.h:124
CDataStream TxOutSer(const COutPoint &outpoint, const Coin &coin)
Definition: coinstats.cpp:30
uint64_t GetBogoSize(const CScript &script_pub_key)
Definition: coinstats.cpp:20
static bool LookUpOne(const CDBWrapper &db, const CBlockIndex *block_index, DBVal &result)
static constexpr uint8_t DB_MUHASH
std::unique_ptr< CoinStatsIndex > g_coin_stats_index
The global UTXO set hash object.
static bool CopyHeightIndexToHashIndex(CDBIterator &db_it, CDBBatch &batch, const std::string &index_name, int start_height, int stop_height)
static constexpr uint8_t DB_BLOCK_HASH
static constexpr uint8_t DB_BLOCK_HEIGHT
#define LogPrintf(...)
Definition: logging.h:187
const char * prefix
Definition: rest.cpp:714
uint8_t ser_readdata8(Stream &s)
Definition: serialize.h:89
void ser_writedata32be(Stream &s, uint32_t obj)
Definition: serialize.h:79
#define SERIALIZE_METHODS(cls, obj)
Implement the Serialize and Unserialize methods by delegating to a single templated static method tha...
Definition: serialize.h:183
void Serialize(Stream &s, char a)
Definition: serialize.h:199
void Unserialize(Stream &s, char &a)
Definition: serialize.h:215
void ser_writedata8(Stream &s, uint8_t obj)
Definition: serialize.h:60
uint32_t ser_readdata32be(Stream &s)
Definition: serialize.h:113
#define READWRITE(...)
Definition: serialize.h:147
constexpr auto MakeUCharSpan(V &&v) -> decltype(UCharSpanCast(MakeSpan(std::forward< V >(v))))
Like MakeSpan, but for (const) unsigned char member types only.
Definition: span.h:249
uint64_t nTransactionOutputs
Definition: coinstats.h:33
uint256 hashSerialized
Definition: coinstats.h:35
CAmount total_prevout_spent_amount
Total cumulative amount of prevouts spent up to and including this block.
Definition: coinstats.h:54
uint64_t nBogoSize
Definition: coinstats.h:34
CAmount total_unspendable_amount
Total cumulative amount of unspendable coins up to and including this block.
Definition: coinstats.h:52
CAmount total_unspendables_unclaimed_rewards
Total cumulative amount of coins lost due to unclaimed miner rewards up to and including this block.
Definition: coinstats.h:66
CAmount total_new_outputs_ex_coinbase_amount
Total cumulative amount of outputs created up to and including this block.
Definition: coinstats.h:56
CAmount total_unspendables_genesis_block
The unspendable coinbase amount from the genesis block.
Definition: coinstats.h:60
CAmount total_unspendables_bip30
The two unspendable coinbase outputs total amount caused by BIP30.
Definition: coinstats.h:62
CAmount total_unspendables_scripts
Total cumulative amount of outputs sent to unspendable scripts (OP_RETURN for example) up to and incl...
Definition: coinstats.h:64
CAmount nTotalAmount
Definition: coinstats.h:37
CAmount total_coinbase_amount
Total cumulative amount of coinbase outputs up to and including this block.
Definition: coinstats.h:58
CAmount total_subsidy
Total cumulative amount of block subsidies up to and including this block.
Definition: coinstats.h:50
#define LOCK(cs)
Definition: sync.h:226
bool error(const char *fmt, const Args &... args)
Definition: system.h:49
uint256 uint256S(const char *str)
Definition: uint256.h:137
ArgsManager gArgs
Definition: system.cpp:85
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params &consensusParams)
assert(!tx.IsCoinBase())