Bitcoin ABC 0.31.0
P2P Digital Currency
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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 return error("%s: previous block header not found; expected %s",
141 __func__, expected_block_hash.ToString());
142 }
143 }
144
145 // TODO: Deduplicate BIP30 related code
146 bool is_bip30_block{
147 (pindex->nHeight == 91722 &&
148 pindex->GetBlockHash() ==
149 BlockHash{uint256S("0x00000000000271a2dc26e7667f8419f2e15416dc"
150 "6955e5a6c6cdf3f2574dd08e")}) ||
151 (pindex->nHeight == 91812 &&
152 pindex->GetBlockHash() ==
153 BlockHash{uint256S("0x00000000000af0aed4792b1acee3d966af36cf5d"
154 "ef14935db8de83d6f9306f2f")})};
155
156 // Add the new utxos created from the block
157 for (size_t i = 0; i < block.vtx.size(); ++i) {
158 const auto &tx{block.vtx.at(i)};
159
160 // Skip duplicate txid coinbase transactions (BIP30).
161 if (is_bip30_block && tx->IsCoinBase()) {
162 m_total_unspendable_amount += block_subsidy;
163 m_total_unspendables_bip30 += block_subsidy;
164 continue;
165 }
166
167 for (uint32_t j = 0; j < tx->vout.size(); ++j) {
168 const CTxOut &out{tx->vout[j]};
169 Coin coin{out, static_cast<uint32_t>(pindex->nHeight),
170 tx->IsCoinBase()};
171 COutPoint outpoint{tx->GetId(), j};
172
173 // Skip unspendable coins
174 if (coin.GetTxOut().scriptPubKey.IsUnspendable()) {
175 m_total_unspendable_amount += coin.GetTxOut().nValue;
176 m_total_unspendables_scripts += coin.GetTxOut().nValue;
177 continue;
178 }
179
180 m_muhash.Insert(MakeUCharSpan(TxOutSer(outpoint, coin)));
181
182 if (tx->IsCoinBase()) {
183 m_total_coinbase_amount += coin.GetTxOut().nValue;
184 } else {
186 coin.GetTxOut().nValue;
187 }
188
190 m_total_amount += coin.GetTxOut().nValue;
191 m_bogo_size += GetBogoSize(coin.GetTxOut().scriptPubKey);
192 }
193
194 // The coinbase tx has no undo data since no former output is spent
195 if (!tx->IsCoinBase()) {
196 const auto &tx_undo{block_undo.vtxundo.at(i - 1)};
197
198 for (size_t j = 0; j < tx_undo.vprevout.size(); ++j) {
199 Coin coin{tx_undo.vprevout[j]};
200 COutPoint outpoint{tx->vin[j].prevout.GetTxId(),
201 tx->vin[j].prevout.GetN()};
202
203 m_muhash.Remove(MakeUCharSpan(TxOutSer(outpoint, coin)));
204
205 m_total_prevout_spent_amount += coin.GetTxOut().nValue;
206
208 m_total_amount -= coin.GetTxOut().nValue;
209 m_bogo_size -= GetBogoSize(coin.GetTxOut().scriptPubKey);
210 }
211 }
212 }
213 } else {
214 // genesis block
215 m_total_unspendable_amount += block_subsidy;
216 m_total_unspendables_genesis_block += block_subsidy;
217 }
218
219 // If spent prevouts + block subsidy are still a higher amount than
220 // new outputs + coinbase + current unspendable amount this means
221 // the miner did not claim the full block reward. Unclaimed block
222 // rewards are also unspendable.
223 const Amount unclaimed_rewards{
227 m_total_unspendable_amount += unclaimed_rewards;
228 m_total_unspendables_unclaimed_rewards += unclaimed_rewards;
229
230 std::pair<BlockHash, DBVal> value;
231 value.first = pindex->GetBlockHash();
232 value.second.transaction_output_count = m_transaction_output_count;
233 value.second.bogo_size = m_bogo_size;
234 value.second.total_amount = m_total_amount;
235 value.second.total_subsidy = m_total_subsidy;
236 value.second.total_unspendable_amount = m_total_unspendable_amount;
237 value.second.total_prevout_spent_amount = m_total_prevout_spent_amount;
238 value.second.total_new_outputs_ex_coinbase_amount =
240 value.second.total_coinbase_amount = m_total_coinbase_amount;
241 value.second.total_unspendables_genesis_block =
243 value.second.total_unspendables_bip30 = m_total_unspendables_bip30;
244 value.second.total_unspendables_scripts = m_total_unspendables_scripts;
245 value.second.total_unspendables_unclaimed_rewards =
247
248 uint256 out;
249 m_muhash.Finalize(out);
250 value.second.muhash = out;
251
252 // Intentionally do not update DB_MUHASH here so it stays in sync with
253 // DB_BEST_BLOCK, and the index is not corrupted if there is an unclean
254 // shutdown.
255 return m_db->Write(DBHeightKey(pindex->nHeight), value);
256}
257
259 const std::string &index_name,
260 int start_height, int stop_height) {
261 DBHeightKey key{start_height};
262 db_it.Seek(key);
263
264 for (int height = start_height; height <= stop_height; ++height) {
265 if (!db_it.GetKey(key) || key.height != height) {
266 return error("%s: unexpected key in %s: expected (%c, %d)",
267 __func__, index_name, DB_BLOCK_HEIGHT, height);
268 }
269
270 std::pair<BlockHash, DBVal> value;
271 if (!db_it.GetValue(value)) {
272 return error("%s: unable to read value in %s at key (%c, %d)",
273 __func__, index_name, DB_BLOCK_HEIGHT, height);
274 }
275
276 batch.Write(DBHashKey(value.first), std::move(value.second));
277
278 db_it.Next();
279 }
280 return true;
281}
282
283bool CoinStatsIndex::Rewind(const CBlockIndex *current_tip,
284 const CBlockIndex *new_tip) {
285 assert(current_tip->GetAncestor(new_tip->nHeight) == new_tip);
286
287 CDBBatch batch(*m_db);
288 std::unique_ptr<CDBIterator> db_it(m_db->NewIterator());
289
290 // During a reorg, we need to copy all hash digests for blocks that are
291 // getting disconnected from the height index to the hash index so we can
292 // still find them when the height index entries are overwritten.
293 if (!CopyHeightIndexToHashIndex(*db_it, batch, m_name, new_tip->nHeight,
294 current_tip->nHeight)) {
295 return false;
296 }
297
298 if (!m_db->WriteBatch(batch)) {
299 return false;
300 }
301
302 {
303 LOCK(cs_main);
305 current_tip->GetBlockHash())};
306
307 do {
308 CBlock block;
309
310 if (!m_chainstate->m_blockman.ReadBlockFromDisk(block, *iter_tip)) {
311 return error("%s: Failed to read block %s from disk", __func__,
312 iter_tip->GetBlockHash().ToString());
313 }
314
315 ReverseBlock(block, iter_tip);
316
317 iter_tip = iter_tip->GetAncestor(iter_tip->nHeight - 1);
318 } while (new_tip != iter_tip);
319 }
320
321 return BaseIndex::Rewind(current_tip, new_tip);
322}
323
324static bool LookUpOne(const CDBWrapper &db, const interfaces::BlockKey &block,
325 DBVal &result) {
326 // First check if the result is stored under the height index and the value
327 // there matches the block hash. This should be the case if the block is on
328 // the active chain.
329 std::pair<BlockHash, DBVal> read_out;
330 if (!db.Read(DBHeightKey(block.height), read_out)) {
331 return false;
332 }
333 if (read_out.first == block.hash) {
334 result = std::move(read_out.second);
335 return true;
336 }
337
338 // If value at the height index corresponds to an different block, the
339 // result will be stored in the hash index.
340 return db.Read(DBHashKey(block.hash), result);
341}
342
343std::optional<CCoinsStats>
344CoinStatsIndex::LookUpStats(const CBlockIndex *block_index) const {
345 CCoinsStats stats{Assert(block_index)->nHeight,
346 block_index->GetBlockHash()};
347 stats.index_used = true;
348
349 DBVal entry;
350 if (!LookUpOne(*m_db, {block_index->GetBlockHash(), block_index->nHeight},
351 entry)) {
352 return std::nullopt;
353 }
354
355 stats.hashSerialized = entry.muhash;
356 stats.nTransactionOutputs = entry.transaction_output_count;
357 stats.nBogoSize = entry.bogo_size;
358 stats.nTotalAmount = entry.total_amount;
359 stats.total_subsidy = entry.total_subsidy;
360 stats.total_unspendable_amount = entry.total_unspendable_amount;
361 stats.total_prevout_spent_amount = entry.total_prevout_spent_amount;
362 stats.total_new_outputs_ex_coinbase_amount =
363 entry.total_new_outputs_ex_coinbase_amount;
364 stats.total_coinbase_amount = entry.total_coinbase_amount;
365 stats.total_unspendables_genesis_block =
366 entry.total_unspendables_genesis_block;
367 stats.total_unspendables_bip30 = entry.total_unspendables_bip30;
368 stats.total_unspendables_scripts = entry.total_unspendables_scripts;
369 stats.total_unspendables_unclaimed_rewards =
370 entry.total_unspendables_unclaimed_rewards;
371
372 return stats;
373}
374
376 const std::optional<interfaces::BlockKey> &block) {
377 if (!m_db->Read(DB_MUHASH, m_muhash)) {
378 // Check that the cause of the read failure is that the key does not
379 // exist. Any other errors indicate database corruption or a disk
380 // failure, and starting the index would cause further corruption.
381 if (m_db->Exists(DB_MUHASH)) {
382 return error(
383 "%s: Cannot read current %s state; index may be corrupted",
384 __func__, GetName());
385 }
386 }
387
388 if (block) {
389 DBVal entry;
390 if (!LookUpOne(*m_db, *block, entry)) {
391 return error(
392 "%s: Cannot read current %s state; index may be corrupted",
393 __func__, GetName());
394 }
395
396 uint256 out;
397 m_muhash.Finalize(out);
398 if (entry.muhash != out) {
399 return error(
400 "%s: Cannot read current %s state; index may be corrupted",
401 __func__, GetName());
402 }
403
404 m_transaction_output_count = entry.transaction_output_count;
405 m_bogo_size = entry.bogo_size;
406 m_total_amount = entry.total_amount;
407 m_total_subsidy = entry.total_subsidy;
408 m_total_unspendable_amount = entry.total_unspendable_amount;
409 m_total_prevout_spent_amount = entry.total_prevout_spent_amount;
411 entry.total_new_outputs_ex_coinbase_amount;
412 m_total_coinbase_amount = entry.total_coinbase_amount;
414 entry.total_unspendables_genesis_block;
415 m_total_unspendables_bip30 = entry.total_unspendables_bip30;
416 m_total_unspendables_scripts = entry.total_unspendables_scripts;
418 entry.total_unspendables_unclaimed_rewards;
419 }
420
421 return true;
422}
423
425 // DB_MUHASH should always be committed in a batch together with
426 // DB_BEST_BLOCK to prevent an inconsistent state of the DB.
427 batch.Write(DB_MUHASH, m_muhash);
428 return BaseIndex::CommitInternal(batch);
429}
430
431// Reverse a single block as part of a reorg
433 const CBlockIndex *pindex) {
434 CBlockUndo block_undo;
435 std::pair<BlockHash, DBVal> read_out;
436
437 const Amount block_subsidy{
438 GetBlockSubsidy(pindex->nHeight, Params().GetConsensus())};
439 m_total_subsidy -= block_subsidy;
440
441 // Ignore genesis block
442 if (pindex->nHeight > 0) {
443 if (!m_chainstate->m_blockman.UndoReadFromDisk(block_undo, *pindex)) {
444 return false;
445 }
446
447 if (!m_db->Read(DBHeightKey(pindex->nHeight - 1), read_out)) {
448 return false;
449 }
450
451 BlockHash expected_block_hash{pindex->pprev->GetBlockHash()};
452 if (read_out.first != expected_block_hash) {
453 LogPrintf("WARNING: previous block header belongs to unexpected "
454 "block %s; expected %s\n",
455 read_out.first.ToString(),
456 expected_block_hash.ToString());
457
458 if (!m_db->Read(DBHashKey(expected_block_hash), read_out)) {
459 return error("%s: previous block header not found; expected %s",
460 __func__, expected_block_hash.ToString());
461 }
462 }
463 }
464
465 // Remove the new UTXOs that were created from the block
466 for (size_t i = 0; i < block.vtx.size(); ++i) {
467 const auto &tx{block.vtx.at(i)};
468
469 for (uint32_t j = 0; j < tx->vout.size(); ++j) {
470 const CTxOut &out{tx->vout[j]};
471 COutPoint outpoint{tx->GetId(), j};
472 Coin coin{out, static_cast<uint32_t>(pindex->nHeight),
473 tx->IsCoinBase()};
474
475 // Skip unspendable coins
476 if (coin.GetTxOut().scriptPubKey.IsUnspendable()) {
477 m_total_unspendable_amount -= coin.GetTxOut().nValue;
478 m_total_unspendables_scripts -= coin.GetTxOut().nValue;
479 continue;
480 }
481
482 m_muhash.Remove(MakeUCharSpan(TxOutSer(outpoint, coin)));
483
484 if (tx->IsCoinBase()) {
485 m_total_coinbase_amount -= coin.GetTxOut().nValue;
486 } else {
488 coin.GetTxOut().nValue;
489 }
490
492 m_total_amount -= coin.GetTxOut().nValue;
493 m_bogo_size -= GetBogoSize(coin.GetTxOut().scriptPubKey);
494 }
495
496 // The coinbase tx has no undo data since no former output is spent
497 if (!tx->IsCoinBase()) {
498 const auto &tx_undo{block_undo.vtxundo.at(i - 1)};
499
500 for (size_t j = 0; j < tx_undo.vprevout.size(); ++j) {
501 Coin coin{tx_undo.vprevout[j]};
502 COutPoint outpoint{tx->vin[j].prevout.GetTxId(),
503 tx->vin[j].prevout.GetN()};
504
505 m_muhash.Insert(MakeUCharSpan(TxOutSer(outpoint, coin)));
506
507 m_total_prevout_spent_amount -= coin.GetTxOut().nValue;
508
510 m_total_amount += coin.GetTxOut().nValue;
511 m_bogo_size += GetBogoSize(coin.GetTxOut().scriptPubKey);
512 }
513 }
514 }
515
516 const Amount unclaimed_rewards{
520 m_total_unspendable_amount -= unclaimed_rewards;
521 m_total_unspendables_unclaimed_rewards -= unclaimed_rewards;
522
523 // Check that the rolled back internal values are consistent with the DB
524 // read out
525 uint256 out;
526 m_muhash.Finalize(out);
527 Assert(read_out.second.muhash == out);
528
530 read_out.second.transaction_output_count);
531 Assert(m_total_amount == read_out.second.total_amount);
532 Assert(m_bogo_size == read_out.second.bogo_size);
533 Assert(m_total_subsidy == read_out.second.total_subsidy);
535 read_out.second.total_unspendable_amount);
537 read_out.second.total_prevout_spent_amount);
539 read_out.second.total_new_outputs_ex_coinbase_amount);
540 Assert(m_total_coinbase_amount == read_out.second.total_coinbase_amount);
542 read_out.second.total_unspendables_genesis_block);
544 read_out.second.total_unspendables_bip30);
546 read_out.second.total_unspendables_scripts);
548 read_out.second.total_unspendables_unclaimed_rewards);
549
550 return true;
551}
ArgsManager gArgs
Definition: args.cpp:38
const CChainParams & Params()
Return the currently selected parameters.
Definition: chainparams.cpp:19
#define Assert(val)
Identity function.
Definition: check.h:84
fs::path GetDataDirNet() const
Get data directory path with appended network identifier.
Definition: args.h:215
Base class for indices of blockchain data.
Definition: base.h:37
virtual bool CommitInternal(CDBBatch &batch)
Virtual method called internally by Commit that can be overridden to atomically commit more index sta...
Definition: base.cpp:232
const std::string & GetName() const LIFETIMEBOUND
Get the name of the index for display in logs.
Definition: base.h:140
const std::string m_name
Definition: base.h:100
Chainstate * m_chainstate
Definition: base.h:99
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:243
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:102
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:757
A UTXO entry.
Definition: coins.h:28
bool IsCoinBase() const
Definition: coins.h:46
Amount m_total_amount
Amount m_total_prevout_spent_amount
Amount m_total_unspendables_bip30
bool CommitInternal(CDBBatch &batch) override
Virtual method called internally by Commit that can be overridden to atomically commit more index sta...
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
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:381
void Finalize(uint256 &out) noexcept
Definition: muhash.cpp:353
MuHash3072 & Insert(Span< const uint8_t > in) noexcept
Definition: muhash.cpp:376
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
bool error(const char *fmt, const Args &...args)
Definition: logging.h:263
#define LogPrintf(...)
Definition: logging.h:227
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:179
CDataStream 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:817
CAddrDb db
Definition: main.cpp:35
uint8_t ser_readdata8(Stream &s)
Definition: serialize.h:83
void ser_writedata32be(Stream &s, uint32_t obj)
Definition: serialize.h:74
#define SERIALIZE_METHODS(cls, obj)
Implement the Serialize and Unserialize methods by delegating to a single templated static method tha...
Definition: serialize.h:213
void Unserialize(Stream &, char)=delete
void ser_writedata8(Stream &s, uint8_t obj)
Lowest-level serialization and conversion.
Definition: serialize.h:55
uint32_t ser_readdata32be(Stream &s)
Definition: serialize.h:103
#define READWRITE(...)
Definition: serialize.h:166
void Serialize(Stream &, char)=delete
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:337
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())