LCOV - code coverage report
Current view: top level - src/test - DoS_tests.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 154 155 99.4 %
Date: 2025-02-23 09:33:43 Functions: 12 12 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2011-2014 The Bitcoin Core developers
       2             : // Copyright (c) 2019-2022 The PIVX Core developers
       3             : // Distributed under the MIT/X11 software license, see the accompanying
       4             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       5             : 
       6             : //
       7             : // Unit tests for denial-of-service detection/prevention code
       8             : //
       9             : 
      10             : #include "test/test_pivx.h"
      11             : 
      12             : #include "arith_uint256.h"
      13             : #include "keystore.h"
      14             : #include "net_processing.h"
      15             : #include "net.h"
      16             : #include "pubkey.h"
      17             : #include "pow.h"
      18             : #include "script/sign.h"
      19             : #include "serialize.h"
      20             : #include "util/system.h"
      21             : #include "validation.h"
      22             : 
      23             : #include <stdint.h>
      24             : 
      25             : #include <boost/test/unit_test.hpp>
      26             : 
      27             : // Tests this internal-to-validation.cpp method:
      28             : extern bool AddOrphanTx(const CTransactionRef& tx, NodeId peer);
      29             : extern void EraseOrphansFor(NodeId peer);
      30             : extern unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans);
      31             : struct COrphanTx {
      32             :     CTransactionRef tx;
      33             :     NodeId fromPeer;
      34             :     int64_t nTimeExpire;
      35             : };
      36             : extern RecursiveMutex g_cs_orphans;
      37             : extern std::map<uint256, COrphanTx> mapOrphanTransactions GUARDED_BY(g_cs_orphans);
      38             : 
      39           5 : CService ip(uint32_t i)
      40             : {
      41           5 :     struct in_addr s;
      42           5 :     s.s_addr = i;
      43          10 :     return CService(CNetAddr(s), Params().GetDefaultPort());
      44             : }
      45             : 
      46             : static NodeId id = 0;
      47             : 
      48             : BOOST_FIXTURE_TEST_SUITE(DoS_tests, TestingSetup)
      49             : 
      50           7 : void misbehave(NodeId id, int value) {
      51           7 :     LOCK(cs_main);
      52          14 :     Misbehaving(id, value); // Should get banned
      53           7 : }
      54             : 
      55           2 : BOOST_AUTO_TEST_CASE(DoS_banning)
      56             : {
      57           1 :     std::atomic<bool> interruptDummy(false);
      58             : 
      59           1 :     connman->ClearBanned();
      60           2 :     CAddress addr1(ip(0xa0b0c001), NODE_NONE);
      61           2 :     CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 0, 0, "", true);
      62           1 :     dummyNode1.SetSendVersion(PROTOCOL_VERSION);
      63           1 :     peerLogic->InitializeNode(&dummyNode1);
      64           1 :     dummyNode1.nVersion = 1;
      65           1 :     dummyNode1.fSuccessfullyConnected = true;
      66           1 :     misbehave(dummyNode1.GetId(), 100); // Should get banned
      67           1 :     {
      68           2 :         LOCK2(cs_main, dummyNode1.cs_sendProcessing);
      69           1 :         peerLogic->SendMessages(&dummyNode1, interruptDummy);
      70             :     }
      71           2 :     BOOST_CHECK(connman->IsBanned(addr1));
      72           2 :     BOOST_CHECK(!connman->IsBanned(ip(0xa0b0c001|0x0000ff00))); // Different IP, not banned
      73             : 
      74           3 :     CAddress addr2(ip(0xa0b0c002), NODE_NONE);
      75           2 :     CNode dummyNode2(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr2, 1, 1, "", true);
      76           1 :     dummyNode2.SetSendVersion(PROTOCOL_VERSION);
      77           1 :     peerLogic->InitializeNode(&dummyNode2);
      78           1 :     dummyNode2.nVersion = 1;
      79           1 :     dummyNode2.fSuccessfullyConnected = true;
      80           1 :     misbehave(dummyNode2.GetId(), 50);
      81           1 :     {
      82           2 :         LOCK2(cs_main, dummyNode2.cs_sendProcessing);
      83           1 :         peerLogic->SendMessages(&dummyNode2, interruptDummy);
      84             :     }
      85           2 :     BOOST_CHECK(!connman->IsBanned(addr2)); // 2 not banned yet...
      86           2 :     BOOST_CHECK(connman->IsBanned(addr1));  // ... but 1 still should be
      87           1 :     misbehave(dummyNode2.GetId(), 50);
      88           1 :     {
      89           2 :         LOCK2(cs_main, dummyNode2.cs_sendProcessing);
      90           1 :         peerLogic->SendMessages(&dummyNode2, interruptDummy);
      91             :     }
      92           2 :     BOOST_CHECK(connman->IsBanned(addr2));
      93           1 : }
      94             : 
      95           2 : BOOST_AUTO_TEST_CASE(DoS_banscore)
      96             : {
      97           1 :     std::atomic<bool> interruptDummy(false);
      98             : 
      99           1 :     connman->ClearBanned();
     100           2 :     gArgs.ForceSetArg("-banscore", "111"); // because 11 is my favorite number
     101           2 :     CAddress addr1(ip(0xa0b0c001), NODE_NONE);
     102           2 :     CNode dummyNode1(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr1, 3, 1, "", true);
     103           1 :     dummyNode1.SetSendVersion(PROTOCOL_VERSION);
     104           1 :     peerLogic->InitializeNode(&dummyNode1);
     105           1 :     dummyNode1.nVersion = 1;
     106           1 :     dummyNode1.fSuccessfullyConnected = true;
     107           1 :     misbehave(dummyNode1.GetId(), 100);
     108           1 :     {
     109           2 :         LOCK2(cs_main, dummyNode1.cs_sendProcessing);
     110           1 :         peerLogic->SendMessages(&dummyNode1, interruptDummy);
     111             :     }
     112           2 :     BOOST_CHECK(!connman->IsBanned(addr1));
     113           1 :     misbehave(dummyNode1.GetId(), 10);
     114           1 :     {
     115           2 :         LOCK2(cs_main, dummyNode1.cs_sendProcessing);
     116           1 :         peerLogic->SendMessages(&dummyNode1, interruptDummy);
     117             :     }
     118           2 :     BOOST_CHECK(!connman->IsBanned(addr1));
     119           1 :     misbehave(dummyNode1.GetId(), 1);
     120           1 :     {
     121           2 :         LOCK2(cs_main, dummyNode1.cs_sendProcessing);
     122           1 :         peerLogic->SendMessages(&dummyNode1, interruptDummy);
     123             :     }
     124           2 :     BOOST_CHECK(connman->IsBanned(addr1));
     125           2 :     gArgs.ForceSetArg("-banscore", std::to_string(DEFAULT_BANSCORE_THRESHOLD));
     126           1 : }
     127             : 
     128           2 : BOOST_AUTO_TEST_CASE(DoS_bantime)
     129             : {
     130           1 :     std::atomic<bool> interruptDummy(false);
     131             : 
     132           1 :     connman->ClearBanned();
     133           1 :     int64_t nStartTime = GetTime();
     134           1 :     SetMockTime(nStartTime); // Overrides future calls to GetTime()
     135             : 
     136           2 :     CAddress addr(ip(0xa0b0c001), NODE_NONE);
     137           3 :     CNode dummyNode(id++, NODE_NETWORK, 0, INVALID_SOCKET, addr, 4, 4, "", true);
     138           1 :     dummyNode.SetSendVersion(PROTOCOL_VERSION);
     139           1 :     peerLogic->InitializeNode(&dummyNode);
     140           1 :     dummyNode.nVersion = 1;
     141           1 :     dummyNode.fSuccessfullyConnected = true;
     142             : 
     143           1 :     misbehave(dummyNode.GetId(), 100);
     144           1 :     {
     145           2 :         LOCK2(cs_main, dummyNode.cs_sendProcessing);
     146           1 :         peerLogic->SendMessages(&dummyNode, interruptDummy);
     147             :     }
     148           2 :     BOOST_CHECK(connman->IsBanned(addr));
     149             : 
     150           1 :     SetMockTime(nStartTime+60*60);
     151           2 :     BOOST_CHECK(connman->IsBanned(addr));
     152             : 
     153           1 :     SetMockTime(nStartTime+60*60*24+1);
     154           2 :     BOOST_CHECK(!connman->IsBanned(addr));
     155           1 : }
     156             : 
     157          60 : CTransactionRef RandomOrphan()
     158             : {
     159          60 :     std::map<uint256, COrphanTx>::iterator it;
     160         120 :     LOCK2(cs_main, g_cs_orphans);
     161          60 :     it = mapOrphanTransactions.lower_bound(InsecureRand256());
     162          60 :     if (it == mapOrphanTransactions.end())
     163           0 :         it = mapOrphanTransactions.begin();
     164         120 :     return it->second.tx;
     165             : }
     166             : 
     167           1 : static void MakeNewKeyWithFastRandomContext(CKey& key)
     168             : {
     169           1 :     std::vector<unsigned char> keydata;
     170           1 :     keydata = g_insecure_rand_ctx.randbytes(32);
     171           1 :     key.Set(keydata.data(), keydata.data() + keydata.size(), /*fCompressedIn*/ true);
     172           1 :     assert(key.IsValid());
     173           1 : }
     174             : 
     175           2 : BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
     176             : {
     177             :     // This test had non-deterministic coverage due to
     178             :     // randomly selected seeds.
     179             :     // This seed is chosen so that all branches of the function
     180             :     // ecdsa_signature_parse_der_lax are executed during this test.
     181             :     // Specifically branches that run only when an ECDSA
     182             :     // signature's R and S values have leading zeros.
     183           2 :     g_insecure_rand_ctx = FastRandomContext(ArithToUint256(arith_uint256(33)));
     184             : 
     185           1 :     CKey key;
     186           1 :     MakeNewKeyWithFastRandomContext(key);
     187           2 :     CBasicKeyStore keystore;
     188           1 :     keystore.AddKey(key);
     189             : 
     190             :     // 50 orphan transactions:
     191          51 :     for (int i = 0; i < 50; i++)
     192             :     {
     193          50 :         CMutableTransaction tx;
     194          50 :         tx.vin.resize(1);
     195          50 :         tx.vin[0].prevout.n = 0;
     196          50 :         tx.vin[0].prevout.hash = InsecureRand256();
     197          50 :         tx.vin[0].scriptSig << OP_1;
     198          50 :         tx.vout.resize(1);
     199          50 :         tx.vout[0].nValue = 1*CENT;
     200          50 :         tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());
     201             : 
     202         100 :         AddOrphanTx(MakeTransactionRef(tx), i);
     203             :     }
     204             : 
     205             :     // ... and 50 that depend on other orphans:
     206          51 :     for (int i = 0; i < 50; i++)
     207             :     {
     208         100 :         CTransactionRef txPrev = RandomOrphan();
     209             : 
     210         100 :         CMutableTransaction tx;
     211          50 :         tx.vin.resize(1);
     212          50 :         tx.vin[0].prevout.n = 0;
     213          50 :         tx.vin[0].prevout.hash = txPrev->GetHash();
     214          50 :         tx.vout.resize(1);
     215          50 :         tx.vout[0].nValue = 1*CENT;
     216          50 :         tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());
     217          50 :         SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL);
     218             : 
     219         100 :         AddOrphanTx(MakeTransactionRef(tx), i);
     220             :     }
     221             : 
     222             :     // This really-big orphan should be ignored:
     223          11 :     for (int i = 0; i < 10; i++)
     224             :     {
     225          20 :         CTransactionRef txPrev = RandomOrphan();
     226             : 
     227          20 :         CMutableTransaction tx;
     228          10 :         tx.vout.resize(1);
     229          10 :         tx.vout[0].nValue = 1*CENT;
     230          10 :         tx.vout[0].scriptPubKey = GetScriptForDestination(key.GetPubKey().GetID());
     231          10 :         tx.vin.resize(2777);
     232       27780 :         for (unsigned int j = 0; j < tx.vin.size(); j++)
     233             :         {
     234       27770 :             tx.vin[j].prevout.n = j;
     235       27770 :             tx.vin[j].prevout.hash = txPrev->GetHash();
     236             :         }
     237          10 :         SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL);
     238             :         // Re-use same signature for other inputs
     239             :         // (they don't have to be valid for this test)
     240       27770 :         for (unsigned int j = 1; j < tx.vin.size(); j++)
     241       27760 :             tx.vin[j].scriptSig = tx.vin[0].scriptSig;
     242             : 
     243          30 :         BOOST_CHECK(!AddOrphanTx(MakeTransactionRef(tx), i));
     244             :     }
     245             : 
     246           3 :     LOCK2(cs_main, g_cs_orphans);
     247             :     // Test EraseOrphansFor:
     248           4 :     for (NodeId i = 0; i < 3; i++)
     249             :     {
     250           3 :         size_t sizeBefore = mapOrphanTransactions.size();
     251           3 :         EraseOrphansFor(i);
     252           6 :         BOOST_CHECK(mapOrphanTransactions.size() < sizeBefore);
     253             :     }
     254             : 
     255             :     // Test LimitOrphanTxSize() function:
     256           1 :     LimitOrphanTxSize(40);
     257           2 :     BOOST_CHECK(mapOrphanTransactions.size() <= 40);
     258           1 :     LimitOrphanTxSize(10);
     259           2 :     BOOST_CHECK(mapOrphanTransactions.size() <= 10);
     260           1 :     LimitOrphanTxSize(0);
     261           2 :     BOOST_CHECK(mapOrphanTransactions.empty());
     262           1 : }
     263             : 
     264             : BOOST_AUTO_TEST_SUITE_END()

Generated by: LCOV version 1.14