Repository: bitcoin/bitcoin
File: src/test/fuzz/utxo_snapshot.cpp (C++)

Code before:
#include <optional>
#include <vector>

using node::SnapshotMetadata;

namespace {

const std::vector<std::shared_ptr<CBlock>>* g_chain;
TestingSetup* g_setup{nullptr};

/** Sanity check the assumeutxo values hardcoded in chainparams for the fuzz target. */
void sanity_check_snapshot()
{
    Assert(g_chain && g_setup == nullptr);

    // Create a temporary chainstate manager to connect the chain to.
    const auto tmp_setup{MakeNoLogFileContext<TestingSetup>(ChainType::REGTEST, TestOpts{.setup_net = false})};
    const auto& node{tmp_setup->m_node};
    for (auto& block: *g_chain) {
        ProcessBlock(node, block);
    }

    // Connect the chain to the tmp chainman and sanity check the chainparams snapshot values.
    LOCK(cs_main);
    auto& cs{node.chainman->ActiveChainstate()};
    cs.ForceFlushStateToDisk();
    const auto stats{*Assert(kernel::ComputeUTXOStats(kernel::CoinStatsHashType::HASH_SERIALIZED, &cs.CoinsDB(), node.chainman->m_blockman))};
    const auto cp_au_data{*Assert(node.chainman->GetParams().AssumeutxoForHeight(2 * COINBASE_MATURITY))};
    Assert(stats.nHeight == cp_au_data.height);
    Assert(stats.nTransactions + 1 == cp_au_data.m_chain_tx_count); // +1 for the genesis tx.
    Assert(stats.hashBlock == cp_au_data.blockhash);
    Assert(AssumeutxoHash{stats.hashSerialized} == cp_au_data.hash_serialized);
}

template <bool INVALID>
void initialize_chain()
{
    const auto params{CreateChainParams(ArgsManager{}, ChainType::REGTEST)};
    static const auto chain{CreateBlockChain(2 * COINBASE_MATURITY, *params)};
    g_chain = &chain;
    SetMockTime(chain.back()->Time());

    // Make sure we can generate a valid snapshot.
    sanity_check_snapshot();

    static const auto setup{
        MakeNoLogFileContext<TestingSetup>(ChainType::REGTEST,
                                           TestOpts{
                                               .setup_net = false,
                                               .setup_validation_interface = false,
                                               .min_validation_cache = true,

Review comment (performance):
Why are we wiping the cache here? We only compute stats from `CoinsDB()`, not the in-memory cache, so a non-wiping flush (`wipe_cache=false`) should be enough for consistency (?)

Code after:
#include <optional>
#include <vector>

using node::SnapshotMetadata;

namespace {

const std::vector<std::shared_ptr<CBlock>>* g_chain;
TestingSetup* g_setup{nullptr};

/** Sanity check the assumeutxo values hardcoded in chainparams for the fuzz target. */
void sanity_check_snapshot()
{
    Assert(g_chain && g_setup == nullptr);

    // Create a temporary chainstate manager to connect the chain to.
    const auto tmp_setup{MakeNoLogFileContext<TestingSetup>(ChainType::REGTEST, TestOpts{.setup_net = false})};
    const auto& node{tmp_setup->m_node};
    for (auto& block: *g_chain) {
        ProcessBlock(node, block);
    }

    // Connect the chain to the tmp chainman and sanity check the chainparams snapshot values.
    LOCK(cs_main);
    auto& cs{node.chainman->ActiveChainstate()};
    cs.ForceFlushStateToDisk(/*wipe_cache=*/false);
    const auto stats{*Assert(kernel::ComputeUTXOStats(kernel::CoinStatsHashType::HASH_SERIALIZED, &cs.CoinsDB(), node.chainman->m_blockman))};
    const auto cp_au_data{*Assert(node.chainman->GetParams().AssumeutxoForHeight(2 * COINBASE_MATURITY))};
    Assert(stats.nHeight == cp_au_data.height);
    Assert(stats.nTransactions + 1 == cp_au_data.m_chain_tx_count); // +1 for the genesis tx.
    Assert(stats.hashBlock == cp_au_data.blockhash);
    Assert(AssumeutxoHash{stats.hashSerialized} == cp_au_data.hash_serialized);
}

template <bool INVALID>
void initialize_chain()
{
    const auto params{CreateChainParams(ArgsManager{}, ChainType::REGTEST)};
    static const auto chain{CreateBlockChain(2 * COINBASE_MATURITY, *params)};
    g_chain = &chain;
    SetMockTime(chain.back()->Time());

    // Make sure we can generate a valid snapshot.
    sanity_check_snapshot();

    static const auto setup{
        MakeNoLogFileContext<TestingSetup>(ChainType::REGTEST,
                                           TestOpts{
                                               .setup_net = false,
                                               .setup_validation_interface = false,
                                               .min_validation_cache = true,