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 <test/util/random.h>7#include <test/util/setup_common.h>9#include <algorithm>10#include <vector>11#include <utility>13#include <boost/test/unit_test.hpp>15#define SKIPLIST_LENGTH 30000017BOOST_FIXTURE_TEST_SUITE(skiplist_tests, BasicTestingSetup)19BOOST_AUTO_TEST_CASE(skiplist_test)20{21std::vector<CBlockIndex> vIndex(SKIPLIST_LENGTH);23for (int i=0; i<SKIPLIST_LENGTH; i++) {24vIndex[i].nHeight = i;25vIndex[i].pprev = (i == 0) ? nullptr : &vIndex[i - 1];26vIndex[i].BuildSkip();27}29for (int i=0; i<SKIPLIST_LENGTH; i++) {30if (i > 0) {31BOOST_CHECK(vIndex[i].pskip == &vIndex[vIndex[i].pskip->nHeight]);32BOOST_CHECK(vIndex[i].pskip->nHeight < i);33} else {34BOOST_CHECK(vIndex[i].pskip == nullptr);35}36}38for (int i=0; i < 1000; i++) {39int from = m_rng.randrange(SKIPLIST_LENGTH - 1);40int to = m_rng.randrange(from + 1);42BOOST_CHECK(vIndex[SKIPLIST_LENGTH - 1].GetAncestor(from) == &vIndex[from]);43BOOST_CHECK(vIndex[from].GetAncestor(to) == &vIndex[to]);44BOOST_CHECK(vIndex[from].GetAncestor(0) == vIndex.data());45}46}48BOOST_AUTO_TEST_CASE(getlocator_test)49{50// Build a main chain 100000 blocks long.51std::vector<uint256> vHashMain(100000);52std::vector<CBlockIndex> vBlocksMain(100000);53for (unsigned int i=0; i<vBlocksMain.size(); i++) {54vHashMain[i] = ArithToUint256(i); // Set the hash equal to the height, so we can quickly check the distances.55vBlocksMain[i].nHeight = i;56vBlocksMain[i].pprev = i ? &vBlocksMain[i - 1] : nullptr;57vBlocksMain[i].phashBlock = &vHashMain[i];58vBlocksMain[i].BuildSkip();59BOOST_CHECK_EQUAL((int)UintToArith256(vBlocksMain[i].GetBlockHash()).GetLow64(), vBlocksMain[i].nHeight);60BOOST_CHECK(vBlocksMain[i].pprev == nullptr || vBlocksMain[i].nHeight == vBlocksMain[i].pprev->nHeight + 1);61}63// Build a branch that splits off at block 49999, 50000 blocks long.64std::vector<uint256> vHashSide(50000);65std::vector<CBlockIndex> vBlocksSide(50000);66for (unsigned int i=0; i<vBlocksSide.size(); i++) {67vHashSide[i] = ArithToUint256(i + 50000 + (arith_uint256(1) << 128)); // Add 1<<128 to the hashes, so GetLow64() still returns the height.68vBlocksSide[i].nHeight = i + 50000;69vBlocksSide[i].pprev = i ? &vBlocksSide[i - 1] : (vBlocksMain.data()+49999);70vBlocksSide[i].phashBlock = &vHashSide[i];71vBlocksSide[i].BuildSkip();72BOOST_CHECK_EQUAL((int)UintToArith256(vBlocksSide[i].GetBlockHash()).GetLow64(), vBlocksSide[i].nHeight);73BOOST_CHECK(vBlocksSide[i].pprev == nullptr || vBlocksSide[i].nHeight == vBlocksSide[i].pprev->nHeight + 1);74}76// Build a CChain for the main branch.77CChain chain;78chain.SetTip(vBlocksMain.back());80// Test 100 random starting points for locators.81for (int n=0; n<100; n++) {82int r = m_rng.randrange(150000);83CBlockIndex* tip = (r < 100000) ? &vBlocksMain[r] : &vBlocksSide[r - 100000];84CBlockLocator locator = GetLocator(tip);86// The first result must be the block itself, the last one must be genesis.87BOOST_CHECK(locator.vHave.front() == tip->GetBlockHash());88BOOST_CHECK(locator.vHave.back() == vBlocksMain[0].GetBlockHash());90// Entries 1 through 11 (inclusive) go back one step each.91for (unsigned int i = 1; i < 12 && i < locator.vHave.size() - 1; i++) {92BOOST_CHECK_EQUAL(UintToArith256(locator.vHave[i]).GetLow64(), tip->nHeight - i);93}95// The further ones (excluding the last one) go back with exponential steps.96unsigned int dist = 2;97for (unsigned int i = 12; i < locator.vHave.size() - 1; i++) {98BOOST_CHECK_EQUAL(UintToArith256(locator.vHave[i - 1]).GetLow64() - UintToArith256(locator.vHave[i]).GetLow64(), dist);99dist *= 2;100}101}102}104BOOST_AUTO_TEST_CASE(findearliestatleast_test)105{106std::vector<uint256> vHashMain(100000);107std::vector<CBlockIndex> vBlocksMain(100000);108for (unsigned int i=0; i<vBlocksMain.size(); i++) {109vHashMain[i] = ArithToUint256(i); // Set the hash equal to the height110vBlocksMain[i].nHeight = i;111vBlocksMain[i].pprev = i ? &vBlocksMain[i - 1] : nullptr;112vBlocksMain[i].phashBlock = &vHashMain[i];113vBlocksMain[i].BuildSkip();114if (i < 10) {115vBlocksMain[i].nTime = i;116vBlocksMain[i].nTimeMax = i;117} else {118// randomly choose something in the range [MTP, MTP*2]119int64_t medianTimePast = vBlocksMain[i].GetMedianTimePast();120int r{int(m_rng.randrange(medianTimePast))};121vBlocksMain[i].nTime = uint32_t(r + medianTimePast);122vBlocksMain[i].nTimeMax = std::max(vBlocksMain[i].nTime, vBlocksMain[i-1].nTimeMax);123}124}125// Check that we set nTimeMax up correctly.126unsigned int curTimeMax = 0;127for (unsigned int i=0; i<vBlocksMain.size(); ++i) {128curTimeMax = std::max(curTimeMax, vBlocksMain[i].nTime);129BOOST_CHECK(curTimeMax == vBlocksMain[i].nTimeMax);130}132// Build a CChain for the main branch.133CChain chain;134chain.SetTip(vBlocksMain.back());136// Verify that FindEarliestAtLeast is correct.137for (unsigned int i=0; i<10000; ++i) {138// Pick a random element in vBlocksMain.139int r = m_rng.randrange(vBlocksMain.size());140int64_t test_time = vBlocksMain[r].nTime;141CBlockIndex* ret = chain.FindEarliestAtLeast(test_time, 0);142BOOST_CHECK(ret->nTimeMax >= test_time);143BOOST_CHECK((ret->pprev==nullptr) || ret->pprev->nTimeMax < test_time);144BOOST_CHECK(vBlocksMain[r].GetAncestor(ret->nHeight) == ret);145}146}148BOOST_AUTO_TEST_CASE(findearliestatleast_edge_test)149{150std::list<CBlockIndex> blocks;151for (const unsigned int timeMax : {100, 100, 100, 200, 200, 200, 300, 300, 300}) {152CBlockIndex* prev = blocks.empty() ? nullptr : &blocks.back();153blocks.emplace_back();154blocks.back().nHeight = prev ? prev->nHeight + 1 : 0;155blocks.back().pprev = prev;156blocks.back().BuildSkip();157blocks.back().nTimeMax = timeMax;158}160CChain chain;161chain.SetTip(blocks.back());163BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(50, 0)->nHeight, 0);164BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(100, 0)->nHeight, 0);165BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(150, 0)->nHeight, 3);166BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(200, 0)->nHeight, 3);167BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(250, 0)->nHeight, 6);168BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(300, 0)->nHeight, 6);169BOOST_CHECK(!chain.FindEarliestAtLeast(350, 0));171BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(0, 0)->nHeight, 0);172BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(-1, 0)->nHeight, 0);174BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(std::numeric_limits<int64_t>::min(), 0)->nHeight, 0);175BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(-int64_t(std::numeric_limits<unsigned int>::max()) - 1, 0)->nHeight, 0);176BOOST_CHECK(!chain.FindEarliestAtLeast(std::numeric_limits<int64_t>::max(), 0));177BOOST_CHECK(!chain.FindEarliestAtLeast(std::numeric_limits<unsigned int>::max(), 0));178BOOST_CHECK(!chain.FindEarliestAtLeast(int64_t(std::numeric_limits<unsigned int>::max()) + 1, 0));180BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(0, -1)->nHeight, 0);181BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(0, 0)->nHeight, 0);182BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(0, 3)->nHeight, 3);183BOOST_CHECK_EQUAL(chain.FindEarliestAtLeast(0, 8)->nHeight, 8);184BOOST_CHECK(!chain.FindEarliestAtLeast(0, 9));186CBlockIndex* ret1 = chain.FindEarliestAtLeast(100, 2);187BOOST_CHECK(ret1->nTimeMax >= 100);188BOOST_CHECK(ret1->nHeight == 2);189BOOST_CHECK(!chain.FindEarliestAtLeast(300, 9));190CBlockIndex* ret2 = chain.FindEarliestAtLeast(200, 4);191BOOST_CHECK(ret2->nTimeMax >= 200);192BOOST_CHECK(ret2->nHeight == 4);193}195BOOST_AUTO_TEST_CASE(build_skip_height_test)196{197// clang-format off198const std::pair<int, int> TEST_DATA[]{199// EVEN values: the rightmost set bit is zeroed200// Various even values with at least 2 bits set201{ 0b00010010 ,2020b00010000 },203{ 0b00100010 ,2040b00100000 },205{ 0b01000010 ,2060b01000000 },207{ 0b00010100 ,2080b00010000 },209{ 0b00011000 ,2100b00010000 },211{ 0b10101010 ,2120b10101000 },213// ODD values: the 2nd and 3rd set bits are zeroed214// Various odd values with at least 4 bits set215{ 0b10010011 ,2160b10000001 },217{ 0b10100011 ,2180b10000001 },219{ 0b11000011 ,2200b10000001 },221{ 0b10010101 ,2220b10000001 },223{ 0b10011001 ,2240b10000001 },225{ 0b10101011 ,2260b10100001 },227// Some longer random values (even and odd)228{ 0b0001011101101000 ,2290b0001011101100000 },230{ 0b0001011101101001 ,2310b0001011101000001 },232{ 0b0110101101011000 ,2330b0110101101010000 },234{ 0b0110101101011001 ,2350b0110101101000001 },236// All values 1-20237{ 1, 0 },238{ 2, 0 },239{ 3, 1 },240{ 4, 0 },241{ 5, 1 },242{ 6, 4 },243{ 7, 1 },244{ 8, 0 },245{ 9, 1 },246{ 10, 8 },247{ 11, 1 },248{ 12, 8 },249{ 13, 1 },250{ 14, 12 },
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.