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) 2024-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 <coins.h>7#include <boost/test/unit_test.hpp>9#include <list>11BOOST_AUTO_TEST_SUITE(coinscachepair_tests)13static constexpr auto NUM_NODES{4};15std::list<CoinsCachePair> CreatePairs(CoinsCachePair& sentinel)16{17std::list<CoinsCachePair> nodes;18for (auto i{0}; i < NUM_NODES; ++i) {19nodes.emplace_back();21auto node{std::prev(nodes.end())};22CCoinsCacheEntry::SetDirty(*node, sentinel);24BOOST_CHECK(node->second.IsDirty());25BOOST_CHECK(!node->second.IsFresh());26BOOST_CHECK_EQUAL(node->second.Next(), &sentinel);27BOOST_CHECK_EQUAL(sentinel.second.Prev(), &(*node));29if (i > 0) {30BOOST_CHECK_EQUAL(std::prev(node)->second.Next(), &(*node));31BOOST_CHECK_EQUAL(node->second.Prev(), &(*std::prev(node)));32}33}34return nodes;35}37BOOST_AUTO_TEST_CASE(linked_list_iteration)38{39CoinsCachePair sentinel;40sentinel.second.SelfRef(sentinel);41auto nodes{CreatePairs(sentinel)};43// Check iterating through pairs is identical to iterating through a list44auto node{sentinel.second.Next()};45for (const auto& expected : nodes) {46BOOST_CHECK_EQUAL(&expected, node);47node = node->second.Next();48}49BOOST_CHECK_EQUAL(node, &sentinel);51// Check iterating through pairs is identical to iterating through a list52// Clear the state during iteration53node = sentinel.second.Next();54for (const auto& expected : nodes) {55BOOST_CHECK_EQUAL(&expected, node);56auto next = node->second.Next();57node->second.SetClean();58node = next;59}60BOOST_CHECK_EQUAL(node, &sentinel);61// Check that sentinel's next and prev are itself62BOOST_CHECK_EQUAL(sentinel.second.Next(), &sentinel);63BOOST_CHECK_EQUAL(sentinel.second.Prev(), &sentinel);65// Delete the nodes from the list to make sure there are no dangling pointers66for (auto it{nodes.begin()}; it != nodes.end(); it = nodes.erase(it)) {67BOOST_CHECK(!it->second.IsDirty());68BOOST_CHECK(!it->second.IsFresh());69}70}72BOOST_AUTO_TEST_CASE(linked_list_iterate_erase)73{74CoinsCachePair sentinel;75sentinel.second.SelfRef(sentinel);76auto nodes{CreatePairs(sentinel)};78// Check iterating through pairs is identical to iterating through a list79// Erase the nodes as we iterate through, but don't clear state80// The state will be cleared by the CCoinsCacheEntry's destructor81auto node{sentinel.second.Next()};82for (auto expected{nodes.begin()}; expected != nodes.end(); expected = nodes.erase(expected)) {83BOOST_CHECK_EQUAL(&(*expected), node);84node = node->second.Next();85}86BOOST_CHECK_EQUAL(node, &sentinel);88// Check that sentinel's next and prev are itself89BOOST_CHECK_EQUAL(sentinel.second.Next(), &sentinel);90BOOST_CHECK_EQUAL(sentinel.second.Prev(), &sentinel);91}93BOOST_AUTO_TEST_CASE(linked_list_random_deletion)94{95CoinsCachePair sentinel;96sentinel.second.SelfRef(sentinel);97auto nodes{CreatePairs(sentinel)};99// Create linked list sentinel->n1->n2->n3->n4->sentinel100auto n1{nodes.begin()};101auto n2{std::next(n1)};102auto n3{std::next(n2)};103auto n4{std::next(n3)};105// Delete n2106// sentinel->n1->n3->n4->sentinel107nodes.erase(n2);108// Check that n1 now points to n3, and n3 still points to n4109// Also check that state was not altered110BOOST_CHECK(n1->second.IsDirty());111BOOST_CHECK(!n1->second.IsFresh());112BOOST_CHECK_EQUAL(n1->second.Next(), &(*n3));113BOOST_CHECK(n3->second.IsDirty());114BOOST_CHECK(!n3->second.IsFresh());115BOOST_CHECK_EQUAL(n3->second.Next(), &(*n4));116BOOST_CHECK_EQUAL(n3->second.Prev(), &(*n1));118// Delete n1119// sentinel->n3->n4->sentinel120nodes.erase(n1);121// Check that sentinel now points to n3, and n3 still points to n4122// Also check that state was not altered123BOOST_CHECK(n3->second.IsDirty());124BOOST_CHECK(!n3->second.IsFresh());125BOOST_CHECK_EQUAL(sentinel.second.Next(), &(*n3));126BOOST_CHECK_EQUAL(n3->second.Next(), &(*n4));127BOOST_CHECK_EQUAL(n3->second.Prev(), &sentinel);129// Delete n4130// sentinel->n3->sentinel131nodes.erase(n4);132// Check that sentinel still points to n3, and n3 points to sentinel133// Also check that state was not altered134BOOST_CHECK(n3->second.IsDirty());135BOOST_CHECK(!n3->second.IsFresh());136BOOST_CHECK_EQUAL(sentinel.second.Next(), &(*n3));137BOOST_CHECK_EQUAL(n3->second.Next(), &sentinel);138BOOST_CHECK_EQUAL(sentinel.second.Prev(), &(*n3));140// Delete n3141// sentinel->sentinel142nodes.erase(n3);143// Check that sentinel's next and prev are itself144BOOST_CHECK_EQUAL(sentinel.second.Next(), &sentinel);145BOOST_CHECK_EQUAL(sentinel.second.Prev(), &sentinel);146}148BOOST_AUTO_TEST_CASE(linked_list_set_state)149{150CoinsCachePair sentinel;151sentinel.second.SelfRef(sentinel);152CoinsCachePair n1;153CoinsCachePair n2;155// Check that setting DIRTY inserts it into linked list and sets state156CCoinsCacheEntry::SetDirty(n1, sentinel);157BOOST_CHECK(n1.second.IsDirty());158BOOST_CHECK(!n1.second.IsFresh());159BOOST_CHECK_EQUAL(n1.second.Next(), &sentinel);160BOOST_CHECK_EQUAL(n1.second.Prev(), &sentinel);161BOOST_CHECK_EQUAL(sentinel.second.Next(), &n1);162BOOST_CHECK_EQUAL(sentinel.second.Prev(), &n1);164// Check that setting FRESH on new node inserts it after n1165CCoinsCacheEntry::SetFresh(n2, sentinel);166BOOST_CHECK(n2.second.IsFresh());167BOOST_CHECK(!n2.second.IsDirty());168BOOST_CHECK_EQUAL(n2.second.Next(), &sentinel);169BOOST_CHECK_EQUAL(n2.second.Prev(), &n1);170BOOST_CHECK_EQUAL(n1.second.Next(), &n2);171BOOST_CHECK_EQUAL(sentinel.second.Prev(), &n2);173// Check that we can set extra state, but they don't change our position174CCoinsCacheEntry::SetFresh(n1, sentinel);175BOOST_CHECK(n1.second.IsDirty());176BOOST_CHECK(n1.second.IsFresh());177BOOST_CHECK_EQUAL(n1.second.Next(), &n2);178BOOST_CHECK_EQUAL(n1.second.Prev(), &sentinel);179BOOST_CHECK_EQUAL(sentinel.second.Next(), &n1);180BOOST_CHECK_EQUAL(n2.second.Prev(), &n1);182// Check that we can clear state then re-set it183n1.second.SetClean();184BOOST_CHECK(!n1.second.IsDirty());185BOOST_CHECK(!n1.second.IsFresh());186BOOST_CHECK_EQUAL(sentinel.second.Next(), &n2);187BOOST_CHECK_EQUAL(sentinel.second.Prev(), &n2);188BOOST_CHECK_EQUAL(n2.second.Next(), &sentinel);189BOOST_CHECK_EQUAL(n2.second.Prev(), &sentinel);191// Calling `SetClean` a second time has no effect192n1.second.SetClean();193BOOST_CHECK(!n1.second.IsDirty());194BOOST_CHECK(!n1.second.IsFresh());195BOOST_CHECK_EQUAL(sentinel.second.Next(), &n2);196BOOST_CHECK_EQUAL(sentinel.second.Prev(), &n2);197BOOST_CHECK_EQUAL(n2.second.Next(), &sentinel);198BOOST_CHECK_EQUAL(n2.second.Prev(), &sentinel);200// Adding DIRTY re-inserts it after n2201CCoinsCacheEntry::SetDirty(n1, sentinel);202BOOST_CHECK(n1.second.IsDirty());203BOOST_CHECK(!n1.second.IsFresh());204BOOST_CHECK_EQUAL(n2.second.Next(), &n1);205BOOST_CHECK_EQUAL(n1.second.Prev(), &n2);206BOOST_CHECK_EQUAL(n1.second.Next(), &sentinel);207BOOST_CHECK_EQUAL(sentinel.second.Prev(), &n1);208}210BOOST_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.