Reverse a single block as part of a reorg
| 403 | |
| 404 | // Reverse a single block as part of a reorg |
| 405 | bool CoinStatsIndex::ReverseBlock(const CBlock& block, const CBlockIndex* pindex) |
| 406 | { |
| 407 | CBlockUndo block_undo; |
| 408 | std::pair<uint256, DBVal> read_out; |
| 409 | |
| 410 | const CAmount block_subsidy{GetBlockSubsidy(pindex->nHeight, Params().GetConsensus())}; |
| 411 | m_total_subsidy -= block_subsidy; |
| 412 | |
| 413 | CAmount elements_block_fee{0}; |
| 414 | CAmount elements_coinbase_amount{0}; |
| 415 | |
| 416 | // Ignore genesis block |
| 417 | if (pindex->nHeight > 0) { |
| 418 | if (!UndoReadFromDisk(block_undo, pindex)) { |
| 419 | return false; |
| 420 | } |
| 421 | |
| 422 | if (!m_db->Read(DBHeightKey(pindex->nHeight - 1), read_out)) { |
| 423 | return false; |
| 424 | } |
| 425 | |
| 426 | uint256 expected_block_hash{pindex->pprev->GetBlockHash()}; |
| 427 | if (read_out.first != expected_block_hash) { |
| 428 | LogPrintf("WARNING: previous block header belongs to unexpected block %s; expected %s\n", |
| 429 | read_out.first.ToString(), expected_block_hash.ToString()); |
| 430 | |
| 431 | if (!m_db->Read(DBHashKey(expected_block_hash), read_out)) { |
| 432 | return error("%s: previous block header not found; expected %s", |
| 433 | __func__, expected_block_hash.ToString()); |
| 434 | } |
| 435 | } |
| 436 | } |
| 437 | |
| 438 | // Remove the new UTXOs that were created from the block |
| 439 | for (size_t i = 0; i < block.vtx.size(); ++i) { |
| 440 | const auto& tx{block.vtx.at(i)}; |
| 441 | |
| 442 | for (uint32_t j = 0; j < tx->vout.size(); ++j) { |
| 443 | const CTxOut& out{tx->vout[j]}; |
| 444 | COutPoint outpoint{tx->GetHash(), j}; |
| 445 | Coin coin{out, pindex->nHeight, tx->IsCoinBase()}; |
| 446 | |
| 447 | // Skip unspendable coins |
| 448 | if (coin.out.scriptPubKey.IsUnspendable()) { |
| 449 | if (coin.out.nValue.IsExplicit()) { |
| 450 | if (coin.out.IsFee()) { |
| 451 | elements_block_fee += coin.out.nValue.GetAmount(); |
| 452 | } else { |
| 453 | m_total_unspendable_amount -= coin.out.nValue.GetAmount(); |
| 454 | m_total_unspendables_scripts -= coin.out.nValue.GetAmount(); |
| 455 | } |
| 456 | } |
| 457 | continue; |
| 458 | } |
| 459 | |
| 460 | m_muhash.Remove(MakeUCharSpan(TxOutSer(outpoint, coin))); |
| 461 | |
| 462 | if (coin.out.nValue.IsExplicit()) { |
nothing calls this directly
no test coverage detected