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) 2011-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// Unit tests for denial-of-service detection/prevention code7#include <banman.h>8#include <chainparams.h>9#include <common/args.h>10#include <net.h>11#include <net_processing.h>12#include <pubkey.h>13#include <script/sign.h>14#include <script/signingprovider.h>15#include <serialize.h>16#include <test/util/net.h>17#include <test/util/random.h>18#include <test/util/setup_common.h>19#include <test/util/time.h>20#include <util/string.h>21#include <util/time.h>22#include <validation.h>24#include <array>25#include <cstdint>27#include <boost/test/unit_test.hpp>29static CService ip(uint32_t i)30{31struct in_addr s;32s.s_addr = i;33return CService(CNetAddr(s), Params().GetDefaultPort());34}36BOOST_FIXTURE_TEST_SUITE(denialofservice_tests, TestingSetup)38// Test eviction of an outbound peer whose chain never advances39// Mock a node connection, and use mocktime to simulate a peer40// which never sends any headers messages. PeerLogic should41// decide to evict that outbound peer, after the appropriate timeouts.42// Note that we protect 4 outbound nodes from being subject to43// this logic; this test takes advantage of that protection only44// being applied to nodes which send headers with sufficient45// work.46BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)47{48LOCK(NetEventsInterface::g_msgproc_mutex);50ConnmanTestMsg& connman = static_cast<ConnmanTestMsg&>(*m_node.connman);51// Disable inactivity checks for this test to avoid interference52connman.SetPeerConnectTimeout(99999s);53PeerManager& peerman = *m_node.peerman;55// Mock an outbound peer56CAddress addr1(ip(0xa0b0c001), NODE_NONE);57NodeId id{0};58CNode dummyNode1{id++,59/*sock=*/nullptr,60addr1,61/*nKeyedNetGroupIn=*/0,62/*nLocalHostNonceIn=*/0,63CAddress(),64/*addrNameIn=*/"",65ConnectionType::OUTBOUND_FULL_RELAY,66/*inbound_onion=*/false,67/*network_key=*/0};69connman.Handshake(70/*node=*/dummyNode1,71/*successfully_connected=*/true,72/*remote_services=*/ServiceFlags(NODE_NETWORK | NODE_WITNESS),73/*local_services=*/ServiceFlags(NODE_NETWORK | NODE_WITNESS),74/*version=*/PROTOCOL_VERSION,75/*relay_txs=*/true);77// This test requires that we have a chain with non-zero work.78{79LOCK(cs_main);80BOOST_CHECK(m_node.chainman->ActiveChain().Tip() != nullptr);81BOOST_CHECK(m_node.chainman->ActiveChain().Tip()->nChainWork > 0);82}84// Test starts here85BOOST_CHECK(peerman.SendMessages(dummyNode1)); // should result in getheaders87{88LOCK(dummyNode1.cs_vSend);89const auto& [to_send, _more, _msg_type] = dummyNode1.m_transport->GetBytesToSend(false);90BOOST_CHECK(!to_send.empty());91}92connman.FlushSendBuffer(dummyNode1);94FakeNodeClock clock{};95clock += 21min;97BOOST_CHECK(peerman.SendMessages(dummyNode1)); // should result in getheaders98{99LOCK(dummyNode1.cs_vSend);100const auto& [to_send, _more, _msg_type] = dummyNode1.m_transport->GetBytesToSend(false);101BOOST_CHECK(!to_send.empty());102}104clock += 3min;105BOOST_CHECK(peerman.SendMessages(dummyNode1)); // should result in disconnect106BOOST_CHECK(dummyNode1.fDisconnect == true);108peerman.FinalizeNode(dummyNode1);109}111struct OutboundTest : TestingSetup {112void AddRandomOutboundPeer(NodeId& id, std::vector<CNode*>& vNodes, PeerManager& peerLogic, ConnmanTestMsg& connman, ConnectionType connType, bool onion_peer = false)113{114CAddress addr;116if (onion_peer) {117auto tor_addr{m_rng.randbytes(ADDR_TORV3_SIZE)};118BOOST_REQUIRE(addr.SetSpecial(OnionToString(tor_addr)));119}121while (!addr.IsRoutable()) {122addr = CAddress(ip(m_rng.randbits(32)), NODE_NONE);123}125vNodes.emplace_back(new CNode{id++,126/*sock=*/nullptr,127addr,128/*nKeyedNetGroupIn=*/0,129/*nLocalHostNonceIn=*/0,130CAddress(),131/*addrNameIn=*/"",132connType,133/*inbound_onion=*/false,134/*network_key=*/0});135CNode &node = *vNodes.back();136node.SetCommonVersion(PROTOCOL_VERSION);138peerLogic.InitializeNode(node, ServiceFlags(NODE_NETWORK | NODE_WITNESS));139node.fSuccessfullyConnected = true;141connman.AddTestNode(node);142}143}; // struct OutboundTest145BOOST_FIXTURE_TEST_CASE(stale_tip_peer_management, OutboundTest)146{147NodeId id{0};148auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params());149auto peerLogic = PeerManager::make(*connman, *m_node.addrman, nullptr, *m_node.chainman, *m_node.mempool, *m_node.warnings, {});151constexpr int max_outbound_full_relay = MAX_OUTBOUND_FULL_RELAY_CONNECTIONS;152CConnman::Options options;153options.m_max_automatic_connections = DEFAULT_MAX_PEER_CONNECTIONS;155const auto time_init{Now<NodeSeconds>()};156FakeNodeClock clock{time_init};157const auto delta{3 * std::chrono::seconds{m_node.chainman->GetConsensus().nPowTargetSpacing} + 1s};158connman->Init(options);159std::vector<CNode *> vNodes;161// Mock some outbound peers162for (int i = 0; i < max_outbound_full_relay; ++i) {163AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::OUTBOUND_FULL_RELAY);164}166peerLogic->CheckForStaleTipAndEvictPeers();168// No nodes should be marked for disconnection while we have no extra peers169for (const CNode *node : vNodes) {170BOOST_CHECK(node->fDisconnect == false);171}173clock += delta;175// Now tip should definitely be stale, and we should look for an extra176// outbound peer177peerLogic->CheckForStaleTipAndEvictPeers();178BOOST_CHECK(connman->GetTryNewOutboundPeer());180// Still no peers should be marked for disconnection181for (const CNode *node : vNodes) {182BOOST_CHECK(node->fDisconnect == false);183}185// If we add one more peer, something should get marked for eviction186// on the next check (since we're mocking the time to be in the future, the187// required time connected check should be satisfied).188clock.set(time_init);189AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::OUTBOUND_FULL_RELAY);190clock += delta;192peerLogic->CheckForStaleTipAndEvictPeers();193for (int i = 0; i < max_outbound_full_relay; ++i) {194BOOST_CHECK(vNodes[i]->fDisconnect == false);195}196// Last added node should get marked for eviction197BOOST_CHECK(vNodes.back()->fDisconnect == true);199vNodes.back()->fDisconnect = false;201// Update the last announced block time for the last202// peer, and check that the next newest node gets evicted.203peerLogic->UpdateLastBlockAnnounceTime(vNodes.back()->GetId(), GetTime());205peerLogic->CheckForStaleTipAndEvictPeers();206for (int i = 0; i < max_outbound_full_relay - 1; ++i) {207BOOST_CHECK(vNodes[i]->fDisconnect == false);208}209BOOST_CHECK(vNodes[max_outbound_full_relay-1]->fDisconnect == true);210BOOST_CHECK(vNodes.back()->fDisconnect == false);212vNodes[max_outbound_full_relay - 1]->fDisconnect = false;214// Add an onion peer, that will be protected because it is the only one for215// its network, so another peer gets disconnected instead.216clock.set(time_init);217AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::OUTBOUND_FULL_RELAY, /*onion_peer=*/true);218clock += delta;219peerLogic->CheckForStaleTipAndEvictPeers();221for (int i = 0; i < max_outbound_full_relay - 2; ++i) {222BOOST_CHECK(vNodes[i]->fDisconnect == false);223}224BOOST_CHECK(vNodes[max_outbound_full_relay - 2]->fDisconnect == false);225BOOST_CHECK(vNodes[max_outbound_full_relay - 1]->fDisconnect == true);226BOOST_CHECK(vNodes[max_outbound_full_relay]->fDisconnect == false);228// Add a second onion peer which won't be protected229clock.set(time_init);230AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::OUTBOUND_FULL_RELAY, /*onion_peer=*/true);231clock += delta;232peerLogic->CheckForStaleTipAndEvictPeers();234BOOST_CHECK(vNodes.back()->fDisconnect == true);236for (const CNode *node : vNodes) {237peerLogic->FinalizeNode(*node);238}240connman->ClearTestNodes();241}243BOOST_FIXTURE_TEST_CASE(block_relay_only_eviction, OutboundTest)244{245NodeId id{0};246FakeNodeClock clock{};247auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params());248auto peerLogic = PeerManager::make(*connman, *m_node.addrman, nullptr, *m_node.chainman, *m_node.mempool, *m_node.warnings, {});250constexpr int max_outbound_block_relay{MAX_BLOCK_RELAY_ONLY_CONNECTIONS};
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.