LCOV - code coverage report
Current view: top level - src/test - denialofservice_tests.cpp (source / functions) Coverage Total Hit
Test: test_bitcoin_coverage.info Lines: 99.0 % 299 296
Test Date: 2026-10-11 07:59:32 Functions: 100.0 % 15 15
Branches: 51.3 % 1266 649

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2011-present The Bitcoin Core developers
       2                 :             : // Distributed under the MIT software license, see the accompanying
       3                 :             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4                 :             : 
       5                 :             : // Unit tests for denial-of-service detection/prevention code
       6                 :             : 
       7                 :             : #include <banman.h>
       8                 :             : #include <chainparams.h>
       9                 :             : #include <common/args.h>
      10                 :             : #include <key.h>
      11                 :             : #include <net.h>
      12                 :             : #include <net_processing.h>
      13                 :             : #include <primitives/transaction.h>
      14                 :             : #include <pubkey.h>
      15                 :             : #include <script/sign.h>
      16                 :             : #include <script/signingprovider.h>
      17                 :             : #include <script/solver.h>
      18                 :             : #include <serialize.h>
      19                 :             : #include <test/util/net.h>
      20                 :             : #include <test/util/random.h>
      21                 :             : #include <test/util/setup_common.h>
      22                 :             : #include <test/util/time.h>
      23                 :             : #include <util/string.h>
      24                 :             : #include <util/time.h>
      25                 :             : #include <validation.h>
      26                 :             : 
      27                 :             : #include <array>
      28                 :             : #include <cstdint>
      29                 :             : 
      30                 :             : #include <boost/test/unit_test.hpp>
      31                 :             : 
      32                 :          18 : static CService ip(uint32_t i)
      33                 :             : {
      34                 :          18 :     struct in_addr s;
      35                 :          18 :     s.s_addr = i;
      36         [ +  - ]:          36 :     return CService(CNetAddr(s), Params().GetDefaultPort());
      37                 :             : }
      38                 :             : 
      39                 :             : BOOST_FIXTURE_TEST_SUITE(denialofservice_tests, TestingSetup)
      40                 :             : 
      41                 :             : // Test eviction of an outbound peer whose chain never advances
      42                 :             : // Mock a node connection, and use mocktime to simulate a peer
      43                 :             : // which never sends any headers messages.  PeerLogic should
      44                 :             : // decide to evict that outbound peer, after the appropriate timeouts.
      45                 :             : // Note that we protect 4 outbound nodes from being subject to
      46                 :             : // this logic; this test takes advantage of that protection only
      47                 :             : // being applied to nodes which send headers with sufficient
      48                 :             : // work.
      49   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(outbound_slow_chain_eviction)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
      50                 :             : {
      51                 :           1 :     LOCK(NetEventsInterface::g_msgproc_mutex);
      52                 :             : 
      53         [ +  - ]:           1 :     ConnmanTestMsg& connman = static_cast<ConnmanTestMsg&>(*m_node.connman);
      54                 :             :     // Disable inactivity checks for this test to avoid interference
      55         [ +  - ]:           1 :     connman.SetPeerConnectTimeout(99999s);
      56                 :           1 :     PeerManager& peerman = *m_node.peerman;
      57                 :             : 
      58                 :             :     // Mock an outbound peer
      59         [ +  - ]:           2 :     CAddress addr1(ip(0xa0b0c001), NODE_NONE);
      60                 :           1 :     NodeId id{0};
      61                 :           1 :     CNode dummyNode1{id++,
      62                 :             :                      /*sock=*/nullptr,
      63                 :             :                      addr1,
      64                 :             :                      /*nKeyedNetGroupIn=*/0,
      65                 :             :                      /*nLocalHostNonceIn=*/0,
      66         [ -  + ]:           1 :                      CAddress(),
      67         [ +  - ]:           2 :                      /*addrNameIn=*/"",
      68                 :             :                      ConnectionType::OUTBOUND_FULL_RELAY,
      69                 :             :                      /*inbound_onion=*/false,
      70   [ +  -  +  - ]:           2 :                      /*network_key=*/0};
      71                 :             : 
      72         [ +  - ]:           1 :     connman.Handshake(
      73                 :             :         /*node=*/dummyNode1,
      74                 :             :         /*successfully_connected=*/true,
      75                 :             :         /*remote_services=*/ServiceFlags(NODE_NETWORK | NODE_WITNESS),
      76                 :             :         /*local_services=*/ServiceFlags(NODE_NETWORK | NODE_WITNESS),
      77                 :             :         /*version=*/PROTOCOL_VERSION,
      78                 :             :         /*relay_txs=*/true);
      79                 :             : 
      80                 :             :     // This test requires that we have a chain with non-zero work.
      81                 :           1 :     {
      82         [ +  - ]:           1 :         LOCK(cs_main);
      83   [ +  -  +  -  :           3 :         BOOST_CHECK(m_node.chainman->ActiveChain().Tip() != nullptr);
          +  -  -  +  +  
                -  +  - ]
      84   [ +  -  +  -  :           3 :         BOOST_CHECK(m_node.chainman->ActiveChain().Tip()->nChainWork > 0);
          -  +  +  -  +  
                -  +  - ]
      85                 :           0 :     }
      86                 :             : 
      87                 :             :     // Test starts here
      88   [ +  -  +  -  :           2 :     BOOST_CHECK(peerman.SendMessages(dummyNode1)); // should result in getheaders
             +  -  +  - ]
      89                 :             : 
      90                 :           1 :     {
      91         [ +  - ]:           1 :         LOCK(dummyNode1.cs_vSend);
      92         [ +  - ]:           1 :         const auto& [to_send, _more, _msg_type] = dummyNode1.m_transport->GetBytesToSend(false);
      93   [ +  -  +  -  :           2 :         BOOST_CHECK(!to_send.empty());
                   +  - ]
      94                 :           0 :     }
      95         [ +  - ]:           1 :     connman.FlushSendBuffer(dummyNode1);
      96                 :             : 
      97         [ +  - ]:           1 :     FakeNodeClock clock{};
      98         [ +  - ]:           1 :     clock += 21min;
      99                 :             : 
     100   [ +  -  +  -  :           2 :     BOOST_CHECK(peerman.SendMessages(dummyNode1)); // should result in getheaders
             +  -  +  - ]
     101                 :           1 :     {
     102         [ +  - ]:           1 :         LOCK(dummyNode1.cs_vSend);
     103         [ +  - ]:           1 :         const auto& [to_send, _more, _msg_type] = dummyNode1.m_transport->GetBytesToSend(false);
     104   [ +  -  +  -  :           2 :         BOOST_CHECK(!to_send.empty());
                   +  - ]
     105                 :           0 :     }
     106                 :             : 
     107         [ +  - ]:           1 :     clock += 3min;
     108   [ +  -  +  -  :           2 :     BOOST_CHECK(peerman.SendMessages(dummyNode1)); // should result in disconnect
             +  -  +  - ]
     109   [ +  -  +  -  :           2 :     BOOST_CHECK(dummyNode1.fDisconnect == true);
                   +  - ]
     110                 :             : 
     111         [ +  - ]:           1 :     peerman.FinalizeNode(dummyNode1);
     112         [ +  - ]:           2 : }
     113                 :             : 
     114                 :           4 : struct OutboundTest : TestingSetup {
     115                 :          14 : void AddRandomOutboundPeer(NodeId& id, std::vector<CNode*>& vNodes, PeerManager& peerLogic, ConnmanTestMsg& connman, ConnectionType connType, bool onion_peer = false)
     116                 :             : {
     117                 :          14 :     CAddress addr;
     118                 :             : 
     119         [ +  + ]:          14 :     if (onion_peer) {
     120                 :           2 :         auto tor_addr{m_rng.randbytes(ADDR_TORV3_SIZE)};
     121   [ +  -  -  +  :           6 :         BOOST_REQUIRE(addr.SetSpecial(OnionToString(tor_addr)));
          +  -  +  -  +  
                      - ]
     122                 :           2 :     }
     123                 :             : 
     124   [ +  -  +  + ]:          26 :     while (!addr.IsRoutable()) {
     125         [ +  - ]:          24 :         addr = CAddress(ip(m_rng.randbits(32)), NODE_NONE);
     126                 :             :     }
     127                 :             : 
     128   [ +  -  -  - ]:          14 :     vNodes.emplace_back(new CNode{id++,
     129                 :             :                                   /*sock=*/nullptr,
     130                 :             :                                   addr,
     131                 :             :                                   /*nKeyedNetGroupIn=*/0,
     132                 :             :                                   /*nLocalHostNonceIn=*/0,
     133         [ -  + ]:          14 :                                   CAddress(),
     134         [ +  - ]:          28 :                                   /*addrNameIn=*/"",
     135                 :             :                                   connType,
     136                 :             :                                   /*inbound_onion=*/false,
     137   [ +  -  +  -  :          42 :                                   /*network_key=*/0});
                   +  - ]
     138                 :          14 :     CNode &node = *vNodes.back();
     139                 :          14 :     node.SetCommonVersion(PROTOCOL_VERSION);
     140                 :             : 
     141         [ +  - ]:          14 :     peerLogic.InitializeNode(node, ServiceFlags(NODE_NETWORK | NODE_WITNESS));
     142         [ +  - ]:          14 :     node.fSuccessfullyConnected = true;
     143                 :             : 
     144         [ +  - ]:          14 :     connman.AddTestNode(node);
     145                 :          14 : }
     146                 :             : }; // struct OutboundTest
     147                 :             : 
     148   [ +  -  +  -  :           7 : BOOST_FIXTURE_TEST_CASE(stale_tip_peer_management, OutboundTest)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     149                 :             : {
     150                 :           1 :     NodeId id{0};
     151                 :           1 :     auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params());
     152         [ +  - ]:           1 :     auto peerLogic = PeerManager::make(*connman, *m_node.addrman, nullptr, *m_node.chainman, *m_node.mempool, *m_node.warnings, {});
     153                 :             : 
     154                 :           1 :     constexpr int max_outbound_full_relay = MAX_OUTBOUND_FULL_RELAY_CONNECTIONS;
     155                 :           1 :     CConnman::Options options;
     156                 :           1 :     options.m_max_automatic_connections = DEFAULT_MAX_PEER_CONNECTIONS;
     157                 :             : 
     158                 :           1 :     const auto time_init{Now<NodeSeconds>()};
     159         [ +  - ]:           1 :     FakeNodeClock clock{time_init};
     160         [ +  - ]:           1 :     const auto delta{3 * std::chrono::seconds{m_node.chainman->GetConsensus().nPowTargetSpacing} + 1s};
     161         [ +  - ]:           1 :     connman->Init(options);
     162                 :           1 :     std::vector<CNode *> vNodes;
     163                 :             : 
     164                 :             :     // Mock some outbound peers
     165         [ +  + ]:           9 :     for (int i = 0; i < max_outbound_full_relay; ++i) {
     166         [ +  - ]:           8 :         AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::OUTBOUND_FULL_RELAY);
     167                 :             :     }
     168                 :             : 
     169         [ +  - ]:           1 :     peerLogic->CheckForStaleTipAndEvictPeers();
     170                 :             : 
     171                 :             :     // No nodes should be marked for disconnection while we have no extra peers
     172         [ +  + ]:           9 :     for (const CNode *node : vNodes) {
     173   [ +  -  +  - ]:          16 :         BOOST_CHECK(node->fDisconnect == false);
     174                 :             :     }
     175                 :             : 
     176         [ +  - ]:           1 :     clock += delta;
     177                 :             : 
     178                 :             :     // Now tip should definitely be stale, and we should look for an extra
     179                 :             :     // outbound peer
     180         [ +  - ]:           1 :     peerLogic->CheckForStaleTipAndEvictPeers();
     181   [ +  -  +  -  :           2 :     BOOST_CHECK(connman->GetTryNewOutboundPeer());
                   +  - ]
     182                 :             : 
     183                 :             :     // Still no peers should be marked for disconnection
     184         [ +  + ]:           9 :     for (const CNode *node : vNodes) {
     185   [ +  -  +  - ]:          16 :         BOOST_CHECK(node->fDisconnect == false);
     186                 :             :     }
     187                 :             : 
     188                 :             :     // If we add one more peer, something should get marked for eviction
     189                 :             :     // on the next check (since we're mocking the time to be in the future, the
     190                 :             :     // required time connected check should be satisfied).
     191         [ +  - ]:           1 :     clock.set(time_init);
     192         [ +  - ]:           1 :     AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::OUTBOUND_FULL_RELAY);
     193         [ +  - ]:           1 :     clock += delta;
     194                 :             : 
     195         [ +  - ]:           1 :     peerLogic->CheckForStaleTipAndEvictPeers();
     196         [ +  + ]:           9 :     for (int i = 0; i < max_outbound_full_relay; ++i) {
     197   [ +  -  +  - ]:          16 :         BOOST_CHECK(vNodes[i]->fDisconnect == false);
     198                 :             :     }
     199                 :             :     // Last added node should get marked for eviction
     200   [ +  -  +  - ]:           2 :     BOOST_CHECK(vNodes.back()->fDisconnect == true);
     201                 :             : 
     202                 :           1 :     vNodes.back()->fDisconnect = false;
     203                 :             : 
     204                 :             :     // Update the last announced block time for the last
     205                 :             :     // peer, and check that the next newest node gets evicted.
     206         [ +  - ]:           1 :     peerLogic->UpdateLastBlockAnnounceTime(vNodes.back()->GetId(), NodeClock::now());
     207                 :             : 
     208         [ +  - ]:           1 :     peerLogic->CheckForStaleTipAndEvictPeers();
     209         [ +  + ]:           8 :     for (int i = 0; i < max_outbound_full_relay - 1; ++i) {
     210   [ +  -  +  - ]:          14 :         BOOST_CHECK(vNodes[i]->fDisconnect == false);
     211                 :             :     }
     212   [ +  -  +  -  :           2 :     BOOST_CHECK(vNodes[max_outbound_full_relay-1]->fDisconnect == true);
                   +  - ]
     213   [ +  -  +  -  :           2 :     BOOST_CHECK(vNodes.back()->fDisconnect == false);
                   +  - ]
     214                 :             : 
     215         [ +  - ]:           1 :     vNodes[max_outbound_full_relay - 1]->fDisconnect = false;
     216                 :             : 
     217                 :             :     // Add an onion peer, that will be protected because it is the only one for
     218                 :             :     // its network, so another peer gets disconnected instead.
     219         [ +  - ]:           1 :     clock.set(time_init);
     220         [ +  - ]:           1 :     AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::OUTBOUND_FULL_RELAY, /*onion_peer=*/true);
     221         [ +  - ]:           1 :     clock += delta;
     222         [ +  - ]:           1 :     peerLogic->CheckForStaleTipAndEvictPeers();
     223                 :             : 
     224         [ +  + ]:           7 :     for (int i = 0; i < max_outbound_full_relay - 2; ++i) {
     225   [ +  -  +  - ]:          12 :         BOOST_CHECK(vNodes[i]->fDisconnect == false);
     226                 :             :     }
     227   [ +  -  +  -  :           2 :     BOOST_CHECK(vNodes[max_outbound_full_relay - 2]->fDisconnect == false);
                   +  - ]
     228   [ +  -  +  -  :           2 :     BOOST_CHECK(vNodes[max_outbound_full_relay - 1]->fDisconnect == true);
                   +  - ]
     229   [ +  -  +  -  :           2 :     BOOST_CHECK(vNodes[max_outbound_full_relay]->fDisconnect == false);
                   +  - ]
     230                 :             : 
     231                 :             :     // Add a second onion peer which won't be protected
     232         [ +  - ]:           1 :     clock.set(time_init);
     233         [ +  - ]:           1 :     AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::OUTBOUND_FULL_RELAY, /*onion_peer=*/true);
     234         [ +  - ]:           1 :     clock += delta;
     235         [ +  - ]:           1 :     peerLogic->CheckForStaleTipAndEvictPeers();
     236                 :             : 
     237   [ +  -  +  - ]:           2 :     BOOST_CHECK(vNodes.back()->fDisconnect == true);
     238                 :             : 
     239         [ +  + ]:          12 :     for (const CNode *node : vNodes) {
     240         [ +  - ]:          11 :         peerLogic->FinalizeNode(*node);
     241                 :             :     }
     242                 :             : 
     243         [ +  - ]:           1 :     connman->ClearTestNodes();
     244                 :           1 : }
     245                 :             : 
     246   [ +  -  +  -  :           7 : BOOST_FIXTURE_TEST_CASE(block_relay_only_eviction, OutboundTest)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     247                 :             : {
     248                 :           1 :     NodeId id{0};
     249                 :           1 :     FakeNodeClock clock{};
     250   [ +  -  +  - ]:           1 :     auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params());
     251         [ +  - ]:           1 :     auto peerLogic = PeerManager::make(*connman, *m_node.addrman, nullptr, *m_node.chainman, *m_node.mempool, *m_node.warnings, {});
     252                 :             : 
     253                 :           1 :     constexpr int max_outbound_block_relay{MAX_BLOCK_RELAY_ONLY_CONNECTIONS};
     254                 :           1 :     constexpr auto MINIMUM_CONNECT_TIME{30s};
     255                 :           1 :     CConnman::Options options;
     256                 :           1 :     options.m_max_automatic_connections = DEFAULT_MAX_PEER_CONNECTIONS;
     257                 :             : 
     258         [ +  - ]:           1 :     connman->Init(options);
     259                 :           1 :     std::vector<CNode*> vNodes;
     260                 :             : 
     261                 :             :     // Add block-relay-only peers up to the limit
     262         [ +  + ]:           3 :     for (int i = 0; i < max_outbound_block_relay; ++i) {
     263         [ +  - ]:           2 :         AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::BLOCK_RELAY);
     264                 :             :     }
     265         [ +  - ]:           1 :     peerLogic->CheckForStaleTipAndEvictPeers();
     266                 :             : 
     267         [ +  + ]:           3 :     for (int i = 0; i < max_outbound_block_relay; ++i) {
     268   [ +  -  +  - ]:           4 :         BOOST_CHECK(vNodes[i]->fDisconnect == false);
     269                 :             :     }
     270                 :             : 
     271                 :             :     // Add an extra block-relay-only peer breaking the limit (mocks logic in ThreadOpenConnections)
     272         [ +  - ]:           1 :     AddRandomOutboundPeer(id, vNodes, *peerLogic, *connman, ConnectionType::BLOCK_RELAY);
     273         [ +  - ]:           1 :     peerLogic->CheckForStaleTipAndEvictPeers();
     274                 :             : 
     275                 :             :     // The extra peer should only get marked for eviction after MINIMUM_CONNECT_TIME
     276         [ +  + ]:           3 :     for (int i = 0; i < max_outbound_block_relay; ++i) {
     277   [ +  -  +  - ]:           4 :         BOOST_CHECK(vNodes[i]->fDisconnect == false);
     278                 :             :     }
     279   [ +  -  +  -  :           2 :     BOOST_CHECK(vNodes.back()->fDisconnect == false);
                   +  - ]
     280                 :             : 
     281         [ +  - ]:           1 :     clock += MINIMUM_CONNECT_TIME;
     282         [ +  - ]:           1 :     peerLogic->CheckForStaleTipAndEvictPeers();
     283         [ +  + ]:           3 :     for (int i = 0; i < max_outbound_block_relay; ++i) {
     284   [ +  -  +  - ]:           4 :         BOOST_CHECK(vNodes[i]->fDisconnect == false);
     285                 :             :     }
     286   [ +  -  +  - ]:           2 :     BOOST_CHECK(vNodes.back()->fDisconnect == true);
     287                 :             : 
     288                 :             :     // Update the last block time for the extra peer,
     289                 :             :     // and check that the next youngest peer gets evicted.
     290                 :           1 :     vNodes.back()->fDisconnect = false;
     291                 :           1 :     vNodes.back()->m_last_block_time = GetTime<std::chrono::seconds>();
     292                 :             : 
     293         [ +  - ]:           1 :     peerLogic->CheckForStaleTipAndEvictPeers();
     294         [ +  + ]:           2 :     for (int i = 0; i < max_outbound_block_relay - 1; ++i) {
     295   [ +  -  +  - ]:           2 :         BOOST_CHECK(vNodes[i]->fDisconnect == false);
     296                 :             :     }
     297   [ +  -  +  -  :           2 :     BOOST_CHECK(vNodes[max_outbound_block_relay - 1]->fDisconnect == true);
                   +  - ]
     298   [ +  -  +  - ]:           2 :     BOOST_CHECK(vNodes.back()->fDisconnect == false);
     299                 :             : 
     300         [ +  + ]:           4 :     for (const CNode* node : vNodes) {
     301         [ +  - ]:           3 :         peerLogic->FinalizeNode(*node);
     302                 :             :     }
     303         [ +  - ]:           1 :     connman->ClearTestNodes();
     304                 :           1 : }
     305                 :             : 
     306   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(peer_discouragement)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     307                 :             : {
     308                 :           1 :     LOCK(NetEventsInterface::g_msgproc_mutex);
     309                 :             : 
     310   [ +  -  +  - ]:           3 :     auto banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME);
     311   [ +  -  +  - ]:           1 :     auto connman = std::make_unique<ConnmanTestMsg>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params());
     312         [ +  - ]:           1 :     auto peerLogic = PeerManager::make(*connman, *m_node.addrman, banman.get(), *m_node.chainman, *m_node.mempool, *m_node.warnings, {});
     313                 :             : 
     314         [ +  - ]:           1 :     CNetAddr tor_netaddr;
     315   [ +  -  +  -  :           2 :     BOOST_REQUIRE(
             +  -  +  - ]
     316                 :             :         tor_netaddr.SetSpecial("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion"));
     317   [ +  -  +  - ]:           1 :     const CService tor_service{tor_netaddr, Params().GetDefaultPort()};
     318                 :             : 
     319         [ +  - ]:           1 :     const std::array<CAddress, 3> addr{CAddress{ip(0xa0b0c001), NODE_NONE},
     320                 :           1 :                                        CAddress{ip(0xa0b0c002), NODE_NONE},
     321   [ +  -  -  - ]:           2 :                                        CAddress{tor_service, NODE_NONE}};
     322                 :             : 
     323         [ +  - ]:           1 :     const CNetAddr other_addr{ip(0xa0b0ff01)}; // Not any of addr[].
     324                 :             : 
     325                 :           1 :     std::array<CNode*, 5> nodes;
     326                 :             : 
     327         [ +  - ]:           1 :     banman->ClearBanned();
     328                 :           1 :     NodeId id{0};
     329                 :           2 :     nodes[0] = new CNode{id++,
     330                 :             :                          /*sock=*/nullptr,
     331         [ +  - ]:           1 :                          addr[0],
     332                 :             :                          /*nKeyedNetGroupIn=*/0,
     333                 :             :                          /*nLocalHostNonceIn=*/0,
     334         [ -  + ]:           1 :                          CAddress(),
     335         [ +  - ]:           2 :                          /*addrNameIn=*/"",
     336                 :             :                          ConnectionType::INBOUND,
     337                 :             :                          /*inbound_onion=*/false,
     338   [ +  -  +  -  :           2 :                          /*network_key=*/1};
                   +  - ]
     339                 :           1 :     nodes[0]->SetCommonVersion(PROTOCOL_VERSION);
     340         [ +  - ]:           1 :     peerLogic->InitializeNode(*nodes[0], NODE_NETWORK);
     341         [ +  - ]:           1 :     nodes[0]->fSuccessfullyConnected = true;
     342         [ +  - ]:           1 :     connman->AddTestNode(*nodes[0]);
     343         [ +  - ]:           1 :     peerLogic->UnitTestMisbehaving(nodes[0]->GetId()); // Should be discouraged
     344   [ +  -  +  -  :           2 :     BOOST_CHECK(peerLogic->SendMessages(*nodes[0]));
             +  -  +  - ]
     345                 :             : 
     346   [ +  -  +  -  :           2 :     BOOST_CHECK(banman->IsDiscouraged(addr[0]));
             +  -  +  - ]
     347   [ +  -  +  -  :           2 :     BOOST_CHECK(nodes[0]->fDisconnect);
                   +  - ]
     348   [ +  -  +  -  :           2 :     BOOST_CHECK(!banman->IsDiscouraged(other_addr)); // Different address, not discouraged
             +  -  +  - ]
     349                 :             : 
     350                 :           2 :     nodes[1] = new CNode{id++,
     351                 :             :                          /*sock=*/nullptr,
     352         [ +  - ]:           1 :                          addr[1],
     353                 :             :                          /*nKeyedNetGroupIn=*/1,
     354                 :             :                          /*nLocalHostNonceIn=*/1,
     355         [ -  + ]:           1 :                          CAddress(),
     356         [ +  - ]:           2 :                          /*addrNameIn=*/"",
     357                 :             :                          ConnectionType::INBOUND,
     358                 :             :                          /*inbound_onion=*/false,
     359   [ +  -  +  -  :           2 :                          /*network_key=*/1};
                   +  - ]
     360                 :           1 :     nodes[1]->SetCommonVersion(PROTOCOL_VERSION);
     361         [ +  - ]:           1 :     peerLogic->InitializeNode(*nodes[1], NODE_NETWORK);
     362         [ +  - ]:           1 :     nodes[1]->fSuccessfullyConnected = true;
     363         [ +  - ]:           1 :     connman->AddTestNode(*nodes[1]);
     364   [ +  -  +  -  :           2 :     BOOST_CHECK(peerLogic->SendMessages(*nodes[1]));
             +  -  +  - ]
     365                 :             :     // [0] is still discouraged/disconnected.
     366   [ +  -  +  -  :           2 :     BOOST_CHECK(banman->IsDiscouraged(addr[0]));
             +  -  +  - ]
     367   [ +  -  +  -  :           2 :     BOOST_CHECK(nodes[0]->fDisconnect);
                   +  - ]
     368                 :             :     // [1] is not discouraged/disconnected yet.
     369   [ +  -  +  -  :           2 :     BOOST_CHECK(!banman->IsDiscouraged(addr[1]));
             +  -  +  - ]
     370   [ +  -  +  -  :           2 :     BOOST_CHECK(!nodes[1]->fDisconnect);
                   +  - ]
     371         [ +  - ]:           1 :     peerLogic->UnitTestMisbehaving(nodes[1]->GetId());
     372   [ +  -  +  -  :           2 :     BOOST_CHECK(peerLogic->SendMessages(*nodes[1]));
             +  -  +  - ]
     373                 :             :     // Expect both [0] and [1] to be discouraged/disconnected now.
     374   [ +  -  +  -  :           2 :     BOOST_CHECK(banman->IsDiscouraged(addr[0]));
             +  -  +  - ]
     375   [ +  -  +  -  :           2 :     BOOST_CHECK(nodes[0]->fDisconnect);
                   +  - ]
     376   [ +  -  +  -  :           2 :     BOOST_CHECK(banman->IsDiscouraged(addr[1]));
             +  -  +  - ]
     377   [ +  -  +  -  :           2 :     BOOST_CHECK(nodes[1]->fDisconnect);
                   +  - ]
     378                 :             : 
     379                 :             :     // Make sure non-IP peers are discouraged and disconnected properly.
     380                 :             : 
     381                 :           2 :     nodes[2] = new CNode{id++,
     382                 :             :                          /*sock=*/nullptr,
     383         [ +  - ]:           1 :                          addr[2],
     384                 :             :                          /*nKeyedNetGroupIn=*/1,
     385                 :             :                          /*nLocalHostNonceIn=*/1,
     386                 :           1 :                          CAddress(),
     387         [ +  - ]:           2 :                          /*addrNameIn=*/"",
     388                 :             :                          ConnectionType::OUTBOUND_FULL_RELAY,
     389                 :             :                          /*inbound_onion=*/false,
     390   [ +  -  +  -  :           2 :                          /*network_key=*/2};
                   +  - ]
     391                 :           1 :     nodes[2]->SetCommonVersion(PROTOCOL_VERSION);
     392         [ +  - ]:           1 :     peerLogic->InitializeNode(*nodes[2], NODE_NETWORK);
     393         [ +  - ]:           1 :     nodes[2]->fSuccessfullyConnected = true;
     394         [ +  - ]:           1 :     connman->AddTestNode(*nodes[2]);
     395                 :             : 
     396                 :           2 :     nodes[3] = new CNode{/*id=*/id++,
     397                 :             :                          /*sock=*/nullptr,
     398         [ +  - ]:           1 :                          /*addrIn=*/addr[2],
     399                 :             :                          /*nKeyedNetGroupIn=*/0,
     400                 :             :                          /*nLocalHostNonceIn=*/0,
     401         [ -  + ]:           1 :                          /*addrBindIn=*/CAddress{},
     402         [ +  - ]:           2 :                          /*addrNameIn=*/"",
     403                 :             :                          /*conn_type_in=*/ConnectionType::PRIVATE_BROADCAST,
     404                 :             :                          /*inbound_onion=*/false,
     405   [ +  -  +  -  :           2 :                          /*network_key=*/0};
                   +  - ]
     406         [ +  - ]:           1 :     peerLogic->InitializeNode(*nodes[3], NODE_NETWORK);
     407         [ +  - ]:           1 :     connman->AddTestNode(*nodes[3]);
     408                 :             : 
     409         [ +  - ]:           1 :     peerLogic->UnitTestMisbehaving(nodes[2]->GetId());
     410   [ +  -  +  -  :           2 :     BOOST_CHECK(peerLogic->SendMessages(*nodes[2]));
             +  -  +  - ]
     411   [ +  -  +  -  :           2 :     BOOST_CHECK(banman->IsDiscouraged(addr[0]));
             +  -  +  - ]
     412   [ +  -  +  -  :           2 :     BOOST_CHECK(banman->IsDiscouraged(addr[1]));
             +  -  +  - ]
     413   [ +  -  +  -  :           2 :     BOOST_CHECK(banman->IsDiscouraged(addr[2]));
             +  -  +  - ]
     414   [ +  -  +  -  :           2 :     BOOST_CHECK(nodes[0]->fDisconnect);
                   +  - ]
     415   [ +  -  +  -  :           2 :     BOOST_CHECK(nodes[1]->fDisconnect);
                   +  - ]
     416   [ +  -  +  -  :           2 :     BOOST_CHECK(nodes[2]->fDisconnect);
                   +  - ]
     417   [ +  -  +  -  :           2 :     BOOST_CHECK(!nodes[3]->fDisconnect);
                   +  - ]
     418                 :             : 
     419                 :           2 :     nodes[4] = new CNode{/*id=*/id++,
     420                 :             :                          /*sock=*/nullptr,
     421   [ +  -  +  -  :           3 :                          /*addrIn=*/CAddress{CService{other_addr, Params().GetDefaultPort()}, NODE_NONE},
                   -  + ]
     422                 :             :                          /*nKeyedNetGroupIn=*/0,
     423                 :             :                          /*nLocalHostNonceIn=*/0,
     424                 :           1 :                          /*addrBindIn=*/CAddress{},
     425         [ +  - ]:           2 :                          /*addrNameIn=*/"",
     426                 :             :                          /*conn_type_in=*/ConnectionType::PRIVATE_BROADCAST,
     427                 :             :                          /*inbound_onion=*/false,
     428   [ +  -  +  -  :           2 :                          /*network_key=*/0};
                   +  - ]
     429         [ +  - ]:           1 :     peerLogic->InitializeNode(*nodes[4], NODE_NETWORK);
     430         [ +  - ]:           1 :     connman->AddTestNode(*nodes[4]);
     431                 :             : 
     432         [ +  - ]:           1 :     peerLogic->UnitTestMisbehaving(nodes[4]->GetId());
     433   [ +  -  +  -  :           2 :     BOOST_CHECK(peerLogic->SendMessages(*nodes[4]));
             +  -  +  - ]
     434   [ +  -  +  -  :           2 :     BOOST_CHECK(nodes[4]->fDisconnect);
                   +  - ]
     435   [ +  -  +  -  :           2 :     BOOST_CHECK(!banman->IsDiscouraged(other_addr));
                   +  - ]
     436                 :             : 
     437         [ +  + ]:           6 :     for (CNode* node : nodes) {
     438         [ +  - ]:           5 :         peerLogic->FinalizeNode(*node);
     439                 :             :     }
     440         [ +  - ]:           1 :     connman->ClearTestNodes();
     441         [ +  - ]:           3 : }
     442                 :             : 
     443   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(DoS_bantime)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     444                 :             : {
     445                 :           1 :     LOCK(NetEventsInterface::g_msgproc_mutex);
     446                 :             : 
     447   [ +  -  +  - ]:           3 :     auto banman = std::make_unique<BanMan>(m_args.GetDataDirBase() / "banlist", nullptr, DEFAULT_MISBEHAVING_BANTIME);
     448   [ +  -  +  - ]:           1 :     auto connman = std::make_unique<CConnman>(0x1337, 0x1337, *m_node.addrman, *m_node.netgroupman, Params());
     449         [ +  - ]:           1 :     auto peerLogic = PeerManager::make(*connman, *m_node.addrman, banman.get(), *m_node.chainman, *m_node.mempool, *m_node.warnings, {});
     450                 :             : 
     451         [ +  - ]:           1 :     banman->ClearBanned();
     452         [ +  - ]:           1 :     const FakeNodeClock clock{}; // keep mocktime constant
     453                 :             : 
     454         [ +  - ]:           2 :     CAddress addr(ip(0xa0b0c001), NODE_NONE);
     455                 :           1 :     NodeId id{0};
     456                 :           1 :     CNode dummyNode{id++,
     457                 :             :                     /*sock=*/nullptr,
     458                 :             :                     addr,
     459                 :             :                     /*nKeyedNetGroupIn=*/4,
     460                 :             :                     /*nLocalHostNonceIn=*/4,
     461         [ -  + ]:           1 :                     CAddress(),
     462         [ +  - ]:           2 :                     /*addrNameIn=*/"",
     463                 :             :                     ConnectionType::INBOUND,
     464                 :             :                     /*inbound_onion=*/false,
     465   [ +  -  +  - ]:           2 :                     /*network_key=*/1};
     466                 :           1 :     dummyNode.SetCommonVersion(PROTOCOL_VERSION);
     467         [ +  - ]:           1 :     peerLogic->InitializeNode(dummyNode, NODE_NETWORK);
     468         [ +  - ]:           1 :     dummyNode.fSuccessfullyConnected = true;
     469                 :             : 
     470         [ +  - ]:           1 :     peerLogic->UnitTestMisbehaving(dummyNode.GetId());
     471   [ +  -  +  -  :           2 :     BOOST_CHECK(peerLogic->SendMessages(dummyNode));
             +  -  +  - ]
     472   [ +  -  +  -  :           2 :     BOOST_CHECK(banman->IsDiscouraged(addr));
             +  -  +  - ]
     473                 :             : 
     474         [ +  - ]:           1 :     peerLogic->FinalizeNode(dummyNode);
     475         [ +  - ]:           2 : }
     476                 :             : 
     477                 :             : // Reconsidering orphans must be interruptible: at most one orphan is accepted
     478                 :             : // or rejected per ProcessMessages() call.
     479                 :             : // See https://bitcoincore.org/en/2024/07/03/disclose-orphan-dos.
     480   [ +  -  +  -  :           7 : BOOST_FIXTURE_TEST_CASE(orphan_reconsideration_interruptible, TestChain100Setup)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     481                 :             : {
     482                 :           1 :     LOCK(NetEventsInterface::g_msgproc_mutex);
     483                 :             : 
     484         [ +  - ]:           1 :     ConnmanTestMsg& connman = static_cast<ConnmanTestMsg&>(*m_node.connman);
     485                 :           1 :     PeerManager& peerman = *m_node.peerman;
     486                 :           1 :     const CTxMemPool& mempool = *m_node.mempool;
     487                 :             : 
     488                 :           1 :     CNode peer{/*id=*/0,
     489                 :             :                /*sock=*/nullptr,
     490   [ +  -  -  + ]:           2 :                CAddress(ip(0xa0b0c001), NODE_NONE),
     491                 :             :                /*nKeyedNetGroupIn=*/0,
     492                 :             :                /*nLocalHostNonceIn=*/0,
     493                 :           1 :                CAddress(),
     494         [ +  - ]:           2 :                /*addrNameIn=*/"",
     495                 :             :                ConnectionType::OUTBOUND_FULL_RELAY,
     496                 :             :                /*inbound_onion=*/false,
     497   [ +  -  +  - ]:           2 :                /*network_key=*/0};
     498         [ +  - ]:           1 :     connman.Handshake(
     499                 :             :         /*node=*/peer,
     500                 :             :         /*successfully_connected=*/true,
     501                 :             :         /*remote_services=*/ServiceFlags(NODE_NETWORK | NODE_WITNESS),
     502                 :             :         /*local_services=*/ServiceFlags(NODE_NETWORK | NODE_WITNESS),
     503                 :             :         /*version=*/PROTOCOL_VERSION,
     504                 :             :         /*relay_txs=*/true);
     505                 :             : 
     506   [ +  -  +  - ]:           1 :     const CScript script{GetScriptForRawPubKey(coinbaseKey.GetPubKey())};
     507                 :           1 :     const int num_children{6};
     508   [ +  -  +  -  :           6 :     const auto parent{MakeTransactionRef(CreateValidMempoolTransaction(
          +  -  +  +  +  
          -  +  +  -  -  
             -  -  -  - ]
     509   [ +  -  +  - ]:           1 :         {m_coinbase_txns[0]}, {COutPoint{m_coinbase_txns[0]->GetHash(), 0}}, /*input_height=*/1, {coinbaseKey},
     510   [ +  -  +  - ]:           3 :         std::vector<CTxOut>(num_children, CTxOut{5 * COIN, script}), /*submit=*/false))};
     511                 :             : 
     512                 :           8 :     const auto send_tx{[&](const CTransactionRef& tx) EXCLUSIVE_LOCKS_REQUIRED(NetEventsInterface::g_msgproc_mutex) {
     513                 :           7 :         connman.FlushSendBuffer(peer); // Drop messages we sent, the transport is shared with the fake peer.
     514   [ +  -  +  -  :          21 :         BOOST_REQUIRE(connman.ReceiveMsgFrom(peer, NetMsg::Make(NetMsgType::TX, TX_WITH_WITNESS(*tx))));
             +  -  +  - ]
     515                 :           7 :         peer.fPauseSend = false;
     516                 :           7 :         return connman.ProcessMessagesOnce(peer);
     517                 :           1 :     }};
     518                 :             : 
     519                 :             :     // Children arrive first and become orphans. Half of them pay no fee and will be rejected.
     520         [ +  + ]:           7 :     for (int i{0}; i < num_children; ++i) {
     521         [ +  + ]:           6 :         const CAmount output_value{i % 2 ? 5 * COIN : 4 * COIN};
     522   [ +  -  +  -  :          36 :         send_tx(MakeTransactionRef(CreateValidMempoolTransaction(parent, i, /*input_height=*/101, coinbaseKey, script, output_value, /*submit=*/false)));
          +  -  +  -  +  
                      - ]
     523                 :             :     }
     524   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(peerman.GetOrphanTransactions().size(), num_children);
                   +  - ]
     525   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(mempool.size(), 0U);
                   +  - ]
     526                 :             : 
     527                 :             :     // Accepting the parent schedules all children for reconsideration.
     528   [ +  -  +  -  :           2 :     BOOST_CHECK(send_tx(parent));
             +  -  +  - ]
     529   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(peerman.GetOrphanTransactions().size(), num_children);
                   +  - ]
     530   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(mempool.size(), 1U);
                   +  - ]
     531                 :             : 
     532                 :             :     // Each call accepts or rejects exactly one orphan, whether it is valid or not.
     533         [ +  + ]:           7 :     for (int i{1}; i <= num_children; ++i) {
     534   [ +  -  +  -  :          12 :         BOOST_CHECK(connman.ProcessMessagesOnce(peer));
             +  -  +  - ]
     535   [ +  -  +  -  :          12 :         BOOST_CHECK_EQUAL(peerman.GetOrphanTransactions().size(), num_children - i);
                   +  - ]
     536                 :             :     }
     537   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(mempool.size(), 1U + num_children / 2);
                   +  - ]
     538   [ +  -  +  -  :           2 :     BOOST_CHECK(!connman.ProcessMessagesOnce(peer));
             +  -  +  - ]
     539                 :             : 
     540         [ +  - ]:           1 :     peerman.FinalizeNode(peer);
     541   [ +  -  +  -  :           4 : }
                   +  - ]
     542                 :             : 
     543                 :             : BOOST_AUTO_TEST_SUITE_END()
        

Generated by: LCOV version 2.0-1