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.
501LOCK(chainman.GetMutex());502// For completeness, we also reset the block sequence counters to503// ensure that no state which affects the ranking of tip-candidates is504// retained (even though this isn't strictly necessary).505chainman.ResetBlockSequenceCounters();506for (const auto& cs : chainman.m_chainstates) {507cs->ClearBlockIndexCandidates();508BOOST_CHECK(cs->setBlockIndexCandidates.empty());509}510chainman.LoadBlockIndex();511for (const auto& cs : chainman.m_chainstates) {512cs->PopulateBlockIndexCandidates();513}514};516// Ensure that without any assumed-valid BlockIndex entries, only the current tip is517// considered as a candidate.518reload_all_block_indexes();519BOOST_CHECK_EQUAL(cs1.setBlockIndexCandidates.size(), 1);521// Reset some region of the chain's nStatus, removing the HAVE_DATA flag.522for (int i = 0; i <= cs1.m_chain.Height(); ++i) {523LOCK(::cs_main);524auto index = cs1.m_chain[i];526// Blocks with heights in range [91, 110] are marked as missing data.527if (i < last_assumed_valid_idx && i >= assumed_valid_start_idx) {528index->nStatus = BlockStatus::BLOCK_VALID_TREE;529index->nTx = 0;530index->m_chain_tx_count = 0;531}533++num_indexes;535// Note the last fully-validated block as the expected validated tip.536if (i == (assumed_valid_start_idx - 1)) {537validated_tip = index;538}539// Note the last assumed valid block as the snapshot base540if (i == last_assumed_valid_idx - 1) {541assumed_base = index;542}543}545// Note: cs2's tip is not set when ActivateExistingSnapshot is called.546Chainstate& cs2{WITH_LOCK(::cs_main, return chainman.AddChainstate(std::make_unique<Chainstate>(nullptr, chainman.m_blockman, chainman, *assumed_base->phashBlock)))};548// Set tip of the fully validated chain to be the validated tip549cs1.m_chain.SetTip(*validated_tip);551// Set tip of the assume-valid-based chain to the assume-valid block552cs2.m_chain.SetTip(*assumed_base);554// Sanity check test variables.555BOOST_CHECK_EQUAL(num_indexes, 121); // 121 total blocks, including genesis556BOOST_CHECK_EQUAL(assumed_tip->nHeight, 120); // original chain has height 120557BOOST_CHECK_EQUAL(validated_tip->nHeight, 90); // current cs1 chain has height 90558BOOST_CHECK_EQUAL(assumed_base->nHeight, 110); // current cs2 chain has height 110560// Regenerate cs1.setBlockIndexCandidates and cs2.setBlockIndexCandidate and561// check contents below.562reload_all_block_indexes();564// The fully validated chain should only have the current validated tip565// as a candidate (block 90). Specifically:566//567// - It does not have blocks 0-89 because they contain less work than the568// chain tip.569//570// - It has block 90 because it has data and equal work to the chain tip,571// (since it is the chain tip).572//573// - It does not have blocks 91-110 because they do not contain data.574//575// - It does not have any blocks after height 110 because cs1 is a background576// chainstate, and only blocks that are ancestors of the snapshot block577// are added as candidates for the background chainstate.578BOOST_CHECK_EQUAL(cs1.setBlockIndexCandidates.size(), 1);579BOOST_CHECK_EQUAL(cs1.setBlockIndexCandidates.count(validated_tip), 1);581// The assumed-valid tolerant chain has the assumed valid base as a582// candidate, but otherwise has none of the assumed-valid (which do not583// HAVE_DATA) blocks as candidates.584//585// Specifically:586// - All blocks below height 110 are not candidates, because cs2 chain tip587// has height 110 and they have less work than it does.588//589// - Block 110 is a candidate even though it does not have data, because it590// is the snapshot block, which is assumed valid.591//592// - Blocks 111-120 are added because they have data.594// Check that block 90 is absent595BOOST_CHECK_EQUAL(cs2.setBlockIndexCandidates.count(validated_tip), 0);596// Check that block 109 is absent597BOOST_CHECK_EQUAL(cs2.setBlockIndexCandidates.count(assumed_base->pprev), 0);598// Check that block 110 is present599BOOST_CHECK_EQUAL(cs2.setBlockIndexCandidates.count(assumed_base), 1);600// Check that block 120 is present601BOOST_CHECK_EQUAL(cs2.setBlockIndexCandidates.count(assumed_tip), 1);602// Check that 11 blocks total are present.603BOOST_CHECK_EQUAL(cs2.setBlockIndexCandidates.size(), num_indexes - last_assumed_valid_idx + 1);604}606BOOST_FIXTURE_TEST_CASE(loadblockindex_invalid_descendants, TestChain100Setup)607{608LOCK(Assert(m_node.chainman)->GetMutex());609// consider the chain of blocks grand_parent <- parent <- child610// intentionally mark:611// - grand_parent: BLOCK_FAILED_VALID612// - parent: BLOCK_FAILED_CHILD613// - child: not invalid614// Test that when the block index is loaded, all blocks are marked as BLOCK_FAILED_VALID615auto* child{m_node.chainman->ActiveChain().Tip()};616auto* parent{child->pprev};617auto* grand_parent{parent->pprev};618grand_parent->nStatus = (grand_parent->nStatus | BLOCK_FAILED_VALID);619parent->nStatus = (parent->nStatus & ~BLOCK_FAILED_VALID) | BLOCK_FAILED_CHILD;620child->nStatus = (child->nStatus & ~BLOCK_FAILED_VALID);622// Reload block index to recompute block status validity flags.623m_node.chainman->LoadBlockIndex();625// check grand_parent, parent, child is marked as BLOCK_FAILED_VALID after reloading the block index626BOOST_CHECK(grand_parent->nStatus & BLOCK_FAILED_VALID);627BOOST_CHECK(parent->nStatus & BLOCK_FAILED_VALID);628BOOST_CHECK(child->nStatus & BLOCK_FAILED_VALID);629}631//! Verify that ReconsiderBlock clears failure flags for the target block, its ancestors, and descendants,632//! but not for sibling forks that diverge from a shared ancestor.633BOOST_FIXTURE_TEST_CASE(invalidate_block_and_reconsider_fork, TestChain100Setup)634{635ChainstateManager& chainman = *Assert(m_node.chainman);636Chainstate& chainstate = chainman.ActiveChainstate();638// we have a chain of 100 blocks: genesis(0) <- ... <- block98 <- block99 <- block100639CBlockIndex* block98;640CBlockIndex* block99;641CBlockIndex* block100;642{643LOCK(chainman.GetMutex());644block98 = chainman.ActiveChain()[98];645block99 = chainman.ActiveChain()[99];646block100 = chainman.ActiveChain()[100];647}649// create the following block constellation:650// genesis(0) <- ... <- block98 <- block99 <- block100651// <- block99' <- block100'652// by temporarily invalidating block99. the chain tip now falls to block98,653// mine 2 new blocks on top of block 98 (block99' and block100') and then restore block99 and block 100.654BlockValidationState state;655BOOST_REQUIRE(chainstate.InvalidateBlock(state, block99));656BOOST_REQUIRE(WITH_LOCK(cs_main, return chainman.ActiveChain().Tip()) == block98);657CScript coinbase_script = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;658for (int i = 0; i < 2; ++i) {659CreateAndProcessBlock({}, coinbase_script);660}661const CBlockIndex* fork_block99;662const CBlockIndex* fork_block100;663{664LOCK(chainman.GetMutex());665fork_block99 = chainman.ActiveChain()[99];666BOOST_REQUIRE(fork_block99->pprev == block98);667fork_block100 = chainman.ActiveChain()[100];668BOOST_REQUIRE(fork_block100->pprev == fork_block99);669}670// Restore original block99 and block100671{672LOCK(chainman.GetMutex());673chainstate.ResetBlockFailureFlags(block99);674chainman.RecalculateBestHeader();675}676chainstate.ActivateBestChain(state);677BOOST_REQUIRE(WITH_LOCK(cs_main, return chainman.ActiveChain().Tip()) == block100);679{680LOCK(chainman.GetMutex());681BOOST_CHECK(!(block100->nStatus & BLOCK_FAILED_VALID));682BOOST_CHECK(!(block99->nStatus & BLOCK_FAILED_VALID));683BOOST_CHECK(!(fork_block100->nStatus & BLOCK_FAILED_VALID));684BOOST_CHECK(!(fork_block99->nStatus & BLOCK_FAILED_VALID));685}687// Invalidate block98688BOOST_REQUIRE(chainstate.InvalidateBlock(state, block98));690{691LOCK(chainman.GetMutex());692// block98 and all descendants of block98 are marked BLOCK_FAILED_VALID693BOOST_CHECK(block98->nStatus & BLOCK_FAILED_VALID);694BOOST_CHECK(block99->nStatus & BLOCK_FAILED_VALID);695BOOST_CHECK(block100->nStatus & BLOCK_FAILED_VALID);696BOOST_CHECK(fork_block99->nStatus & BLOCK_FAILED_VALID);697BOOST_CHECK(fork_block100->nStatus & BLOCK_FAILED_VALID);698}700// Reconsider block99. ResetBlockFailureFlags clears BLOCK_FAILED_VALID from701// block99 and its ancestors (block98) and descendants (block100)702// but NOT from block99' and block100' (not a direct ancestor/descendant)703{704LOCK(chainman.GetMutex());705chainstate.ResetBlockFailureFlags(block99);706chainman.RecalculateBestHeader();707}708chainstate.ActivateBestChain(state);709{710LOCK(chainman.GetMutex());711BOOST_CHECK(!(block98->nStatus & BLOCK_FAILED_VALID));712BOOST_CHECK(!(block99->nStatus & BLOCK_FAILED_VALID));713BOOST_CHECK(!(block100->nStatus & BLOCK_FAILED_VALID));714BOOST_CHECK(fork_block99->nStatus & BLOCK_FAILED_VALID);715BOOST_CHECK(fork_block100->nStatus & BLOCK_FAILED_VALID);716}717}719//! Ensure that snapshot chainstate can be loaded when found on disk after a720//! restart, and that new blocks can be connected to both chainstates.721BOOST_FIXTURE_TEST_CASE(chainstatemanager_snapshot_init, SnapshotTestSetup)722{723ChainstateManager& chainman = *Assert(m_node.chainman);724Chainstate& bg_chainstate = chainman.ActiveChainstate();726this->SetupSnapshot();728fs::path snapshot_chainstate_dir = *node::FindAssumeutxoChainstateDir(chainman.m_options.datadir);729BOOST_CHECK(fs::exists(snapshot_chainstate_dir));730BOOST_CHECK_EQUAL(snapshot_chainstate_dir, gArgs.GetDataDirNet() / "chainstate_snapshot");732BOOST_CHECK(WITH_LOCK(::cs_main, return chainman.CurrentChainstate().m_from_snapshot_blockhash));733const uint256 snapshot_tip_hash = WITH_LOCK(chainman.GetMutex(),734return chainman.ActiveTip()->GetBlockHash());736BOOST_CHECK_EQUAL(WITH_LOCK(chainman.GetMutex(), return chainman.m_chainstates.size()), 2);738// "Rewind" the background chainstate so that its tip is not at the739// base block of the snapshot - this is so after simulating a node restart,740// it will initialize instead of attempting to complete validation.741//742// Note that this is not a realistic use of DisconnectTip().743DisconnectedBlockTransactions unused_pool{MAX_DISCONNECTED_TX_POOL_BYTES};744BlockValidationState unused_state;745{746LOCK2(::cs_main, bg_chainstate.MempoolMutex());747BOOST_CHECK(bg_chainstate.DisconnectTip(unused_state, &unused_pool));748unused_pool.clear(); // to avoid queuedTx assertion errors on teardown749}750BOOST_CHECK_EQUAL(bg_chainstate.m_chain.Height(), 109);
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.