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) 2017-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 <addresstype.h>6#include <blockfilter.h>7#include <chain.h>8#include <index/blockfilterindex.h>9#include <interfaces/chain.h>10#include <key.h>11#include <node/blockstorage.h>12#include <primitives/block.h>13#include <script/script.h>14#include <sync.h>15#include <test/util/blockfilter.h>16#include <test/util/common.h>17#include <test/util/mining.h>18#include <test/util/setup_common.h>19#include <uint256.h>20#include <util/check.h>21#include <validation.h>23#include <boost/test/unit_test.hpp>25#include <compare>26#include <cstddef>27#include <cstdint>28#include <functional>29#include <memory>30#include <span>31#include <string>32#include <utility>33#include <vector>35using node::BlockManager;37BOOST_AUTO_TEST_SUITE(blockfilter_index_tests)39static bool CheckFilterLookups(BlockFilterIndex& filter_index, const CBlockIndex* block_index,40uint256& last_header, const BlockManager& blockman)41{42BlockFilter expected_filter;43if (!ComputeFilter(filter_index.GetFilterType(), *block_index, expected_filter, blockman)) {44BOOST_ERROR("ComputeFilter failed on block " << block_index->nHeight);45return false;46}48BlockFilter filter;49uint256 filter_header;50std::vector<BlockFilter> filters;51std::vector<uint256> filter_hashes;53BOOST_CHECK(filter_index.LookupFilter(block_index, filter));54BOOST_CHECK(filter_index.LookupFilterHeader(block_index, filter_header));55BOOST_CHECK(filter_index.LookupFilterRange(block_index->nHeight, block_index, filters));56BOOST_CHECK(filter_index.LookupFilterHashRange(block_index->nHeight, block_index,57filter_hashes));59BOOST_CHECK_EQUAL(filters.size(), 1U);60BOOST_CHECK_EQUAL(filter_hashes.size(), 1U);62BOOST_CHECK_EQUAL(filter.GetHash(), expected_filter.GetHash());63BOOST_CHECK_EQUAL(filter_header, expected_filter.ComputeHeader(last_header));64BOOST_CHECK_EQUAL(filters[0].GetHash(), expected_filter.GetHash());65BOOST_CHECK_EQUAL(filter_hashes[0], expected_filter.GetHash());67filters.clear();68filter_hashes.clear();69last_header = filter_header;70return true;71}73BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, TestChain100Setup)74{75BlockFilterIndex filter_index(interfaces::MakeChain(m_node), BlockFilterType::BASIC, 1_MiB, true);76BOOST_REQUIRE(filter_index.Init());78uint256 last_header;80// Filter should not be found in the index before it is started.81{82LOCK(cs_main);84BlockFilter filter;85uint256 filter_header;86std::vector<BlockFilter> filters;87std::vector<uint256> filter_hashes;89for (const CBlockIndex* block_index = m_node.chainman->ActiveChain().Genesis();90block_index != nullptr;91block_index = m_node.chainman->ActiveChain().Next(*block_index)) {92BOOST_CHECK(!filter_index.LookupFilter(block_index, filter));93BOOST_CHECK(!filter_index.LookupFilterHeader(block_index, filter_header));94BOOST_CHECK(!filter_index.LookupFilterRange(block_index->nHeight, block_index, filters));95BOOST_CHECK(!filter_index.LookupFilterHashRange(block_index->nHeight, block_index,96filter_hashes));97}98}100// BlockUntilSyncedToCurrentChain should return false before index is started.101BOOST_CHECK(!filter_index.BlockUntilSyncedToCurrentChain());103filter_index.Sync();105// Check that filter index has all blocks that were in the chain before it started.106{107LOCK(cs_main);108const CBlockIndex* block_index;109for (block_index = m_node.chainman->ActiveChain().Genesis();110block_index != nullptr;111block_index = m_node.chainman->ActiveChain().Next(*block_index)) {112CheckFilterLookups(filter_index, block_index, last_header, m_node.chainman->m_blockman);113}114}116// Create two forks.117const CBlockIndex* tip;118{119LOCK(cs_main);120tip = m_node.chainman->ActiveChain().Tip();121}122CKey coinbase_key_A = GenerateRandomKey();123CKey coinbase_key_B = GenerateRandomKey();124CScript coinbase_script_pub_key_A = GetScriptForDestination(PKHash(coinbase_key_A.GetPubKey()));125CScript coinbase_script_pub_key_B = GetScriptForDestination(PKHash(coinbase_key_B.GetPubKey()));126std::vector<std::shared_ptr<CBlock>> chainA, chainB;127BOOST_REQUIRE(BuildChain(m_node, tip, coinbase_script_pub_key_A, 10, chainA));128BOOST_REQUIRE(BuildChain(m_node, tip, coinbase_script_pub_key_B, 10, chainB));130// Check that new blocks on chain A get indexed.131uint256 chainA_last_header = last_header;132for (size_t i = 0; i < 2; i++) {133const auto& block = chainA[i];134BOOST_REQUIRE(Assert(m_node.chainman)->ProcessNewBlock(block, true, true, nullptr));135}136for (size_t i = 0; i < 2; i++) {137const auto& block = chainA[i];138const CBlockIndex* block_index;139{140LOCK(cs_main);141block_index = m_node.chainman->m_blockman.LookupBlockIndex(block->GetHash());142}144BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());145CheckFilterLookups(filter_index, block_index, chainA_last_header, m_node.chainman->m_blockman);146}148// Reorg to chain B.149uint256 chainB_last_header = last_header;150for (size_t i = 0; i < 3; i++) {151const auto& block = chainB[i];152BOOST_REQUIRE(Assert(m_node.chainman)->ProcessNewBlock(block, true, true, nullptr));153}154for (size_t i = 0; i < 3; i++) {155const auto& block = chainB[i];156const CBlockIndex* block_index;157{158LOCK(cs_main);159block_index = m_node.chainman->m_blockman.LookupBlockIndex(block->GetHash());160}162BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());163CheckFilterLookups(filter_index, block_index, chainB_last_header, m_node.chainman->m_blockman);164}166// Check that filters for stale blocks on A can be retrieved.167chainA_last_header = last_header;168for (size_t i = 0; i < 2; i++) {169const auto& block = chainA[i];170const CBlockIndex* block_index;171{172LOCK(cs_main);173block_index = m_node.chainman->m_blockman.LookupBlockIndex(block->GetHash());174}176BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());177CheckFilterLookups(filter_index, block_index, chainA_last_header, m_node.chainman->m_blockman);178}180// Reorg back to chain A.181for (size_t i = 2; i < 4; i++) {182const auto& block = chainA[i];183BOOST_REQUIRE(Assert(m_node.chainman)->ProcessNewBlock(block, true, true, nullptr));184}186// Check that chain A and B blocks can be retrieved.187chainA_last_header = last_header;188chainB_last_header = last_header;189for (size_t i = 0; i < 3; i++) {190const CBlockIndex* block_index;192{193LOCK(cs_main);194block_index = m_node.chainman->m_blockman.LookupBlockIndex(chainA[i]->GetHash());195}196BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());197CheckFilterLookups(filter_index, block_index, chainA_last_header, m_node.chainman->m_blockman);199{200LOCK(cs_main);201block_index = m_node.chainman->m_blockman.LookupBlockIndex(chainB[i]->GetHash());202}203BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());204CheckFilterLookups(filter_index, block_index, chainB_last_header, m_node.chainman->m_blockman);205}207// Test lookups for a range of filters/hashes.208std::vector<BlockFilter> filters;209std::vector<uint256> filter_hashes;211{212LOCK(cs_main);213tip = m_node.chainman->ActiveChain().Tip();214}215BOOST_CHECK(filter_index.LookupFilterRange(0, tip, filters));216BOOST_CHECK(filter_index.LookupFilterHashRange(0, tip, filter_hashes));218assert(tip->nHeight >= 0);219BOOST_CHECK_EQUAL(filters.size(), tip->nHeight + 1U);220BOOST_CHECK_EQUAL(filter_hashes.size(), tip->nHeight + 1U);222filters.clear();223filter_hashes.clear();225filter_index.Interrupt();226filter_index.Stop();227}229BOOST_FIXTURE_TEST_CASE(blockfilter_index_init_destroy, BasicTestingSetup)230{231BlockFilterIndex* filter_index;233filter_index = GetBlockFilterIndex(BlockFilterType::BASIC);234BOOST_CHECK(filter_index == nullptr);236BOOST_CHECK(InitBlockFilterIndex([&]{ return interfaces::MakeChain(m_node); }, BlockFilterType::BASIC, 1_MiB, true, false));238filter_index = GetBlockFilterIndex(BlockFilterType::BASIC);239BOOST_CHECK(filter_index != nullptr);240BOOST_CHECK(filter_index->GetFilterType() == BlockFilterType::BASIC);242// Initialize returns false if index already exists.243BOOST_CHECK(!InitBlockFilterIndex([&]{ return interfaces::MakeChain(m_node); }, BlockFilterType::BASIC, 1_MiB, true, false));245int iter_count = 0;246ForEachBlockFilterIndex([&iter_count](BlockFilterIndex& _index) { iter_count++; });247BOOST_CHECK_EQUAL(iter_count, 1);249BOOST_CHECK(DestroyBlockFilterIndex(BlockFilterType::BASIC));
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.