Bitcoin ABC 0.26.3
P2P Digital Currency
Loading...
Searching...
No Matches
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) {
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) {
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
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,
111}
112
114 const CBlockIndex *pindex) {
116 const Amount block_subsidy{
117 GetBlockSubsidy(pindex->nHeight, Params().GetConsensus())};
119
120 // Ignore genesis block
121 if (pindex->nHeight > 0) {
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
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()) {
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
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.
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)",
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)",
273 }
274
275 batch.Write(DBHashKey(value.first), std::move(value.second));
276
277 db_it.Next();
278 }
279 return true;
280}
281
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
306 do {
307 CBlock block;
308
310 return error("%s: Failed to read block %s from disk", __func__,
311 iter_tip->GetBlockHash().ToString());
312 }
313
314 ReverseBlock(block, iter_tip);
315
316 iter_tip = iter_tip->GetAncestor(iter_tip->nHeight - 1);
317 } while (new_tip != iter_tip);
318 }
319
321}
322
323static bool LookUpOne(const CDBWrapper &db, const CBlockIndex *block_index,
324 DBVal &result) {
325 // First check if the result is stored under the height index and the value
326 // there matches the block hash. This should be the case if the block is on
327 // the active chain.
328 std::pair<BlockHash, DBVal> read_out;
329 if (!db.Read(DBHeightKey(block_index->nHeight), read_out)) {
330 return false;
331 }
332 if (read_out.first == block_index->GetBlockHash()) {
333 result = std::move(read_out.second);
334 return true;
335 }
336
337 // If value at the height index corresponds to an different block, the
338 // result will be stored in the hash index.
339 return db.Read(DBHashKey(block_index->GetBlockHash()), result);
340}
341
342std::optional<CCoinsStats>
345 block_index->GetBlockHash()};
346 stats.index_used = true;
347
348 DBVal entry;
349 if (!LookUpOne(*m_db, block_index, entry)) {
350 return std::nullopt;
351 }
352
353 stats.hashSerialized = entry.muhash;
354 stats.nTransactionOutputs = entry.transaction_output_count;
355 stats.nBogoSize = entry.bogo_size;
356 stats.nTotalAmount = entry.total_amount;
357 stats.total_subsidy = entry.total_subsidy;
358 stats.total_unspendable_amount = entry.total_unspendable_amount;
359 stats.total_prevout_spent_amount = entry.total_prevout_spent_amount;
360 stats.total_new_outputs_ex_coinbase_amount =
361 entry.total_new_outputs_ex_coinbase_amount;
362 stats.total_coinbase_amount = entry.total_coinbase_amount;
363 stats.total_unspendables_genesis_block =
364 entry.total_unspendables_genesis_block;
365 stats.total_unspendables_bip30 = entry.total_unspendables_bip30;
366 stats.total_unspendables_scripts = entry.total_unspendables_scripts;
367 stats.total_unspendables_unclaimed_rewards =
368 entry.total_unspendables_unclaimed_rewards;
369
370 return stats;
371}
372
374 if (!m_db->Read(DB_MUHASH, m_muhash)) {
375 // Check that the cause of the read failure is that the key does not
376 // exist. Any other errors indicate database corruption or a disk
377 // failure, and starting the index would cause further corruption.
378 if (m_db->Exists(DB_MUHASH)) {
379 return error(
380 "%s: Cannot read current %s state; index may be corrupted",
381 __func__, GetName());
382 }
383 }
384
385 if (!BaseIndex::Init()) {
386 return false;
387 }
388
389 const CBlockIndex *pindex{CurrentIndex()};
390
391 if (pindex) {
392 DBVal entry;
393 if (!LookUpOne(*m_db, pindex, entry)) {
394 return error(
395 "%s: Cannot read current %s state; index may be corrupted",
396 __func__, GetName());
397 }
398
399 uint256 out;
400 m_muhash.Finalize(out);
401 if (entry.muhash != out) {
402 return error(
403 "%s: Cannot read current %s state; index may be corrupted",
404 __func__, GetName());
405 }
406
407 m_transaction_output_count = entry.transaction_output_count;
408 m_bogo_size = entry.bogo_size;
409 m_total_amount = entry.total_amount;
410 m_total_subsidy = entry.total_subsidy;
411 m_total_unspendable_amount = entry.total_unspendable_amount;
412 m_total_prevout_spent_amount = entry.total_prevout_spent_amount;
414 entry.total_new_outputs_ex_coinbase_amount;
415 m_total_coinbase_amount = entry.total_coinbase_amount;
417 entry.total_unspendables_genesis_block;
418 m_total_unspendables_bip30 = entry.total_unspendables_bip30;
419 m_total_unspendables_scripts = entry.total_unspendables_scripts;
421 entry.total_unspendables_unclaimed_rewards;
422 }
423
424 return true;
425}
426
428 // DB_MUHASH should always be committed in a batch together with
429 // DB_BEST_BLOCK to prevent an inconsistent state of the DB.
430 batch.Write(DB_MUHASH, m_muhash);
431 return BaseIndex::CommitInternal(batch);
432}
433
434// Reverse a single block as part of a reorg
436 const CBlockIndex *pindex) {
438 std::pair<BlockHash, DBVal> read_out;
439
440 const Amount block_subsidy{
441 GetBlockSubsidy(pindex->nHeight, Params().GetConsensus())};
443
444 // Ignore genesis block
445 if (pindex->nHeight > 0) {
447 return false;
448 }
449
450 if (!m_db->Read(DBHeightKey(pindex->nHeight - 1), read_out)) {
451 return false;
452 }
453
455 if (read_out.first != expected_block_hash) {
456 LogPrintf("WARNING: previous block header belongs to unexpected "
457 "block %s; expected %s\n",
458 read_out.first.ToString(),
459 expected_block_hash.ToString());
460
461 if (!m_db->Read(DBHashKey(expected_block_hash), read_out)) {
462 return error("%s: previous block header not found; expected %s",
463 __func__, expected_block_hash.ToString());
464 }
465 }
466 }
467
468 // Remove the new UTXOs that were created from the block
469 for (size_t i = 0; i < block.vtx.size(); ++i) {
470 const auto &tx{block.vtx.at(i)};
471
472 for (uint32_t j = 0; j < tx->vout.size(); ++j) {
473 const CTxOut &out{tx->vout[j]};
474 COutPoint outpoint{tx->GetId(), j};
475 Coin coin{out, static_cast<uint32_t>(pindex->nHeight),
476 tx->IsCoinBase()};
477
478 // Skip unspendable coins
479 if (coin.GetTxOut().scriptPubKey.IsUnspendable()) {
480 m_total_unspendable_amount -= coin.GetTxOut().nValue;
481 m_total_unspendables_scripts -= coin.GetTxOut().nValue;
482 continue;
483 }
484
485 m_muhash.Remove(MakeUCharSpan(TxOutSer(outpoint, coin)));
486
487 if (tx->IsCoinBase()) {
488 m_total_coinbase_amount -= coin.GetTxOut().nValue;
489 } else {
491 coin.GetTxOut().nValue;
492 }
493
495 m_total_amount -= coin.GetTxOut().nValue;
496 m_bogo_size -= GetBogoSize(coin.GetTxOut().scriptPubKey);
497 }
498
499 // The coinbase tx has no undo data since no former output is spent
500 if (!tx->IsCoinBase()) {
501 const auto &tx_undo{block_undo.vtxundo.at(i - 1)};
502
503 for (size_t j = 0; j < tx_undo.vprevout.size(); ++j) {
504 Coin coin{tx_undo.vprevout[j]};
505 COutPoint outpoint{tx->vin[j].prevout.GetTxId(),
506 tx->vin[j].prevout.GetN()};
507
508 m_muhash.Insert(MakeUCharSpan(TxOutSer(outpoint, coin)));
509
510 m_total_prevout_spent_amount -= coin.GetTxOut().nValue;
511
513 m_total_amount += coin.GetTxOut().nValue;
514 m_bogo_size += GetBogoSize(coin.GetTxOut().scriptPubKey);
515 }
516 }
517 }
518
525
526 // Check that the rolled back internal values are consistent with the DB
527 // read out
528 uint256 out;
529 m_muhash.Finalize(out);
530 Assert(read_out.second.muhash == out);
531
533 read_out.second.transaction_output_count);
534 Assert(m_total_amount == read_out.second.total_amount);
535 Assert(m_bogo_size == read_out.second.bogo_size);
536 Assert(m_total_subsidy == read_out.second.total_subsidy);
538 read_out.second.total_unspendable_amount);
540 read_out.second.total_prevout_spent_amount);
542 read_out.second.total_new_outputs_ex_coinbase_amount);
543 Assert(m_total_coinbase_amount == read_out.second.total_coinbase_amount);
545 read_out.second.total_unspendables_genesis_block);
547 read_out.second.total_unspendables_bip30);
549 read_out.second.total_unspendables_scripts);
551 read_out.second.total_unspendables_unclaimed_rewards);
552
553 return true;
554}
ArgsManager gArgs
Definition args.cpp:38
static bool CopyHeightIndexToHashIndex(CDBIterator &db_it, CDBBatch &batch, const std::string &index_name, int start_height, int stop_height)
constexpr uint8_t DB_BLOCK_HASH
The index database stores three items for each block: the disk location of the encoded filter,...
constexpr uint8_t DB_BLOCK_HEIGHT
const CChainParams & Params()
Return the currently selected parameters.
#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
virtual bool Init()
Initialize internal state from the database and block index.
Definition base.cpp:68
virtual bool CommitInternal(CDBBatch &batch)
Virtual method called internally by Commit that can be overridden to atomically commit more index sta...
Definition base.cpp:226
Chainstate * m_chainstate
Definition base.h:82
const CBlockIndex * CurrentIndex()
Definition base.h:89
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:237
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
BlockHash GetBlockHash() const
Definition blockindex.h:146
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
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
An output of a transaction.
node::BlockManager & m_blockman
Reference to a BlockManager instance which itself is shared across all Chainstate instances.
Definition validation.h:772
A UTXO entry.
Definition coins.h:28
bool IsCoinBase() const
Definition coins.h:46
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< kernel::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
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
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 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
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
T GetRand(T nMax=std::numeric_limits< T >::max()) noexcept
Generate a uniform random integer of type T in the range [0..nMax) nMax defaults to std::numeric_limi...
Definition random.h:85
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
A BlockHash is a unqiue identifier for a block.
Definition blockhash.h:13
#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())