Bitcoin ABC 0.32.4
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
6
7#include <chainparams.h>
8#include <coins.h>
9#include <common/args.h>
10#include <consensus/amount.h>
11#include <crypto/muhash.h>
12#include <logging.h>
13#include <node/blockstorage.h>
15#include <serialize.h>
16#include <txdb.h>
17#include <undo.h>
18#include <util/check.h>
19#include <validation.h>
20
24
25static constexpr uint8_t DB_BLOCK_HASH{'s'};
26static constexpr uint8_t DB_BLOCK_HEIGHT{'t'};
27static constexpr uint8_t DB_MUHASH{'M'};
28
29namespace {
30
31struct DBVal {
32 uint256 muhash;
33 uint64_t transaction_output_count;
34 uint64_t bogo_size;
35 Amount total_amount;
36 Amount total_subsidy;
37 Amount total_unspendable_amount;
38 Amount total_prevout_spent_amount;
39 Amount total_new_outputs_ex_coinbase_amount;
40 Amount total_coinbase_amount;
41 Amount total_unspendables_genesis_block;
42 Amount total_unspendables_bip30;
43 Amount total_unspendables_scripts;
44 Amount total_unspendables_unclaimed_rewards;
45
46 SERIALIZE_METHODS(DBVal, obj) {
47 READWRITE(obj.muhash);
48 READWRITE(obj.transaction_output_count);
49 READWRITE(obj.bogo_size);
50 READWRITE(obj.total_amount);
51 READWRITE(obj.total_subsidy);
52 READWRITE(obj.total_unspendable_amount);
53 READWRITE(obj.total_prevout_spent_amount);
54 READWRITE(obj.total_new_outputs_ex_coinbase_amount);
55 READWRITE(obj.total_coinbase_amount);
56 READWRITE(obj.total_unspendables_genesis_block);
57 READWRITE(obj.total_unspendables_bip30);
58 READWRITE(obj.total_unspendables_scripts);
59 READWRITE(obj.total_unspendables_unclaimed_rewards);
60 }
61};
62
63struct DBHeightKey {
64 int height;
65
66 explicit DBHeightKey(int height_in) : height(height_in) {}
67
68 template <typename Stream> void Serialize(Stream &s) const {
70 ser_writedata32be(s, height);
71 }
72
73 template <typename Stream> void Unserialize(Stream &s) {
74 const uint8_t prefix{ser_readdata8(s)};
75 if (prefix != DB_BLOCK_HEIGHT) {
76 throw std::ios_base::failure(
77 "Invalid format for coinstatsindex DB height key");
78 }
79 height = ser_readdata32be(s);
80 }
81};
82
83struct DBHashKey {
84 BlockHash block_hash;
85
86 explicit DBHashKey(const BlockHash &hash_in) : block_hash(hash_in) {}
87
88 SERIALIZE_METHODS(DBHashKey, obj) {
89 uint8_t prefix{DB_BLOCK_HASH};
91 if (prefix != DB_BLOCK_HASH) {
92 throw std::ios_base::failure(
93 "Invalid format for coinstatsindex DB hash key");
94 }
95
96 READWRITE(obj.block_hash);
97 }
98};
99
100}; // namespace
101
102std::unique_ptr<CoinStatsIndex> g_coin_stats_index;
103
104CoinStatsIndex::CoinStatsIndex(std::unique_ptr<interfaces::Chain> chain,
105 size_t n_cache_size, bool f_memory, bool f_wipe)
106 : BaseIndex(std::move(chain), "coinstatsindex") {
107 fs::path path{gArgs.GetDataDirNet() / "indexes" / "coinstats"};
109
110 m_db = std::make_unique<CoinStatsIndex::DB>(path / "db", n_cache_size,
111 f_memory, f_wipe);
112}
113
115 const CBlockIndex *pindex) {
116 CBlockUndo block_undo;
117 const Amount block_subsidy{
118 GetBlockSubsidy(pindex->nHeight, Params().GetConsensus())};
119 m_total_subsidy += block_subsidy;
120
121 // Ignore genesis block
122 if (pindex->nHeight > 0) {
123 if (!m_chainstate->m_blockman.UndoReadFromDisk(block_undo, *pindex)) {
124 return false;
125 }
126
127 std::pair<BlockHash, DBVal> read_out;
128 if (!m_db->Read(DBHeightKey(pindex->nHeight - 1), read_out)) {
129 return false;
130 }
131
132 BlockHash expected_block_hash{pindex->pprev->GetBlockHash()};
133 if (read_out.first != expected_block_hash) {
134 LogPrintf("WARNING: previous block header belongs to unexpected "
135 "block %s; expected %s\n",
136 read_out.first.ToString(),
137 expected_block_hash.ToString());
138
139 if (!m_db->Read(DBHashKey(expected_block_hash), read_out)) {
140 LogError("%s: previous block header not found; expected %s\n",
141 __func__, expected_block_hash.ToString());
142 return false;
143 }
144 }
145
146 // TODO: Deduplicate BIP30 related code
147 bool is_bip30_block{
148 (pindex->nHeight == 91722 &&
149 pindex->GetBlockHash() ==
150 BlockHash{uint256S("0x00000000000271a2dc26e7667f8419f2e15416dc"
151 "6955e5a6c6cdf3f2574dd08e")}) ||
152 (pindex->nHeight == 91812 &&
153 pindex->GetBlockHash() ==
154 BlockHash{uint256S("0x00000000000af0aed4792b1acee3d966af36cf5d"
155 "ef14935db8de83d6f9306f2f")})};
156
157 // Add the new utxos created from the block
158 for (size_t i = 0; i < block.vtx.size(); ++i) {
159 const auto &tx{block.vtx.at(i)};
160
161 // Skip duplicate txid coinbase transactions (BIP30).
162 if (is_bip30_block && tx->IsCoinBase()) {
163 m_total_unspendable_amount += block_subsidy;
164 m_total_unspendables_bip30 += block_subsidy;
165 continue;
166 }
167
168 for (uint32_t j = 0; j < tx->vout.size(); ++j) {
169 const CTxOut &out{tx->vout[j]};
170 Coin coin{out, static_cast<uint32_t>(pindex->nHeight),
171 tx->IsCoinBase()};
172 COutPoint outpoint{tx->GetId(), j};
173
174 // Skip unspendable coins
175 if (coin.GetTxOut().scriptPubKey.IsUnspendable()) {
176 m_total_unspendable_amount += coin.GetTxOut().nValue;
177 m_total_unspendables_scripts += coin.GetTxOut().nValue;
178 continue;
179 }
180
181 m_muhash.Insert(MakeUCharSpan(TxOutSer(outpoint, coin)));
182
183 if (tx->IsCoinBase()) {
184 m_total_coinbase_amount += coin.GetTxOut().nValue;
185 } else {
187 coin.GetTxOut().nValue;
188 }
189
191 m_total_amount += coin.GetTxOut().nValue;
192 m_bogo_size += GetBogoSize(coin.GetTxOut().scriptPubKey);
193 }
194
195 // The coinbase tx has no undo data since no former output is spent
196 if (!tx->IsCoinBase()) {
197 const auto &tx_undo{block_undo.vtxundo.at(i - 1)};
198
199 for (size_t j = 0; j < tx_undo.vprevout.size(); ++j) {
200 Coin coin{tx_undo.vprevout[j]};
201 COutPoint outpoint{tx->vin[j].prevout.GetTxId(),
202 tx->vin[j].prevout.GetN()};
203
204 m_muhash.Remove(MakeUCharSpan(TxOutSer(outpoint, coin)));
205
206 m_total_prevout_spent_amount += coin.GetTxOut().nValue;
207
209 m_total_amount -= coin.GetTxOut().nValue;
210 m_bogo_size -= GetBogoSize(coin.GetTxOut().scriptPubKey);
211 }
212 }
213 }
214 } else {
215 // genesis block
216 m_total_unspendable_amount += block_subsidy;
217 m_total_unspendables_genesis_block += block_subsidy;
218 }
219
220 // If spent prevouts + block subsidy are still a higher amount than
221 // new outputs + coinbase + current unspendable amount this means
222 // the miner did not claim the full block reward. Unclaimed block
223 // rewards are also unspendable.
224 const Amount unclaimed_rewards{
228 m_total_unspendable_amount += unclaimed_rewards;
229 m_total_unspendables_unclaimed_rewards += unclaimed_rewards;
230
231 std::pair<BlockHash, DBVal> value;
232 value.first = pindex->GetBlockHash();
233 value.second.transaction_output_count = m_transaction_output_count;
234 value.second.bogo_size = m_bogo_size;
235 value.second.total_amount = m_total_amount;
236 value.second.total_subsidy = m_total_subsidy;
237 value.second.total_unspendable_amount = m_total_unspendable_amount;
238 value.second.total_prevout_spent_amount = m_total_prevout_spent_amount;
239 value.second.total_new_outputs_ex_coinbase_amount =
241 value.second.total_coinbase_amount = m_total_coinbase_amount;
242 value.second.total_unspendables_genesis_block =
244 value.second.total_unspendables_bip30 = m_total_unspendables_bip30;
245 value.second.total_unspendables_scripts = m_total_unspendables_scripts;
246 value.second.total_unspendables_unclaimed_rewards =
248
249 uint256 out;
250 m_muhash.Finalize(out);
251 value.second.muhash = out;
252
253 // Intentionally do not update DB_MUHASH here so it stays in sync with
254 // DB_BEST_BLOCK, and the index is not corrupted if there is an unclean
255 // shutdown.
256 return m_db->Write(DBHeightKey(pindex->nHeight), value);
257}
258
260 const std::string &index_name,
261 int start_height, int stop_height) {
262 DBHeightKey key{start_height};
263 db_it.Seek(key);
264
265 for (int height = start_height; height <= stop_height; ++height) {
266 if (!db_it.GetKey(key) || key.height != height) {
267 LogError("%s: unexpected key in %s: expected (%c, %d)\n", __func__,
268 index_name, DB_BLOCK_HEIGHT, height);
269 return false;
270 }
271
272 std::pair<BlockHash, DBVal> value;
273 if (!db_it.GetValue(value)) {
274 LogError("%s: unable to read value in %s at key (%c, %d)\n",
275 __func__, index_name, DB_BLOCK_HEIGHT, height);
276 return false;
277 }
278
279 batch.Write(DBHashKey(value.first), std::move(value.second));
280
281 db_it.Next();
282 }
283 return true;
284}
285
286bool CoinStatsIndex::Rewind(const CBlockIndex *current_tip,
287 const CBlockIndex *new_tip) {
288 assert(current_tip->GetAncestor(new_tip->nHeight) == new_tip);
289
290 CDBBatch batch(*m_db);
291 std::unique_ptr<CDBIterator> db_it(m_db->NewIterator());
292
293 // During a reorg, we need to copy all hash digests for blocks that are
294 // getting disconnected from the height index to the hash index so we can
295 // still find them when the height index entries are overwritten.
296 if (!CopyHeightIndexToHashIndex(*db_it, batch, m_name, new_tip->nHeight,
297 current_tip->nHeight)) {
298 return false;
299 }
300
301 if (!m_db->WriteBatch(batch)) {
302 return false;
303 }
304
305 {
306 LOCK(cs_main);
308 current_tip->GetBlockHash())};
309
310 do {
311 CBlock block;
312
313 if (!m_chainstate->m_blockman.ReadBlockFromDisk(block, *iter_tip)) {
314 LogError("%s: Failed to read block %s from disk\n", __func__,
315 iter_tip->GetBlockHash().ToString());
316 return false;
317 }
318
319 ReverseBlock(block, iter_tip);
320
321 iter_tip = iter_tip->GetAncestor(iter_tip->nHeight - 1);
322 } while (new_tip != iter_tip);
323 }
324
325 return BaseIndex::Rewind(current_tip, new_tip);
326}
327
328static bool LookUpOne(const CDBWrapper &db, const interfaces::BlockKey &block,
329 DBVal &result) {
330 // First check if the result is stored under the height index and the value
331 // there matches the block hash. This should be the case if the block is on
332 // the active chain.
333 std::pair<BlockHash, DBVal> read_out;
334 if (!db.Read(DBHeightKey(block.height), read_out)) {
335 return false;
336 }
337 if (read_out.first == block.hash) {
338 result = std::move(read_out.second);
339 return true;
340 }
341
342 // If value at the height index corresponds to an different block, the
343 // result will be stored in the hash index.
344 return db.Read(DBHashKey(block.hash), result);
345}
346
347std::optional<CCoinsStats>
348CoinStatsIndex::LookUpStats(const CBlockIndex *block_index) const {
349 CCoinsStats stats{Assert(block_index)->nHeight,
350 block_index->GetBlockHash()};
351 stats.index_used = true;
352
353 DBVal entry;
354 if (!LookUpOne(*m_db, {block_index->GetBlockHash(), block_index->nHeight},
355 entry)) {
356 return std::nullopt;
357 }
358
359 stats.hashSerialized = entry.muhash;
360 stats.nTransactionOutputs = entry.transaction_output_count;
361 stats.nBogoSize = entry.bogo_size;
362 stats.nTotalAmount = entry.total_amount;
363 stats.total_subsidy = entry.total_subsidy;
364 stats.total_unspendable_amount = entry.total_unspendable_amount;
365 stats.total_prevout_spent_amount = entry.total_prevout_spent_amount;
366 stats.total_new_outputs_ex_coinbase_amount =
367 entry.total_new_outputs_ex_coinbase_amount;
368 stats.total_coinbase_amount = entry.total_coinbase_amount;
369 stats.total_unspendables_genesis_block =
370 entry.total_unspendables_genesis_block;
371 stats.total_unspendables_bip30 = entry.total_unspendables_bip30;
372 stats.total_unspendables_scripts = entry.total_unspendables_scripts;
373 stats.total_unspendables_unclaimed_rewards =
374 entry.total_unspendables_unclaimed_rewards;
375
376 return stats;
377}
378
380 const std::optional<interfaces::BlockKey> &block) {
381 if (!m_db->Read(DB_MUHASH, m_muhash)) {
382 // Check that the cause of the read failure is that the key does not
383 // exist. Any other errors indicate database corruption or a disk
384 // failure, and starting the index would cause further corruption.
385 if (m_db->Exists(DB_MUHASH)) {
386 LogError(
387 "%s: Cannot read current %s state; index may be corrupted\n",
388 __func__, GetName());
389 return false;
390 }
391 }
392
393 if (block) {
394 DBVal entry;
395 if (!LookUpOne(*m_db, *block, entry)) {
396 LogError(
397 "%s: Cannot read current %s state; index may be corrupted\n",
398 __func__, GetName());
399 return false;
400 }
401
402 uint256 out;
403 m_muhash.Finalize(out);
404 if (entry.muhash != out) {
405 LogError(
406 "%s: Cannot read current %s state; index may be corrupted\n",
407 __func__, GetName());
408 return false;
409 }
410
411 m_transaction_output_count = entry.transaction_output_count;
412 m_bogo_size = entry.bogo_size;
413 m_total_amount = entry.total_amount;
414 m_total_subsidy = entry.total_subsidy;
415 m_total_unspendable_amount = entry.total_unspendable_amount;
416 m_total_prevout_spent_amount = entry.total_prevout_spent_amount;
418 entry.total_new_outputs_ex_coinbase_amount;
419 m_total_coinbase_amount = entry.total_coinbase_amount;
421 entry.total_unspendables_genesis_block;
422 m_total_unspendables_bip30 = entry.total_unspendables_bip30;
423 m_total_unspendables_scripts = entry.total_unspendables_scripts;
425 entry.total_unspendables_unclaimed_rewards;
426 }
427
428 return true;
429}
430
432 // DB_MUHASH should always be committed in a batch together with
433 // DB_BEST_BLOCK to prevent an inconsistent state of the DB.
434 batch.Write(DB_MUHASH, m_muhash);
435 return true;
436}
437
438// Reverse a single block as part of a reorg
440 const CBlockIndex *pindex) {
441 CBlockUndo block_undo;
442 std::pair<BlockHash, DBVal> read_out;
443
444 const Amount block_subsidy{
445 GetBlockSubsidy(pindex->nHeight, Params().GetConsensus())};
446 m_total_subsidy -= block_subsidy;
447
448 // Ignore genesis block
449 if (pindex->nHeight > 0) {
450 if (!m_chainstate->m_blockman.UndoReadFromDisk(block_undo, *pindex)) {
451 return false;
452 }
453
454 if (!m_db->Read(DBHeightKey(pindex->nHeight - 1), read_out)) {
455 return false;
456 }
457
458 BlockHash expected_block_hash{pindex->pprev->GetBlockHash()};
459 if (read_out.first != expected_block_hash) {
460 LogPrintf("WARNING: previous block header belongs to unexpected "
461 "block %s; expected %s\n",
462 read_out.first.ToString(),
463 expected_block_hash.ToString());
464
465 if (!m_db->Read(DBHashKey(expected_block_hash), read_out)) {
466 LogError("%s: previous block header not found; expected %s\n",
467 __func__, expected_block_hash.ToString());
468 return false;
469 }
470 }
471 }
472
473 // Remove the new UTXOs that were created from the block
474 for (size_t i = 0; i < block.vtx.size(); ++i) {
475 const auto &tx{block.vtx.at(i)};
476
477 for (uint32_t j = 0; j < tx->vout.size(); ++j) {
478 const CTxOut &out{tx->vout[j]};
479 COutPoint outpoint{tx->GetId(), j};
480 Coin coin{out, static_cast<uint32_t>(pindex->nHeight),
481 tx->IsCoinBase()};
482
483 // Skip unspendable coins
484 if (coin.GetTxOut().scriptPubKey.IsUnspendable()) {
485 m_total_unspendable_amount -= coin.GetTxOut().nValue;
486 m_total_unspendables_scripts -= coin.GetTxOut().nValue;
487 continue;
488 }
489
490 m_muhash.Remove(MakeUCharSpan(TxOutSer(outpoint, coin)));
491
492 if (tx->IsCoinBase()) {
493 m_total_coinbase_amount -= coin.GetTxOut().nValue;
494 } else {
496 coin.GetTxOut().nValue;
497 }
498
500 m_total_amount -= coin.GetTxOut().nValue;
501 m_bogo_size -= GetBogoSize(coin.GetTxOut().scriptPubKey);
502 }
503
504 // The coinbase tx has no undo data since no former output is spent
505 if (!tx->IsCoinBase()) {
506 const auto &tx_undo{block_undo.vtxundo.at(i - 1)};
507
508 for (size_t j = 0; j < tx_undo.vprevout.size(); ++j) {
509 Coin coin{tx_undo.vprevout[j]};
510 COutPoint outpoint{tx->vin[j].prevout.GetTxId(),
511 tx->vin[j].prevout.GetN()};
512
513 m_muhash.Insert(MakeUCharSpan(TxOutSer(outpoint, coin)));
514
515 m_total_prevout_spent_amount -= coin.GetTxOut().nValue;
516
518 m_total_amount += coin.GetTxOut().nValue;
519 m_bogo_size += GetBogoSize(coin.GetTxOut().scriptPubKey);
520 }
521 }
522 }
523
524 const Amount unclaimed_rewards{
528 m_total_unspendable_amount -= unclaimed_rewards;
529 m_total_unspendables_unclaimed_rewards -= unclaimed_rewards;
530
531 // Check that the rolled back internal values are consistent with the DB
532 // read out
533 uint256 out;
534 m_muhash.Finalize(out);
535 Assert(read_out.second.muhash == out);
536
538 read_out.second.transaction_output_count);
539 Assert(m_total_amount == read_out.second.total_amount);
540 Assert(m_bogo_size == read_out.second.bogo_size);
541 Assert(m_total_subsidy == read_out.second.total_subsidy);
543 read_out.second.total_unspendable_amount);
545 read_out.second.total_prevout_spent_amount);
547 read_out.second.total_new_outputs_ex_coinbase_amount);
548 Assert(m_total_coinbase_amount == read_out.second.total_coinbase_amount);
550 read_out.second.total_unspendables_genesis_block);
552 read_out.second.total_unspendables_bip30);
554 read_out.second.total_unspendables_scripts);
556 read_out.second.total_unspendables_unclaimed_rewards);
557
558 return true;
559}
ArgsManager gArgs
Definition: args.cpp:40
const CChainParams & Params()
Return the currently selected parameters.
Definition: chainparams.cpp:21
#define Assert(val)
Identity function.
Definition: check.h:84
fs::path GetDataDirNet() const
Get data directory path with appended network identifier.
Definition: args.h:239
Base class for indices of blockchain data.
Definition: base.h:37
const std::string & GetName() const LIFETIMEBOUND
Get the name of the index for display in logs.
Definition: base.h:143
const std::string m_name
Definition: base.h:103
Chainstate * m_chainstate
Definition: base.h:102
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:252
Definition: block.h:60
std::vector< CTransactionRef > vtx
Definition: block.h:63
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: blockindex.h:25
CBlockIndex * pprev
pointer to the index of the predecessor of this block
Definition: blockindex.h:32
CBlockIndex * GetAncestor(int height)
Efficiently find an ancestor of this block.
Definition: blockindex.cpp:62
BlockHash GetBlockHash() const
Definition: blockindex.h:130
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: blockindex.h:38
Undo information for a CBlock.
Definition: undo.h:73
std::vector< CTxUndo > vtxundo
Definition: undo.h:76
Batch of changes queued to be written to a CDBWrapper.
Definition: dbwrapper.h:78
void Write(const K &key, const V &value)
Definition: dbwrapper.h:103
bool GetValue(V &value)
Definition: dbwrapper.h:184
bool GetKey(K &key)
Definition: dbwrapper.h:173
void Seek(const K &key)
Definition: dbwrapper.h:163
void Next()
Definition: dbwrapper.cpp:259
An output of a transaction.
Definition: transaction.h:128
node::BlockManager & m_blockman
Reference to a BlockManager instance which itself is shared across all Chainstate instances.
Definition: validation.h:791
A UTXO entry.
Definition: coins.h:29
bool IsCoinBase() const
Definition: coins.h:47
Amount m_total_amount
Amount m_total_prevout_spent_amount
Amount m_total_unspendables_bip30
Amount m_total_unspendables_genesis_block
CoinStatsIndex(std::unique_ptr< interfaces::Chain > chain, size_t n_cache_size, bool f_memory=false, bool f_wipe=false)
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.
Amount m_total_coinbase_amount
bool ReverseBlock(const CBlock &block, const CBlockIndex *pindex)
MuHash3072 m_muhash
std::unique_ptr< BaseIndex::DB > m_db
std::optional< kernel::CCoinsStats > LookUpStats(const CBlockIndex *block_index) const
bool CustomCommit(CDBBatch &batch) override
Virtual method called internally by Commit that can be overridden to atomically commit more index sta...
Amount m_total_unspendables_scripts
bool WriteBlock(const CBlock &block, const CBlockIndex *pindex) override
Write update index entries for a newly connected block.
bool CustomInit(const std::optional< interfaces::BlockKey > &block) override
Initialize internal state from the database and block index.
Amount m_total_new_outputs_ex_coinbase_amount
Amount m_total_unspendable_amount
Amount m_total_unspendables_unclaimed_rewards
Amount m_total_subsidy
MuHash3072 & Remove(Span< const uint8_t > in) noexcept
Definition: muhash.cpp:711
void Finalize(uint256 &out) noexcept
Definition: muhash.cpp:683
MuHash3072 & Insert(Span< const uint8_t > in) noexcept
Definition: muhash.cpp:706
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:30
bool ReadBlockFromDisk(CBlock &block, const FlatFilePos &pos) const
Functions for disk access for blocks.
CBlockIndex * LookupBlockIndex(const BlockHash &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
bool UndoReadFromDisk(CBlockUndo &blockundo, const CBlockIndex &index) const
256-bit opaque blob.
Definition: uint256.h:129
static constexpr uint8_t DB_MUHASH
static bool LookUpOne(const CDBWrapper &db, const interfaces::BlockKey &block, DBVal &result)
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
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
#define LogPrintf(...)
Definition: logging.h:424
static bool create_directories(const std::filesystem::path &p)
Create directory (and if necessary its parents), unless the leaf directory already exists or is a sym...
Definition: fs.h:184
DataStream TxOutSer(const COutPoint &outpoint, const Coin &coin)
Definition: coinstats.cpp:28
uint64_t GetBogoSize(const CScript &script_pub_key)
Definition: coinstats.cpp:22
Implement std::hash so RCUPtr can be used as a key for maps or sets.
Definition: rcu.h:259
const char * prefix
Definition: rest.cpp:812
CAddrDb db
Definition: main.cpp:35
void Serialize(Stream &, V)=delete
uint8_t ser_readdata8(Stream &s)
Definition: serialize.h:85
void ser_writedata32be(Stream &s, uint32_t obj)
Definition: serialize.h:76
#define SERIALIZE_METHODS(cls, obj)
Implement the Serialize and Unserialize methods by delegating to a single templated static method tha...
Definition: serialize.h:215
void Unserialize(Stream &, V)=delete
void ser_writedata8(Stream &s, uint8_t obj)
Lowest-level serialization and conversion.
Definition: serialize.h:57
uint32_t ser_readdata32be(Stream &s)
Definition: serialize.h:105
#define READWRITE(...)
Definition: serialize.h:168
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
Definition: amount.h:19
A BlockHash is a unqiue identifier for a block.
Definition: blockhash.h:13
Hash/height pair to help track and identify blocks.
Definition: chain.h:49
BlockHash hash
Definition: chain.h:50
#define LOCK(cs)
Definition: sync.h:306
uint256 uint256S(const char *str)
uint256 from const char *.
Definition: uint256.h:143
Amount GetBlockSubsidy(int nHeight, const Consensus::Params &consensusParams)
assert(!tx.IsCoinBase())