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) 2014-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.5#include <chain.h>6#include <chainparams.h>7#include <consensus/params.h>8#include <test/util/random.h>9#include <test/util/common.h>10#include <test/util/setup_common.h>11#include <test/util/versionbits.h>12#include <util/chaintype.h>13#include <versionbits.h>14#include <versionbits_impl.h>16#include <boost/test/unit_test.hpp>18/* Define a virtual block time, one block per 10 minutes after Nov 14 2014, 0:55:36am */19static int32_t TestTime(int nHeight) { return 1415926536 + 600 * nHeight; }21class TestConditionChecker final : public VersionBitsConditionChecker22{23private:24mutable ThresholdConditionCache cache;26public:27// constructor is implicit to allow for easier initialization of vector<TestConditionChecker>28explicit(false) TestConditionChecker(const Consensus::BIP9Deployment& dep) : VersionBitsConditionChecker{dep} { }29~TestConditionChecker() override = default;31ThresholdState StateFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateFor(pindexPrev, cache); }32int StateSinceHeightFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateSinceHeightFor(pindexPrev, cache); }33void clear() { cache.clear(); }34};36namespace {37struct Deployments38{39const Consensus::BIP9Deployment normal{40.bit = 8,41.nStartTime = TestTime(10000),42.nTimeout = TestTime(20000),43.min_activation_height = 0,44.period = 1000,45.threshold = 900,46};47Consensus::BIP9Deployment always, never, delayed;48Deployments()49{50delayed = normal; delayed.min_activation_height = 15000;51always = normal; always.nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE;52never = normal; never.nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE;53}54};55}57#define CHECKERS 659class VersionBitsTester60{61FastRandomContext& m_rng;62// A fake blockchain63std::vector<CBlockIndex*> vpblock;65// Used to automatically set the top bits for manual calls to Mine()66const int32_t nVersionBase{0};68// Setup BIP9Deployment structs for the checkers69const Deployments test_deployments;71// 6 independent checkers for the same bit.72// The first one performs all checks, the second only 50%, the third only 25%, etc...73// This is to test whether lack of cached information leads to the same results.74std::vector<TestConditionChecker> checker{CHECKERS, {test_deployments.normal}};75// Another 6 that assume delayed activation76std::vector<TestConditionChecker> checker_delayed{CHECKERS, {test_deployments.delayed}};77// Another 6 that assume always active activation78std::vector<TestConditionChecker> checker_always{CHECKERS, {test_deployments.always}};79// Another 6 that assume never active activation80std::vector<TestConditionChecker> checker_never{CHECKERS, {test_deployments.never}};82// Test counter (to identify failures)83int num{1000};85public:86explicit VersionBitsTester(FastRandomContext& rng, int32_t nVersionBase=0) : m_rng{rng}, nVersionBase{nVersionBase} { }88VersionBitsTester& Reset() {89// Have each group of tests be counted by the 1000s part, starting at 100090num = num - (num % 1000) + 1000;92for (unsigned int i = 0; i < vpblock.size(); i++) {93delete vpblock[i];94}95for (unsigned int i = 0; i < CHECKERS; i++) {96checker[i].clear();97checker_delayed[i].clear();98checker_always[i].clear();99checker_never[i].clear();100}101vpblock.clear();102return *this;103}105~VersionBitsTester() {106Reset();107}109VersionBitsTester& Mine(unsigned int height, int32_t nTime, int32_t nVersion) {110while (vpblock.size() < height) {111CBlockIndex* pindex = new CBlockIndex();112pindex->nHeight = vpblock.size();113pindex->pprev = Tip();114pindex->nTime = nTime;115pindex->nVersion = (nVersionBase | nVersion);116pindex->BuildSkip();117vpblock.push_back(pindex);118}119return *this;120}122VersionBitsTester& TestStateSinceHeight(int height)123{124return TestStateSinceHeight(height, height);125}127VersionBitsTester& TestStateSinceHeight(int height, int height_delayed)128{129const CBlockIndex* tip = Tip();130for (int i = 0; i < CHECKERS; i++) {131if (m_rng.randbits(i) == 0) {132BOOST_CHECK_MESSAGE(checker[i].StateSinceHeightFor(tip) == height, strprintf("Test %i for StateSinceHeight", num));133BOOST_CHECK_MESSAGE(checker_delayed[i].StateSinceHeightFor(tip) == height_delayed, strprintf("Test %i for StateSinceHeight (delayed)", num));134BOOST_CHECK_MESSAGE(checker_always[i].StateSinceHeightFor(tip) == 0, strprintf("Test %i for StateSinceHeight (always active)", num));135BOOST_CHECK_MESSAGE(checker_never[i].StateSinceHeightFor(tip) == 0, strprintf("Test %i for StateSinceHeight (never active)", num));136}137}138num++;139return *this;140}142VersionBitsTester& TestState(ThresholdState exp)143{144return TestState(exp, exp);145}147VersionBitsTester& TestState(ThresholdState exp, ThresholdState exp_delayed)148{149if (exp != exp_delayed) {150// only expected differences are that delayed stays in locked_in longer151BOOST_CHECK_EQUAL(exp, ThresholdState::ACTIVE);152BOOST_CHECK_EQUAL(exp_delayed, ThresholdState::LOCKED_IN);153}155const CBlockIndex* pindex = Tip();156for (int i = 0; i < CHECKERS; i++) {157if (m_rng.randbits(i) == 0) {158ThresholdState got = checker[i].StateFor(pindex);159ThresholdState got_delayed = checker_delayed[i].StateFor(pindex);160ThresholdState got_always = checker_always[i].StateFor(pindex);161ThresholdState got_never = checker_never[i].StateFor(pindex);162// nHeight of the next block. If vpblock is empty, the next (ie first)163// block should be the genesis block with nHeight == 0.164int height = pindex == nullptr ? 0 : pindex->nHeight + 1;165BOOST_CHECK_MESSAGE(got == exp, strprintf("Test %i for %s height %d (got %s)", num, StateName(exp), height, StateName(got)));166BOOST_CHECK_MESSAGE(got_delayed == exp_delayed, strprintf("Test %i for %s height %d (got %s; delayed case)", num, StateName(exp_delayed), height, StateName(got_delayed)));167BOOST_CHECK_MESSAGE(got_always == ThresholdState::ACTIVE, strprintf("Test %i for ACTIVE height %d (got %s; always active case)", num, height, StateName(got_always)));168BOOST_CHECK_MESSAGE(got_never == ThresholdState::FAILED, strprintf("Test %i for FAILED height %d (got %s; never active case)", num, height, StateName(got_never)));169}170}171num++;172return *this;173}175VersionBitsTester& TestDefined() { return TestState(ThresholdState::DEFINED); }176VersionBitsTester& TestStarted() { return TestState(ThresholdState::STARTED); }177VersionBitsTester& TestLockedIn() { return TestState(ThresholdState::LOCKED_IN); }178VersionBitsTester& TestActive() { return TestState(ThresholdState::ACTIVE); }179VersionBitsTester& TestFailed() { return TestState(ThresholdState::FAILED); }181// non-delayed should be active; delayed should still be locked in182VersionBitsTester& TestActiveDelayed() { return TestState(ThresholdState::ACTIVE, ThresholdState::LOCKED_IN); }184CBlockIndex* Tip() { return vpblock.empty() ? nullptr : vpblock.back(); }185};187BOOST_FIXTURE_TEST_SUITE(versionbits_tests, BasicTestingSetup)189BOOST_AUTO_TEST_CASE(versionbits_test)190{191for (int i = 0; i < 64; i++) {192// DEFINED -> STARTED after timeout reached -> FAILED193VersionBitsTester(m_rng, VERSIONBITS_TOP_BITS).TestDefined().TestStateSinceHeight(0)194.Mine(1, TestTime(1), 0x100).TestDefined().TestStateSinceHeight(0)195.Mine(11, TestTime(11), 0x100).TestDefined().TestStateSinceHeight(0)196.Mine(989, TestTime(989), 0x100).TestDefined().TestStateSinceHeight(0)197.Mine(999, TestTime(20000), 0x100).TestDefined().TestStateSinceHeight(0) // Timeout and start time reached simultaneously198.Mine(1000, TestTime(20000), 0).TestStarted().TestStateSinceHeight(1000) // Hit started, stop signalling199.Mine(1999, TestTime(30001), 0).TestStarted().TestStateSinceHeight(1000)200.Mine(2000, TestTime(30002), 0x100).TestFailed().TestStateSinceHeight(2000) // Hit failed, start signalling again201.Mine(2001, TestTime(30003), 0x100).TestFailed().TestStateSinceHeight(2000)202.Mine(2999, TestTime(30004), 0x100).TestFailed().TestStateSinceHeight(2000)203.Mine(3000, TestTime(30005), 0x100).TestFailed().TestStateSinceHeight(2000)204.Mine(4000, TestTime(30006), 0x100).TestFailed().TestStateSinceHeight(2000)206// DEFINED -> STARTED -> FAILED207.Reset().TestDefined().TestStateSinceHeight(0)208.Mine(1, TestTime(1), 0).TestDefined().TestStateSinceHeight(0)209.Mine(1000, TestTime(10000) - 1, 0x100).TestDefined().TestStateSinceHeight(0) // One second more and it would be defined210.Mine(2000, TestTime(10000), 0x100).TestStarted().TestStateSinceHeight(2000) // So that's what happens the next period211.Mine(2051, TestTime(10010), 0).TestStarted().TestStateSinceHeight(2000) // 51 old blocks212.Mine(2950, TestTime(10020), 0x100).TestStarted().TestStateSinceHeight(2000) // 899 new blocks213.Mine(3000, TestTime(20000), 0).TestFailed().TestStateSinceHeight(3000) // 50 old blocks (so 899 out of the past 1000)214.Mine(4000, TestTime(20010), 0x100).TestFailed().TestStateSinceHeight(3000)216// DEFINED -> STARTED -> LOCKEDIN after timeout reached -> ACTIVE217.Reset().TestDefined().TestStateSinceHeight(0)218.Mine(1, TestTime(1), 0).TestDefined().TestStateSinceHeight(0)219.Mine(1000, TestTime(10000) - 1, 0x101).TestDefined().TestStateSinceHeight(0) // One second more and it would be defined220.Mine(2000, TestTime(10000), 0x101).TestStarted().TestStateSinceHeight(2000) // So that's what happens the next period221.Mine(2999, TestTime(30000), 0x100).TestStarted().TestStateSinceHeight(2000) // 999 new blocks222.Mine(3000, TestTime(30000), 0x100).TestLockedIn().TestStateSinceHeight(3000) // 1 new block (so 1000 out of the past 1000 are new)223.Mine(3999, TestTime(30001), 0).TestLockedIn().TestStateSinceHeight(3000)224.Mine(4000, TestTime(30002), 0).TestActiveDelayed().TestStateSinceHeight(4000, 3000)225.Mine(14333, TestTime(30003), 0).TestActiveDelayed().TestStateSinceHeight(4000, 3000)226.Mine(24000, TestTime(40000), 0).TestActive().TestStateSinceHeight(4000, 15000)228// DEFINED -> STARTED -> LOCKEDIN before timeout -> ACTIVE229.Reset().TestDefined()230.Mine(1, TestTime(1), 0).TestDefined().TestStateSinceHeight(0)231.Mine(1000, TestTime(10000) - 1, 0x101).TestDefined().TestStateSinceHeight(0) // One second more and it would be defined232.Mine(2000, TestTime(10000), 0x101).TestStarted().TestStateSinceHeight(2000) // So that's what happens the next period233.Mine(2050, TestTime(10010), 0x200).TestStarted().TestStateSinceHeight(2000) // 50 old blocks234.Mine(2950, TestTime(10020), 0x100).TestStarted().TestStateSinceHeight(2000) // 900 new blocks235.Mine(2999, TestTime(19999), 0x200).TestStarted().TestStateSinceHeight(2000) // 49 old blocks236.Mine(3000, TestTime(29999), 0x200).TestLockedIn().TestStateSinceHeight(3000) // 1 old block (so 900 out of the past 1000)237.Mine(3999, TestTime(30001), 0).TestLockedIn().TestStateSinceHeight(3000)238.Mine(4000, TestTime(30002), 0).TestActiveDelayed().TestStateSinceHeight(4000, 3000) // delayed will not become active until height=15000239.Mine(14333, TestTime(30003), 0).TestActiveDelayed().TestStateSinceHeight(4000, 3000)240.Mine(15000, TestTime(40000), 0).TestActive().TestStateSinceHeight(4000, 15000)241.Mine(24000, TestTime(40000), 0).TestActive().TestStateSinceHeight(4000, 15000)243// DEFINED multiple periods -> STARTED multiple periods -> FAILED244.Reset().TestDefined().TestStateSinceHeight(0)245.Mine(999, TestTime(999), 0).TestDefined().TestStateSinceHeight(0)246.Mine(1000, TestTime(1000), 0).TestDefined().TestStateSinceHeight(0)247.Mine(2000, TestTime(2000), 0).TestDefined().TestStateSinceHeight(0)248.Mine(3000, TestTime(10000), 0).TestStarted().TestStateSinceHeight(3000)249.Mine(4000, TestTime(10000), 0).TestStarted().TestStateSinceHeight(3000)250.Mine(5000, TestTime(10000), 0).TestStarted().TestStateSinceHeight(3000)
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.