Repository: bitcoin/bitcoin
File: src/index/coinstatsindex.cpp (C++)

Code before:
            LogWarning("previous block header belongs to unexpected block %s; expected %s",
                      read_out.first.ToString(), expected_block_hash.ToString());

            if (!m_db->Read(DBHashKey(expected_block_hash), read_out)) {
                LogError("previous block header not found; expected %s",
                          expected_block_hash.ToString());
                return false;
            }
        }
    }

    // Remove the new UTXOs that were created from the block
    assert(block.data);
    assert(block.undo_data);
    for (size_t i = 0; i < block.data->vtx.size(); ++i) {
        const auto& tx{block.data->vtx.at(i)};

        for (uint32_t j = 0; j < tx->vout.size(); ++j) {
            const CTxOut& out{tx->vout[j]};
            COutPoint outpoint{tx->GetHash(), j};
            Coin coin{out, block.height, tx->IsCoinBase()};

            // Skip unspendable coins
            if (coin.out.scriptPubKey.IsUnspendable()) {
                m_total_unspendable_amount -= coin.out.nValue;
                m_total_unspendables_scripts -= coin.out.nValue;
                continue;
            }

            RemoveCoinHash(m_muhash, outpoint, coin);

            if (tx->IsCoinBase()) {
                m_total_coinbase_amount -= coin.out.nValue;
            } else {
                m_total_new_outputs_ex_coinbase_amount -= coin.out.nValue;
            }

            --m_transaction_output_count;
            m_total_amount -= coin.out.nValue;
            m_bogo_size -= GetBogoSize(coin.out.scriptPubKey);
        }

        // The coinbase tx has no undo data since no former output is spent
        if (!tx->IsCoinBase()) {
            const auto& tx_undo{block.undo_data->vtxundo.at(i - 1)};

            for (size_t j = 0; j < tx_undo.vprevout.size(); ++j) {
                Coin coin{tx_undo.vprevout[j]};
                COutPoint outpoint{tx->vin[j].prevout.hash, tx->vin[j].prevout.n};

                ApplyCoinHash(m_muhash, outpoint, coin);

Review comment (bug):
In b8c5bf71a4be4756740fb7b8a6a580153b007475 "index, refactor: DRY coinbase check"

This seems like a bug fix that should be in it's own commit.

Should this be decrementing `m_total_unspendable_amount` and `m_total_unspendables_bip30` to reverse what the similar code in `CustomAppend` does? This doesn't really matter once those members are removed.

Code after:
        }

        uint256 expected_block_hash{*block.prev_hash};
        if (read_out.first != expected_block_hash) {
            LogWarning("previous block header belongs to unexpected block %s; expected %s",
                      read_out.first.ToString(), expected_block_hash.ToString());

            if (!m_db->Read(DBHashKey(expected_block_hash), read_out)) {
                LogError("previous block header not found; expected %s",
                          expected_block_hash.ToString());
                return false;
            }
        }
    }

    // Roll back muhash by removing the new UTXOs that were created by the
    // block and reapplying the old UTXOs that were spent by the block
    assert(block.data);
    assert(block.undo_data);
    for (size_t i = 0; i < block.data->vtx.size(); ++i) {
        const auto& tx{block.data->vtx.at(i)};
        const bool is_coinbase{tx->IsCoinBase()};

        if (is_coinbase && IsBIP30Unspendable(block.hash, block.height)) {
            continue;
        }

        for (uint32_t j = 0; j < tx->vout.size(); ++j) {
            const CTxOut& out{tx->vout[j]};
            const COutPoint outpoint{tx->GetHash(), j};
            const Coin coin{out, block.height, is_coinbase};

            if (!coin.out.scriptPubKey.IsUnspendable()) {
                RemoveCoinHash(m_muhash, outpoint, coin);
            }
        }

        // The coinbase tx has no undo data since no former output is spent
        if (!is_coinbase) {
            const auto& tx_undo{block.undo_data->vtxundo.at(i - 1)};

            for (size_t j = 0; j < tx_undo.vprevout.size(); ++j) {
                const Coin& coin{tx_undo.vprevout[j]};
                const COutPoint outpoint{tx->vin[j].prevout.hash, tx->vin[j].prevout.n};
                ApplyCoinHash(m_muhash, outpoint, coin);
            }
        }
    }

    // Check that the rolled back muhash is consistent with the DB read out
    uint256 out;