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) The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#include <boost/test/unit_test.hpp>7#include <chain.h>8#include <test/util/setup_common.h>10#include <array>11#include <memory>13BOOST_FIXTURE_TEST_SUITE(chain_tests, BasicTestingSetup)15namespace {17const CBlockIndex* NaiveGetAncestor(const CBlockIndex* a, int height)18{19while (a->nHeight > height) {20a = a->pprev;21}22BOOST_REQUIRE_EQUAL(a->nHeight, height);23return a;24}26const CBlockIndex* NaiveLastCommonAncestor(const CBlockIndex* a, const CBlockIndex* b)27{28while (a->nHeight > b->nHeight) {29a = a->pprev;30}31while (b->nHeight > a->nHeight) {32b = b->pprev;33}34while (a != b) {35BOOST_REQUIRE_EQUAL(a->nHeight, b->nHeight);36a = a->pprev;37b = b->pprev;38}39BOOST_REQUIRE_EQUAL(a, b);40return a;41}43} // namespace45BOOST_AUTO_TEST_CASE(basic_tests)46{47// An empty chain48const CChain chain_0;49// A chain with 2 blocks50CChain chain_2;52CBlockIndex genesis;53genesis.nHeight = 0;54chain_2.SetTip(genesis);56CBlockIndex bi1;57bi1.pprev = &genesis;58bi1.nHeight = 1;59chain_2.SetTip(bi1);61BOOST_CHECK_EQUAL(chain_0.Height(), -1);62BOOST_CHECK_EQUAL(chain_2.Height(), 1);64BOOST_CHECK_EQUAL(chain_0.Tip(), nullptr);65BOOST_CHECK_EQUAL(chain_2.Tip(), &bi1);67// Indexer accessor: call with valid and invalid (low & high) values68BOOST_CHECK_EQUAL(chain_2[-1], nullptr);69BOOST_CHECK_EQUAL(chain_2[0], &genesis);70BOOST_CHECK_EQUAL(chain_2[1], &bi1);71BOOST_CHECK_EQUAL(chain_2[2], nullptr);73// Contains: call with contained & non-contained blocks74BOOST_CHECK(chain_2.Contains(genesis));75BOOST_CHECK(chain_2.Contains(bi1));76BOOST_CHECK(!chain_0.Contains(genesis));78// Call with non-tip & tip blocks79BOOST_CHECK_EQUAL(chain_2.Next(genesis), &bi1);80BOOST_CHECK_EQUAL(chain_2.Next(bi1), nullptr);81BOOST_CHECK_EQUAL(chain_0.Next(genesis), nullptr);83BOOST_CHECK_EQUAL(chain_2.Genesis(), &genesis);84BOOST_CHECK_EQUAL(chain_0.Genesis(), nullptr);85}87BOOST_AUTO_TEST_CASE(findfork_tests)88{89// Create a forking chain90const auto init_branch{[](auto& blocks, CBlockIndex* parent, int start_height) {91for (size_t i{0}; i < blocks.size(); ++i) {92blocks[i].pprev = i == 0 ? parent : &blocks[i - 1];93blocks[i].nHeight = start_height + i;94}95}};97const auto check_same{[](const CChain& chain, const auto& blocks) {98for (const auto& block : blocks) {99BOOST_CHECK_EQUAL(chain.FindFork(block), &block);100}101}};103const auto check_fork_point{[](const CChain& chain, const auto& blocks, const CBlockIndex& fork_point) {104for (const auto& block : blocks) {105BOOST_CHECK_EQUAL(chain.FindFork(block), &fork_point);106}107}};109std::array<CBlockIndex, 10> blocks_common;110init_branch(blocks_common, nullptr, 0);112std::array<CBlockIndex, 10> blocks_long;113init_branch(blocks_long, &blocks_common.back(), blocks_common.size());115std::array<CBlockIndex, 5> blocks_short;116init_branch(blocks_short, &blocks_common.back(), blocks_common.size());118// Create a chain with the longer fork119CChain chain_long;120chain_long.SetTip(blocks_long.back());121BOOST_CHECK_EQUAL(chain_long.Height(), 10 + 10 - 1);122// Test the blocks in the common part -> result should be the same123check_same(chain_long, blocks_common);124// Test the blocks on the longer fork -> result should be the same125check_same(chain_long, blocks_long);126// Test the blocks on the other shorter fork -> result should be the fork point127check_fork_point(chain_long, blocks_short, blocks_common.back());129// Create a chain with the shorter fork130CChain chain_short;131chain_short.SetTip(blocks_short.back());132BOOST_CHECK_EQUAL(chain_short.Height(), 10 + 5 - 1);133// Test the blocks in the common part -> result should be the same134check_same(chain_short, blocks_common);135// Test the blocks on the shorter fork -> result should be the same136check_same(chain_short, blocks_short);137// Test the blocks on the other longer fork -> result should be the fork point138check_fork_point(chain_short, blocks_long, blocks_common.back());140// Invalid test case. Mixing chains is not supported141CBlockIndex block_on_unrelated_chain;142BOOST_CHECK_EQUAL(chain_long.FindFork(block_on_unrelated_chain), nullptr);143}145BOOST_AUTO_TEST_CASE(chain_test)146{147FastRandomContext ctx;148std::vector<std::unique_ptr<CBlockIndex>> block_index;149// Run 10 iterations of the whole test.150for (int i = 0; i < 10; ++i) {151block_index.clear();152// Create genesis block.153auto genesis = std::make_unique<CBlockIndex>();154genesis->nHeight = 0;155block_index.push_back(std::move(genesis));156// Create 10000 more blocks.157for (int b = 0; b < 10000; ++b) {158auto new_index = std::make_unique<CBlockIndex>();159// 95% of blocks build on top of the last block; the others fork off randomly.160if (ctx.randrange(20) != 0) {161new_index->pprev = block_index.back().get();162} else {163new_index->pprev = block_index[ctx.randrange(block_index.size())].get();164}165new_index->nHeight = new_index->pprev->nHeight + 1;166new_index->BuildSkip();167block_index.push_back(std::move(new_index));168}169// Run 10000 random GetAncestor queries.170for (int q = 0; q < 10000; ++q) {171const CBlockIndex* block = block_index[ctx.randrange(block_index.size())].get();172unsigned height = ctx.randrange<unsigned>(block->nHeight + 1);173const CBlockIndex* result = block->GetAncestor(height);174BOOST_CHECK(result == NaiveGetAncestor(block, height));175}176// Run 10000 random LastCommonAncestor queries.177for (int q = 0; q < 10000; ++q) {178const CBlockIndex* block1 = block_index[ctx.randrange(block_index.size())].get();179const CBlockIndex* block2 = block_index[ctx.randrange(block_index.size())].get();180const CBlockIndex* result = LastCommonAncestor(block1, block2);181BOOST_CHECK(result == NaiveLastCommonAncestor(block1, block2));182}183}184}186BOOST_AUTO_TEST_SUITE_END()
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.