Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1// Copyright (c) 2021-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.4//5#ifndef BITCOIN_TEST_UTIL_CHAINSTATE_H6#define BITCOIN_TEST_UTIL_CHAINSTATE_H8#include <clientversion.h>9#include <node/context.h>10#include <node/utxo_snapshot.h>11#include <rpc/blockchain.h>12#include <test/util/setup_common.h>13#include <util/byte_units.h>14#include <util/fs.h>15#include <util/log.h>16#include <validation.h>18#include <univalue.h>20inline constexpr auto NoMalleation = [](AutoFile& file, node::SnapshotMetadata& meta){};22/**23* Create and activate a UTXO snapshot, optionally providing a function to24* malleate the snapshot.25*26* If `reset_chainstate` is true, reset the original chainstate back to the genesis27* block. This allows us to simulate more realistic conditions in which a snapshot is28* loaded into an otherwise mostly-uninitialized datadir. It also allows us to test29* conditions that would otherwise cause shutdowns based on the IBD chainstate going30* past the snapshot it generated.31*/32template<typename F = decltype(NoMalleation)>33static bool34CreateAndActivateUTXOSnapshot(35TestingSetup* fixture,36F malleation = NoMalleation,37bool reset_chainstate = false,38bool in_memory_chainstate = false)39{40node::NodeContext& node = fixture->m_node;41fs::path root = fixture->m_path_root;43// Write out a snapshot to the test's tempdir.44//45int height;46WITH_LOCK(::cs_main, height = node.chainman->ActiveHeight());47fs::path snapshot_path = root / fs::u8path(tfm::format("test_snapshot.%d.dat", height));48FILE* outfile{fsbridge::fopen(snapshot_path, "wb")};49AutoFile auto_outfile{outfile};51UniValue result = CreateUTXOSnapshot(node,52node.chainman->ActiveChainstate(),53std::move(auto_outfile), // Will close auto_outfile.54snapshot_path,55snapshot_path);56LogInfo("Wrote UTXO snapshot to %s: %s",57fs::PathToString(snapshot_path.make_preferred()), result.write());59// Read the written snapshot in and then activate it.60//61FILE* infile{fsbridge::fopen(snapshot_path, "rb")};62AutoFile auto_infile{infile};63node::SnapshotMetadata metadata{node.chainman->GetParams().MessageStart()};64auto_infile >> metadata;66malleation(auto_infile, metadata);68if (reset_chainstate) {69{70// What follows is code to selectively reset chainstate data without71// disturbing the existing BlockManager instance, which is needed to72// recognize the headers chain previously generated by the chainstate we're73// removing. Without those headers, we can't activate the snapshot below.74//75// This is a stripped-down version of node::LoadChainstate which76// preserves the block index.77LOCK(::cs_main);78CBlockIndex *orig_tip = node.chainman->ActiveChainstate().m_chain.Tip();79uint256 gen_hash = node.chainman->ActiveChainstate().m_chain[0]->GetBlockHash();80node.chainman->ResetChainstates();81node.chainman->InitializeChainstate(node.mempool.get());82Chainstate& chain = node.chainman->ActiveChainstate();83Assert(node.chainman->LoadGenesisBlock());84// These cache values will be corrected shortly in `MaybeRebalanceCaches`.85chain.InitCoinsDB(1_MiB, /*in_memory=*/true, /*should_wipe=*/false);86chain.InitCoinsCache(1_MiB);87chain.CoinsTip().SetBestBlock(gen_hash);88chain.LoadChainTip();89node.chainman->MaybeRebalanceCaches();91// Reset the HAVE_DATA flags below the snapshot height, simulating92// never-having-downloaded them in the first place.93// TODO: perhaps we could improve this by using pruning to delete94// these blocks instead95CBlockIndex *pindex = orig_tip;96while (pindex && pindex != chain.m_chain.Tip()) {97// Remove all data and validity flags by just setting98// BLOCK_VALID_TREE. Also reset transaction counts and sequence99// ids that are set when blocks are received, to make test setup100// more realistic and satisfy consistency checks in101// CheckBlockIndex().102assert(pindex->IsValid(BlockStatus::BLOCK_VALID_TREE));103pindex->nStatus = BlockStatus::BLOCK_VALID_TREE;104pindex->nTx = 0;105pindex->m_chain_tx_count = 0;106pindex->nSequenceId = 0;107pindex = pindex->pprev;108}109chain.PopulateBlockIndexCandidates();110}111BlockValidationState state;112if (!node.chainman->ActiveChainstate().ActivateBestChain(state)) {113throw std::runtime_error(strprintf("ActivateBestChain failed. (%s)", state.ToString()));114}115Assert(1160 == WITH_LOCK(node.chainman->GetMutex(), return node.chainman->ActiveHeight()));117}119auto& new_active = node.chainman->ActiveChainstate();120auto* tip = new_active.m_chain.Tip();122// Disconnect a block so that the snapshot chainstate will be ahead, otherwise123// it will refuse to activate.124//125// TODO this is a unittest-specific hack, and we should probably rethink how to126// better generate/activate snapshots in unittests.127if (tip->pprev) {128new_active.m_chain.SetTip(*(tip->pprev));129}131auto res = node.chainman->ActivateSnapshot(auto_infile, metadata, in_memory_chainstate);133// Restore the old tip.134new_active.m_chain.SetTip(*tip);135return !!res;136}139#endif // BITCOIN_TEST_UTIL_CHAINSTATE_H
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.