| 110 | } |
| 111 | |
| 112 | bool CoinStatsIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex) |
| 113 | { |
| 114 | CBlockUndo block_undo; |
| 115 | const CAmount block_subsidy{GetBlockSubsidy(pindex->nHeight, Params().GetConsensus())}; |
| 116 | m_total_subsidy += block_subsidy; |
| 117 | |
| 118 | CAmount elements_block_fee{0}; |
| 119 | CAmount elements_coinbase_amount{0}; |
| 120 | |
| 121 | // Ignore genesis block |
| 122 | if (pindex->nHeight > 0) { |
| 123 | if (!UndoReadFromDisk(block_undo, pindex)) { |
| 124 | return false; |
| 125 | } |
| 126 | |
| 127 | std::pair<uint256, DBVal> read_out; |
| 128 | if (!m_db->Read(DBHeightKey(pindex->nHeight - 1), read_out)) { |
| 129 | return false; |
| 130 | } |
| 131 | |
| 132 | uint256 expected_block_hash{pindex->pprev->GetBlockHash()}; |
| 133 | if (read_out.first != expected_block_hash) { |
| 134 | LogPrintf("WARNING: previous block header belongs to unexpected block %s; expected %s\n", |
| 135 | read_out.first.ToString(), expected_block_hash.ToString()); |
| 136 | |
| 137 | if (!m_db->Read(DBHashKey(expected_block_hash), read_out)) { |
| 138 | return error("%s: previous block header not found; expected %s", |
| 139 | __func__, expected_block_hash.ToString()); |
| 140 | } |
| 141 | } |
| 142 | |
| 143 | // TODO: Deduplicate BIP30 related code |
| 144 | bool is_bip30_block{(pindex->nHeight == 91722 && pindex->GetBlockHash() == uint256S("0x00000000000271a2dc26e7667f8419f2e15416dc6955e5a6c6cdf3f2574dd08e")) || |
| 145 | (pindex->nHeight == 91812 && pindex->GetBlockHash() == uint256S("0x00000000000af0aed4792b1acee3d966af36cf5def14935db8de83d6f9306f2f"))}; |
| 146 | |
| 147 | // Add the new utxos created from the block |
| 148 | for (size_t i = 0; i < block.vtx.size(); ++i) { |
| 149 | const auto& tx{block.vtx.at(i)}; |
| 150 | |
| 151 | // Skip duplicate txid coinbase transactions (BIP30). |
| 152 | if (is_bip30_block && tx->IsCoinBase()) { |
| 153 | m_total_unspendable_amount += block_subsidy; |
| 154 | m_total_unspendables_bip30 += block_subsidy; |
| 155 | continue; |
| 156 | } |
| 157 | |
| 158 | for (uint32_t j = 0; j < tx->vout.size(); ++j) { |
| 159 | const CTxOut& out{tx->vout[j]}; |
| 160 | Coin coin{out, pindex->nHeight, tx->IsCoinBase()}; |
| 161 | COutPoint outpoint{tx->GetHash(), j}; |
| 162 | |
| 163 | // Skip unspendable coins |
| 164 | if (coin.out.scriptPubKey.IsUnspendable()) { |
| 165 | if (coin.out.nValue.IsExplicit()) { |
| 166 | if (coin.out.IsFee()) { |
| 167 | elements_block_fee += coin.out.nValue.GetAmount(); |
| 168 | } else { |
| 169 | m_total_unspendable_amount += coin.out.nValue.GetAmount(); |
nothing calls this directly
no test coverage detected