Bitcoin ABC  0.28.12
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 <index/coinstatsindex.h>
6 
7 #include <chainparams.h>
8 #include <coins.h>
9 #include <consensus/amount.h>
10 #include <crypto/muhash.h>
11 #include <node/blockstorage.h>
12 #include <primitives/blockhash.h>
13 #include <serialize.h>
14 #include <txdb.h>
15 #include <undo.h>
16 #include <util/check.h>
17 #include <validation.h>
18 
19 using node::CCoinsStats;
20 using node::GetBogoSize;
22 using node::TxOutSer;
24 
25 static constexpr char DB_BLOCK_HASH = 's';
26 static constexpr char DB_BLOCK_HEIGHT = 't';
27 static constexpr char DB_MUHASH = 'M';
28 
29 namespace {
30 
31 struct 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 
63 struct 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  char prefix{static_cast<char>(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 
83 struct DBHashKey {
84  BlockHash block_hash;
85 
86  explicit DBHashKey(const BlockHash &hash_in) : block_hash(hash_in) {}
87 
88  SERIALIZE_METHODS(DBHashKey, obj) {
89  char 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 
102 std::unique_ptr<CoinStatsIndex> g_coin_stats_index;
103 
104 CoinStatsIndex::CoinStatsIndex(size_t n_cache_size, bool f_memory,
105  bool f_wipe) {
106  fs::path path{gArgs.GetDataDirNet() / "indexes" / "coinstats"};
108 
109  m_db = std::make_unique<CoinStatsIndex::DB>(path / "db", n_cache_size,
110  f_memory, f_wipe);
111 }
112 
114  const CBlockIndex *pindex) {
115  CBlockUndo block_undo;
116  const Amount block_subsidy{
117  GetBlockSubsidy(pindex->nHeight, Params().GetConsensus())};
118  m_total_subsidy += block_subsidy;
119 
120  // Ignore genesis block
121  if (pindex->nHeight > 0) {
122  if (!UndoReadFromDisk(block_undo, pindex)) {
123  return false;
124  }
125 
126  std::pair<BlockHash, DBVal> read_out;
127  if (!m_db->Read(DBHeightKey(pindex->nHeight - 1), read_out)) {
128  return false;
129  }
130 
131  BlockHash expected_block_hash{pindex->pprev->GetBlockHash()};
132  if (read_out.first != expected_block_hash) {
133  LogPrintf("WARNING: previous block header belongs to unexpected "
134  "block %s; expected %s\n",
135  read_out.first.ToString(),
136  expected_block_hash.ToString());
137 
138  if (!m_db->Read(DBHashKey(expected_block_hash), read_out)) {
139  return error("%s: previous block header not found; expected %s",
140  __func__, expected_block_hash.ToString());
141  }
142  }
143 
144  // TODO: Deduplicate BIP30 related code
145  bool is_bip30_block{
146  (pindex->nHeight == 91722 &&
147  pindex->GetBlockHash() ==
148  BlockHash{uint256S("0x00000000000271a2dc26e7667f8419f2e15416dc"
149  "6955e5a6c6cdf3f2574dd08e")}) ||
150  (pindex->nHeight == 91812 &&
151  pindex->GetBlockHash() ==
152  BlockHash{uint256S("0x00000000000af0aed4792b1acee3d966af36cf5d"
153  "ef14935db8de83d6f9306f2f")})};
154 
155  // Add the new utxos created from the block
156  for (size_t i = 0; i < block.vtx.size(); ++i) {
157  const auto &tx{block.vtx.at(i)};
158 
159  // Skip duplicate txid coinbase transactions (BIP30).
160  if (is_bip30_block && tx->IsCoinBase()) {
161  m_total_unspendable_amount += block_subsidy;
162  m_total_unspendables_bip30 += block_subsidy;
163  continue;
164  }
165 
166  for (uint32_t j = 0; j < tx->vout.size(); ++j) {
167  const CTxOut &out{tx->vout[j]};
168  Coin coin{out, static_cast<uint32_t>(pindex->nHeight),
169  tx->IsCoinBase()};
170  COutPoint outpoint{tx->GetId(), j};
171 
172  // Skip unspendable coins
173  if (coin.GetTxOut().scriptPubKey.IsUnspendable()) {
174  m_total_unspendable_amount += coin.GetTxOut().nValue;
175  m_total_unspendables_scripts += coin.GetTxOut().nValue;
176  continue;
177  }
178 
179  m_muhash.Insert(MakeUCharSpan(TxOutSer(outpoint, coin)));
180 
181  if (tx->IsCoinBase()) {
182  m_total_coinbase_amount += coin.GetTxOut().nValue;
183  } else {
185  coin.GetTxOut().nValue;
186  }
187 
189  m_total_amount += coin.GetTxOut().nValue;
190  m_bogo_size += GetBogoSize(coin.GetTxOut().scriptPubKey);
191  }
192 
193  // The coinbase tx has no undo data since no former output is spent
194  if (!tx->IsCoinBase()) {
195  const auto &tx_undo{block_undo.vtxundo.at(i - 1)};
196 
197  for (size_t j = 0; j < tx_undo.vprevout.size(); ++j) {
198  Coin coin{tx_undo.vprevout[j]};
199  COutPoint outpoint{tx->vin[j].prevout.GetTxId(),
200  tx->vin[j].prevout.GetN()};
201 
202  m_muhash.Remove(MakeUCharSpan(TxOutSer(outpoint, coin)));
203 
204  m_total_prevout_spent_amount += coin.GetTxOut().nValue;
205 
207  m_total_amount -= coin.GetTxOut().nValue;
208  m_bogo_size -= GetBogoSize(coin.GetTxOut().scriptPubKey);
209  }
210  }
211  }
212  } else {
213  // genesis block
214  m_total_unspendable_amount += block_subsidy;
215  m_total_unspendables_genesis_block += block_subsidy;
216  }
217 
218  // If spent prevouts + block subsidy are still a higher amount than
219  // new outputs + coinbase + current unspendable amount this means
220  // the miner did not claim the full block reward. Unclaimed block
221  // rewards are also unspendable.
222  const Amount unclaimed_rewards{
226  m_total_unspendable_amount += unclaimed_rewards;
227  m_total_unspendables_unclaimed_rewards += unclaimed_rewards;
228 
229  std::pair<BlockHash, DBVal> value;
230  value.first = pindex->GetBlockHash();
231  value.second.transaction_output_count = m_transaction_output_count;
232  value.second.bogo_size = m_bogo_size;
233  value.second.total_amount = m_total_amount;
234  value.second.total_subsidy = m_total_subsidy;
235  value.second.total_unspendable_amount = m_total_unspendable_amount;
236  value.second.total_prevout_spent_amount = m_total_prevout_spent_amount;
237  value.second.total_new_outputs_ex_coinbase_amount =
239  value.second.total_coinbase_amount = m_total_coinbase_amount;
240  value.second.total_unspendables_genesis_block =
242  value.second.total_unspendables_bip30 = m_total_unspendables_bip30;
243  value.second.total_unspendables_scripts = m_total_unspendables_scripts;
244  value.second.total_unspendables_unclaimed_rewards =
246 
247  uint256 out;
248  m_muhash.Finalize(out);
249  value.second.muhash = out;
250 
251  // Intentionally do not update DB_MUHASH here so it stays in sync with
252  // DB_BEST_BLOCK, and the index is not corrupted if there is an unclean
253  // shutdown.
254  return m_db->Write(DBHeightKey(pindex->nHeight), value);
255 }
256 
258  const std::string &index_name,
259  int start_height, int stop_height) {
260  DBHeightKey key{start_height};
261  db_it.Seek(key);
262 
263  for (int height = start_height; height <= stop_height; ++height) {
264  if (!db_it.GetKey(key) || key.height != height) {
265  return error("%s: unexpected key in %s: expected (%c, %d)",
266  __func__, index_name, DB_BLOCK_HEIGHT, height);
267  }
268 
269  std::pair<BlockHash, DBVal> value;
270  if (!db_it.GetValue(value)) {
271  return error("%s: unable to read value in %s at key (%c, %d)",
272  __func__, index_name, DB_BLOCK_HEIGHT, height);
273  }
274 
275  batch.Write(DBHashKey(value.first), std::move(value.second));
276 
277  db_it.Next();
278  }
279  return true;
280 }
281 
282 bool CoinStatsIndex::Rewind(const CBlockIndex *current_tip,
283  const CBlockIndex *new_tip) {
284  assert(current_tip->GetAncestor(new_tip->nHeight) == new_tip);
285 
286  CDBBatch batch(*m_db);
287  std::unique_ptr<CDBIterator> db_it(m_db->NewIterator());
288 
289  // During a reorg, we need to copy all hash digests for blocks that are
290  // getting disconnected from the height index to the hash index so we can
291  // still find them when the height index entries are overwritten.
292  if (!CopyHeightIndexToHashIndex(*db_it, batch, m_name, new_tip->nHeight,
293  current_tip->nHeight)) {
294  return false;
295  }
296 
297  if (!m_db->WriteBatch(batch)) {
298  return false;
299  }
300 
301  {
302  LOCK(cs_main);
304  current_tip->GetBlockHash())};
305  const auto &consensus_params{Params().GetConsensus()};
306 
307  do {
308  CBlock block;
309 
310  if (!ReadBlockFromDisk(block, iter_tip, consensus_params)) {
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 
324 static bool LookUpOne(const CDBWrapper &db, const CBlockIndex *block_index,
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_index->nHeight), read_out)) {
331  return false;
332  }
333  if (read_out.first == block_index->GetBlockHash()) {
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_index->GetBlockHash()), result);
341 }
342 
343 std::optional<CCoinsStats>
344 CoinStatsIndex::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, entry)) {
351  return std::nullopt;
352  }
353 
354  stats.hashSerialized = entry.muhash;
355  stats.nTransactionOutputs = entry.transaction_output_count;
356  stats.nBogoSize = entry.bogo_size;
357  stats.nTotalAmount = entry.total_amount;
358  stats.total_subsidy = entry.total_subsidy;
359  stats.total_unspendable_amount = entry.total_unspendable_amount;
360  stats.total_prevout_spent_amount = entry.total_prevout_spent_amount;
361  stats.total_new_outputs_ex_coinbase_amount =
362  entry.total_new_outputs_ex_coinbase_amount;
363  stats.total_coinbase_amount = entry.total_coinbase_amount;
364  stats.total_unspendables_genesis_block =
365  entry.total_unspendables_genesis_block;
366  stats.total_unspendables_bip30 = entry.total_unspendables_bip30;
367  stats.total_unspendables_scripts = entry.total_unspendables_scripts;
368  stats.total_unspendables_unclaimed_rewards =
369  entry.total_unspendables_unclaimed_rewards;
370 
371  return stats;
372 }
373 
375  if (!m_db->Read(DB_MUHASH, m_muhash)) {
376  // Check that the cause of the read failure is that the key does not
377  // exist. Any other errors indicate database corruption or a disk
378  // failure, and starting the index would cause further corruption.
379  if (m_db->Exists(DB_MUHASH)) {
380  return error(
381  "%s: Cannot read current %s state; index may be corrupted",
382  __func__, GetName());
383  }
384  }
385 
386  if (!BaseIndex::Init()) {
387  return false;
388  }
389 
390  const CBlockIndex *pindex{CurrentIndex()};
391 
392  if (pindex) {
393  DBVal entry;
394  if (!LookUpOne(*m_db, pindex, entry)) {
395  return error(
396  "%s: Cannot read current %s state; index may be corrupted",
397  __func__, GetName());
398  }
399 
400  uint256 out;
401  m_muhash.Finalize(out);
402  if (entry.muhash != out) {
403  return error(
404  "%s: Cannot read current %s state; index may be corrupted",
405  __func__, GetName());
406  }
407 
408  m_transaction_output_count = entry.transaction_output_count;
409  m_bogo_size = entry.bogo_size;
410  m_total_amount = entry.total_amount;
411  m_total_subsidy = entry.total_subsidy;
412  m_total_unspendable_amount = entry.total_unspendable_amount;
413  m_total_prevout_spent_amount = entry.total_prevout_spent_amount;
415  entry.total_new_outputs_ex_coinbase_amount;
416  m_total_coinbase_amount = entry.total_coinbase_amount;
418  entry.total_unspendables_genesis_block;
419  m_total_unspendables_bip30 = entry.total_unspendables_bip30;
420  m_total_unspendables_scripts = entry.total_unspendables_scripts;
422  entry.total_unspendables_unclaimed_rewards;
423  }
424 
425  return true;
426 }
427 
429  // DB_MUHASH should always be committed in a batch together with
430  // DB_BEST_BLOCK to prevent an inconsistent state of the DB.
431  batch.Write(DB_MUHASH, m_muhash);
432  return BaseIndex::CommitInternal(batch);
433 }
434 
435 // Reverse a single block as part of a reorg
437  const CBlockIndex *pindex) {
438  CBlockUndo block_undo;
439  std::pair<BlockHash, DBVal> read_out;
440 
441  const Amount block_subsidy{
442  GetBlockSubsidy(pindex->nHeight, Params().GetConsensus())};
443  m_total_subsidy -= block_subsidy;
444 
445  // Ignore genesis block
446  if (pindex->nHeight > 0) {
447  if (!UndoReadFromDisk(block_undo, pindex)) {
448  return false;
449  }
450 
451  if (!m_db->Read(DBHeightKey(pindex->nHeight - 1), read_out)) {
452  return false;
453  }
454 
455  BlockHash expected_block_hash{pindex->pprev->GetBlockHash()};
456  if (read_out.first != expected_block_hash) {
457  LogPrintf("WARNING: previous block header belongs to unexpected "
458  "block %s; expected %s\n",
459  read_out.first.ToString(),
460  expected_block_hash.ToString());
461 
462  if (!m_db->Read(DBHashKey(expected_block_hash), read_out)) {
463  return error("%s: previous block header not found; expected %s",
464  __func__, expected_block_hash.ToString());
465  }
466  }
467  }
468 
469  // Remove the new UTXOs that were created from the block
470  for (size_t i = 0; i < block.vtx.size(); ++i) {
471  const auto &tx{block.vtx.at(i)};
472 
473  for (uint32_t j = 0; j < tx->vout.size(); ++j) {
474  const CTxOut &out{tx->vout[j]};
475  COutPoint outpoint{tx->GetId(), j};
476  Coin coin{out, static_cast<uint32_t>(pindex->nHeight),
477  tx->IsCoinBase()};
478 
479  // Skip unspendable coins
480  if (coin.GetTxOut().scriptPubKey.IsUnspendable()) {
481  m_total_unspendable_amount -= coin.GetTxOut().nValue;
482  m_total_unspendables_scripts -= coin.GetTxOut().nValue;
483  continue;
484  }
485 
486  m_muhash.Remove(MakeUCharSpan(TxOutSer(outpoint, coin)));
487 
488  if (tx->IsCoinBase()) {
489  m_total_coinbase_amount -= coin.GetTxOut().nValue;
490  } else {
492  coin.GetTxOut().nValue;
493  }
494 
496  m_total_amount -= coin.GetTxOut().nValue;
497  m_bogo_size -= GetBogoSize(coin.GetTxOut().scriptPubKey);
498  }
499 
500  // The coinbase tx has no undo data since no former output is spent
501  if (!tx->IsCoinBase()) {
502  const auto &tx_undo{block_undo.vtxundo.at(i - 1)};
503 
504  for (size_t j = 0; j < tx_undo.vprevout.size(); ++j) {
505  Coin coin{tx_undo.vprevout[j]};
506  COutPoint outpoint{tx->vin[j].prevout.GetTxId(),
507  tx->vin[j].prevout.GetN()};
508 
509  m_muhash.Insert(MakeUCharSpan(TxOutSer(outpoint, coin)));
510 
511  m_total_prevout_spent_amount -= coin.GetTxOut().nValue;
512 
514  m_total_amount += coin.GetTxOut().nValue;
515  m_bogo_size += GetBogoSize(coin.GetTxOut().scriptPubKey);
516  }
517  }
518  }
519 
520  const Amount unclaimed_rewards{
524  m_total_unspendable_amount -= unclaimed_rewards;
525  m_total_unspendables_unclaimed_rewards -= unclaimed_rewards;
526 
527  // Check that the rolled back internal values are consistent with the DB
528  // read out
529  uint256 out;
530  m_muhash.Finalize(out);
531  Assert(read_out.second.muhash == out);
532 
534  read_out.second.transaction_output_count);
535  Assert(m_total_amount == read_out.second.total_amount);
536  Assert(m_bogo_size == read_out.second.bogo_size);
537  Assert(m_total_subsidy == read_out.second.total_subsidy);
539  read_out.second.total_unspendable_amount);
541  read_out.second.total_prevout_spent_amount);
543  read_out.second.total_new_outputs_ex_coinbase_amount);
544  Assert(m_total_coinbase_amount == read_out.second.total_coinbase_amount);
546  read_out.second.total_unspendables_genesis_block);
548  read_out.second.total_unspendables_bip30);
550  read_out.second.total_unspendables_scripts);
552  read_out.second.total_unspendables_unclaimed_rewards);
553 
554  return true;
555 }
const CChainParams & Params()
Return the currently selected parameters.
#define Assert(val)
Identity function.
Definition: check.h:84
const fs::path & GetDataDirNet() const
Get data directory path with appended network identifier.
Definition: system.h:268
virtual bool Init()
Initialize internal state from the database and block index.
Definition: base.cpp:58
virtual bool CommitInternal(CDBBatch &batch)
Virtual method called internally by Commit that can be overridden to atomically commit more index sta...
Definition: base.cpp:217
const CBlockIndex * CurrentIndex()
Definition: base.h:87
Chainstate * m_chainstate
Definition: base.h:80
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:228
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:26
CBlockIndex * pprev
pointer to the index of the predecessor of this block
Definition: blockindex.h:33
CBlockIndex * GetAncestor(int height)
Efficiently find an ancestor of this block.
Definition: blockindex.cpp:71
BlockHash GetBlockHash() const
Definition: blockindex.h:147
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: blockindex.h:39
Undo information for a CBlock.
Definition: undo.h:73
std::vector< CTxUndo > vtxundo
Definition: undo.h:76
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:86
Batch of changes queued to be written to a CDBWrapper.
Definition: dbwrapper.h:54
void Write(const K &key, const V &value)
Definition: dbwrapper.h:79
bool GetValue(V &value)
Definition: dbwrapper.h:160
bool GetKey(K &key)
Definition: dbwrapper.h:149
void Seek(const K &key)
Definition: dbwrapper.h:139
void Next()
Definition: dbwrapper.cpp:257
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:20
const TxId & GetTxId() const
Definition: transaction.h:35
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:726
A UTXO entry.
Definition: coins.h:27
bool IsCoinBase() const
Definition: coins.h:45
Amount m_total_amount
Amount m_total_prevout_spent_amount
Amount m_total_unspendables_bip30
const char * GetName() const override
Get the name of the index for display in logs.
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
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
CoinStatsIndex(size_t n_cache_size, bool f_memory=false, bool f_wipe=false)
std::optional< node::CCoinsStats > LookUpStats(const CBlockIndex *block_index) const
std::string m_name
Amount m_total_unspendables_scripts
bool WriteBlock(const CBlock &block, const CBlockIndex *pindex) override
Write update index entries for a newly connected block.
Amount m_total_new_outputs_ex_coinbase_amount
Amount m_total_unspendable_amount
Amount m_total_unspendables_unclaimed_rewards
Amount m_total_subsidy
bool Init() override
Initialize internal state from the database and block index.
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
CBlockIndex * LookupBlockIndex(const BlockHash &hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
256-bit opaque blob.
Definition: uint256.h:127
static bool LookUpOne(const CDBWrapper &db, const CBlockIndex *block_index, DBVal &result)
static constexpr char DB_BLOCK_HASH
std::unique_ptr< CoinStatsIndex > g_coin_stats_index
The global UTXO set hash object.
static constexpr char DB_BLOCK_HEIGHT
static bool CopyHeightIndexToHashIndex(CDBIterator &db_it, CDBBatch &batch, const std::string &index_name, int start_height, int stop_height)
static constexpr char DB_MUHASH
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: cs_main.cpp:7
#define LogPrintf(...)
Definition: logging.h:206
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
bool ReadBlockFromDisk(CBlock &block, const FlatFilePos &pos, const Consensus::Params &params)
Functions for disk access for blocks.
CDataStream TxOutSer(const COutPoint &outpoint, const Coin &coin)
Definition: coinstats.cpp:31
uint64_t GetBogoSize(const CScript &script_pub_key)
Definition: coinstats.cpp:25
bool UndoReadFromDisk(CBlockUndo &blockundo, const CBlockIndex *pindex)
const char * prefix
Definition: rest.cpp:819
CAddrDb db
Definition: main.cpp:35
uint8_t ser_readdata8(Stream &s)
Definition: serialize.h:98
void ser_writedata32be(Stream &s, uint32_t obj)
Definition: serialize.h:89
#define SERIALIZE_METHODS(cls, obj)
Implement the Serialize and Unserialize methods by delegating to a single templated static method tha...
Definition: serialize.h:227
void Serialize(Stream &s, char a)
Definition: serialize.h:242
void Unserialize(Stream &s, char &a)
Definition: serialize.h:294
void ser_writedata8(Stream &s, uint8_t obj)
Lowest-level serialization and conversion.
Definition: serialize.h:70
uint32_t ser_readdata32be(Stream &s)
Definition: serialize.h:118
#define READWRITE(...)
Definition: serialize.h:180
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:307
Definition: amount.h:19
A BlockHash is a unqiue identifier for a block.
Definition: blockhash.h:13
#define LOCK(cs)
Definition: sync.h:306
ArgsManager gArgs
Definition: system.cpp:80
bool error(const char *fmt, const Args &...args)
Definition: system.h:45
uint256 uint256S(const char *str)
uint256 from const char *.
Definition: uint256.h:141
Amount GetBlockSubsidy(int nHeight, const Consensus::Params &consensusParams)
assert(!tx.IsCoinBase())