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) 2012-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 <checkqueue.h>6#include <common/args.h>7#include <sync.h>8#include <test/util/random.h>9#include <test/util/setup_common.h>10#include <util/chaintype.h>11#include <util/time.h>13#include <boost/test/unit_test.hpp>15#include <atomic>16#include <condition_variable>17#include <mutex>18#include <thread>19#include <unordered_set>20#include <utility>21#include <vector>23/**24* Identical to BasicTestingSetup but excludes lock contention logging if25* `DEBUG_LOCKCONTENTION` is defined, as some of these tests are designed to be26* heavily contested to trigger race conditions or other issues.27*/28struct NoLockLoggingTestingSetup : public BasicTestingSetup {29NoLockLoggingTestingSetup()30#ifdef DEBUG_LOCKCONTENTION31: BasicTestingSetup{ChainType::MAIN, {.extra_args = { "-debugexclude=lock" } }} {}32#else33: BasicTestingSetup{ChainType::MAIN} {}34#endif35};37struct CheckQueueTest : NoLockLoggingTestingSetup {38void Correct_Queue_range(std::vector<size_t> range);39};41static const unsigned int QUEUE_BATCH_SIZE = 128;42static const int SCRIPT_CHECK_THREADS = 3;44struct FakeCheck {45std::optional<int> operator()() const46{47return std::nullopt;48}49};51struct FakeCheckCheckCompletion {52static std::atomic<size_t> n_calls;53std::optional<int> operator()()54{55n_calls.fetch_add(1, std::memory_order_relaxed);56return std::nullopt;57}58};60struct FixedCheck61{62std::optional<int> m_result;63FixedCheck(std::optional<int> result) : m_result(result){};64std::optional<int> operator()() const { return m_result; }65};67struct UniqueCheck {68static Mutex m;69static std::unordered_multiset<size_t> results GUARDED_BY(m);70size_t check_id;71UniqueCheck(size_t check_id_in) : check_id(check_id_in){};72std::optional<int> operator()()73{74LOCK(m);75results.insert(check_id);76return std::nullopt;77}78};81struct MemoryCheck {82static std::atomic<size_t> fake_allocated_memory;83bool b {false};84std::optional<int> operator()() const85{86return std::nullopt;87}88MemoryCheck(const MemoryCheck& x)89{90// We have to do this to make sure that destructor calls are paired91//92// Really, copy constructor should be deletable, but CCheckQueue breaks93// if it is deleted because of internal push_back.94fake_allocated_memory.fetch_add(b, std::memory_order_relaxed);95};96MemoryCheck(bool b_) : b(b_)97{98fake_allocated_memory.fetch_add(b, std::memory_order_relaxed);99};100~MemoryCheck()101{102fake_allocated_memory.fetch_sub(b, std::memory_order_relaxed);103};104};106struct FrozenCleanupCheck {107static std::atomic<uint64_t> nFrozen;108static std::condition_variable cv;109static std::mutex m;110bool should_freeze{true};111std::optional<int> operator()() const112{113return std::nullopt;114}115FrozenCleanupCheck() = default;116~FrozenCleanupCheck()117{118if (should_freeze) {119std::unique_lock<std::mutex> l(m);120nFrozen.store(1, std::memory_order_relaxed);121cv.notify_one();122cv.wait(l, []{ return nFrozen.load(std::memory_order_relaxed) == 0;});123}124}125FrozenCleanupCheck(FrozenCleanupCheck&& other) noexcept126{127should_freeze = other.should_freeze;128other.should_freeze = false;129}130FrozenCleanupCheck& operator=(FrozenCleanupCheck&& other) noexcept131{132should_freeze = other.should_freeze;133other.should_freeze = false;134return *this;135}136};138// Static Allocations139std::mutex FrozenCleanupCheck::m{};140std::atomic<uint64_t> FrozenCleanupCheck::nFrozen{0};141std::condition_variable FrozenCleanupCheck::cv{};142Mutex UniqueCheck::m;143std::unordered_multiset<size_t> UniqueCheck::results;144std::atomic<size_t> FakeCheckCheckCompletion::n_calls{0};145std::atomic<size_t> MemoryCheck::fake_allocated_memory{0};147// Queue Typedefs148typedef CCheckQueue<FakeCheckCheckCompletion> Correct_Queue;149typedef CCheckQueue<FakeCheck> Standard_Queue;150typedef CCheckQueue<FixedCheck> Fixed_Queue;151typedef CCheckQueue<UniqueCheck> Unique_Queue;152typedef CCheckQueue<MemoryCheck> Memory_Queue;153typedef CCheckQueue<FrozenCleanupCheck> FrozenCleanup_Queue;156/** This test case checks that the CCheckQueue works properly157* with each specified size_t Checks pushed.158*/159void CheckQueueTest::Correct_Queue_range(std::vector<size_t> range)160{161auto small_queue = std::make_unique<Correct_Queue>(QUEUE_BATCH_SIZE, SCRIPT_CHECK_THREADS);162// Make vChecks here to save on malloc (this test can be slow...)163std::vector<FakeCheckCheckCompletion> vChecks;164vChecks.reserve(9);165for (const size_t i : range) {166size_t total = i;167FakeCheckCheckCompletion::n_calls = 0;168CCheckQueueControl<FakeCheckCheckCompletion> control(*small_queue);169while (total) {170vChecks.clear();171vChecks.resize(std::min<size_t>(total, m_rng.randrange(10)));172total -= vChecks.size();173control.Add(std::move(vChecks));174}175BOOST_REQUIRE(!control.Complete().has_value());176BOOST_REQUIRE_EQUAL(FakeCheckCheckCompletion::n_calls, i);177}178}180BOOST_FIXTURE_TEST_SUITE(checkqueue_tests, CheckQueueTest)182/** Test that 0 checks is correct183*/184BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Zero)185{186std::vector<size_t> range;187range.push_back(size_t{0});188Correct_Queue_range(range);189}190/** Test that 1 check is correct191*/192BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_One)193{194std::vector<size_t> range;195range.push_back(size_t{1});196Correct_Queue_range(range);197}198/** Test that MAX check is correct199*/200BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Max)201{202std::vector<size_t> range;203range.push_back(100000);204Correct_Queue_range(range);205}206/** Test that random numbers of checks are correct207*/208BOOST_AUTO_TEST_CASE(test_CheckQueue_Correct_Random)209{210std::vector<size_t> range;211range.reserve(100000/1000);212for (size_t i = 2; i < 100000; i += std::max((size_t)1, (size_t)m_rng.randrange(std::min((size_t)1000, ((size_t)100000) - i))))213range.push_back(i);214Correct_Queue_range(range);215}218/** Test that distinct failing checks are caught */219BOOST_AUTO_TEST_CASE(test_CheckQueue_Catches_Failure)220{221auto fixed_queue = std::make_unique<Fixed_Queue>(QUEUE_BATCH_SIZE, SCRIPT_CHECK_THREADS);222for (size_t i = 0; i < 1001; ++i) {223CCheckQueueControl<FixedCheck> control(*fixed_queue);224size_t remaining = i;225while (remaining) {226size_t r = m_rng.randrange(10);228std::vector<FixedCheck> vChecks;229vChecks.reserve(r);230for (size_t k = 0; k < r && remaining; k++, remaining--)231vChecks.emplace_back(remaining == 1 ? std::make_optional<int>(17 * i) : std::nullopt);232control.Add(std::move(vChecks));233}234auto result = control.Complete();235if (i > 0) {236BOOST_REQUIRE(result.has_value());237BOOST_REQUIRE(*result == static_cast<int>(17 * i));238} else {239BOOST_REQUIRE(!result.has_value());240}241}242}243// Test that a block validation which fails does not interfere with244// future blocks, ie, the bad state is cleared.245BOOST_AUTO_TEST_CASE(test_CheckQueue_Recovers_From_Failure)246{247auto fail_queue = std::make_unique<Fixed_Queue>(QUEUE_BATCH_SIZE, SCRIPT_CHECK_THREADS);248for (auto times = 0; times < 10; ++times) {249for (const bool end_fails : {true, false}) {250CCheckQueueControl<FixedCheck> control(*fail_queue);
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.