LCOV - code coverage report
Current view: top level - src/test - orphanage_tests.cpp (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 98.9 % 553 547
Test Date: 2025-08-01 05:08:13 Functions: 100.0 % 21 21
Branches: 50.7 % 2696 1366

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2011-2022 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                 :             : #include <arith_uint256.h>
       6                 :             : #include <consensus/validation.h>
       7                 :             : #include <node/txorphanage.h>
       8                 :             : #include <policy/policy.h>
       9                 :             : #include <primitives/transaction.h>
      10                 :             : #include <pubkey.h>
      11                 :             : #include <script/sign.h>
      12                 :             : #include <script/signingprovider.h>
      13                 :             : #include <test/util/random.h>
      14                 :             : #include <test/util/setup_common.h>
      15                 :             : #include <test/util/transaction_utils.h>
      16                 :             : 
      17                 :             : #include <array>
      18                 :             : #include <cstdint>
      19                 :             : 
      20                 :             : #include <boost/test/unit_test.hpp>
      21                 :             : 
      22                 :             : BOOST_FIXTURE_TEST_SUITE(orphanage_tests, TestingSetup)
      23                 :             : 
      24                 :         161 : static void MakeNewKeyWithFastRandomContext(CKey& key, FastRandomContext& rand_ctx)
      25                 :             : {
      26                 :         161 :     std::vector<unsigned char> keydata;
      27                 :         161 :     keydata = rand_ctx.randbytes(32);
      28         [ +  - ]:         161 :     key.Set(keydata.data(), keydata.data() + keydata.size(), /*fCompressedIn=*/true);
      29         [ -  + ]:         161 :     assert(key.IsValid());
      30                 :         161 : }
      31                 :             : 
      32                 :             : // Creates a transaction with 2 outputs. Spends all outpoints. If outpoints is empty, spends a random one.
      33                 :         160 : static CTransactionRef MakeTransactionSpending(const std::vector<COutPoint>& outpoints, FastRandomContext& det_rand)
      34                 :             : {
      35                 :         160 :     CKey key;
      36         [ +  - ]:         160 :     MakeNewKeyWithFastRandomContext(key, det_rand);
      37         [ +  - ]:         160 :     CMutableTransaction tx;
      38                 :             :     // If no outpoints are given, create a random one.
      39         [ +  + ]:         160 :     if (outpoints.empty()) {
      40         [ +  - ]:         117 :         tx.vin.emplace_back(Txid::FromUint256(det_rand.rand256()), 0);
      41                 :             :     } else {
      42         [ +  + ]:         704 :         for (const auto& outpoint : outpoints) {
      43         [ +  - ]:         661 :             tx.vin.emplace_back(outpoint);
      44                 :             :         }
      45                 :             :     }
      46                 :             :     // Ensure txid != wtxid
      47   [ +  -  +  - ]:         320 :     tx.vin[0].scriptWitness.stack.push_back({1});
      48         [ +  - ]:         160 :     tx.vout.resize(2);
      49         [ +  - ]:         160 :     tx.vout[0].nValue = CENT;
      50   [ +  -  +  -  :         160 :     tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
                   +  - ]
      51         [ +  - ]:         160 :     tx.vout[1].nValue = 3 * CENT;
      52   [ +  -  +  -  :         160 :     tx.vout[1].scriptPubKey = GetScriptForDestination(WitnessV0KeyHash(key.GetPubKey()));
                   +  - ]
      53         [ +  - ]:         320 :     return MakeTransactionRef(tx);
      54                 :         160 : }
      55                 :             : 
      56                 :             : // Make another (not necessarily valid) tx with the same txid but different wtxid.
      57                 :           3 : static CTransactionRef MakeMutation(const CTransactionRef& ptx)
      58                 :             : {
      59                 :           3 :     CMutableTransaction tx(*ptx);
      60   [ +  -  +  - ]:           6 :     tx.vin[0].scriptWitness.stack.push_back({5});
      61         [ +  - ]:           3 :     auto mutated_tx = MakeTransactionRef(tx);
      62         [ -  + ]:           3 :     assert(ptx->GetHash() == mutated_tx->GetHash());
      63                 :           3 :     return mutated_tx;
      64                 :           3 : }
      65                 :             : 
      66                 :           4 : static bool EqualTxns(const std::set<CTransactionRef>& set_txns, const std::vector<CTransactionRef>& vec_txns)
      67                 :             : {
      68         [ +  - ]:           4 :     if (vec_txns.size() != set_txns.size()) return false;
      69         [ +  + ]:           9 :     for (const auto& tx : vec_txns) {
      70         [ +  - ]:           5 :         if (!set_txns.contains(tx)) return false;
      71                 :             :     }
      72                 :             :     return true;
      73                 :             : }
      74                 :             : 
      75                 :         122 : unsigned int CheckNumEvictions(node::TxOrphanage& orphanage)
      76                 :             : {
      77                 :         122 :     const auto original_total_count{orphanage.CountAnnouncements()};
      78                 :         122 :     orphanage.LimitOrphans();
      79         [ -  + ]:         122 :     assert(orphanage.TotalLatencyScore() <= orphanage.MaxGlobalLatencyScore());
      80         [ -  + ]:         122 :     assert(orphanage.TotalOrphanUsage() <= orphanage.MaxGlobalUsage());
      81                 :         122 :     return original_total_count - orphanage.CountAnnouncements();
      82                 :             : }
      83                 :             : 
      84   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(peer_dos_limits)
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
      85                 :             : {
      86                 :           1 :     FastRandomContext det_rand{true};
      87                 :             : 
      88                 :             :     // Construct transactions to use. They must all be the same size.
      89                 :           1 :     static constexpr unsigned int NUM_TXNS_CREATED = 100;
      90                 :           1 :     static constexpr int64_t TX_SIZE{469};
      91                 :           1 :     static constexpr int64_t TOTAL_SIZE = NUM_TXNS_CREATED * TX_SIZE;
      92                 :             : 
      93                 :           1 :     std::vector<CTransactionRef> txns;
      94         [ +  - ]:           1 :     txns.reserve(NUM_TXNS_CREATED);
      95                 :             :     // All transactions are the same size.
      96         [ +  + ]:         101 :     for (unsigned int i{0}; i < NUM_TXNS_CREATED; ++i) {
      97         [ +  - ]:         100 :         auto ptx = MakeTransactionSpending({}, det_rand);
      98         [ +  - ]:         100 :         txns.emplace_back(ptx);
      99   [ +  -  +  -  :         100 :         BOOST_CHECK_EQUAL(TX_SIZE, GetTransactionWeight(*ptx));
                   +  - ]
     100                 :         100 :     }
     101                 :             : 
     102                 :             :     // Single peer: eviction is triggered if either limit is hit
     103                 :           1 :     {
     104                 :             :         // Test announcement limits
     105                 :           1 :         NodeId peer{8};
     106                 :           1 :         auto orphanage_low_ann = node::MakeTxOrphanage(/*max_global_ann=*/1, /*reserved_peer_usage=*/TX_SIZE * 10);
     107                 :           1 :         auto orphanage_low_mem = node::MakeTxOrphanage(/*max_global_ann=*/10, /*reserved_peer_usage=*/TX_SIZE);
     108                 :             : 
     109   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(CheckNumEvictions(*orphanage_low_mem), 0);
                   +  - ]
     110   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(CheckNumEvictions(*orphanage_low_ann), 0);
                   +  - ]
     111                 :             : 
     112                 :             :         // Add the first transaction
     113   [ +  -  +  - ]:           1 :         orphanage_low_ann->AddTx(txns.at(0), peer);
     114   [ +  -  +  - ]:           1 :         orphanage_low_mem->AddTx(txns.at(0), peer);
     115                 :             : 
     116                 :             :         // Add more. One of the limits is exceeded, so LimitOrphans evicts 1.
     117   [ +  -  +  - ]:           1 :         orphanage_low_ann->AddTx(txns.at(1), peer);
     118   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage_low_ann->TotalLatencyScore() > orphanage_low_ann->MaxGlobalLatencyScore());
          +  -  +  -  +  
                      - ]
     119   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage_low_ann->TotalOrphanUsage() <= orphanage_low_ann->MaxGlobalUsage());
          +  -  +  -  +  
                      - ]
     120                 :             : 
     121   [ +  -  +  - ]:           1 :         orphanage_low_mem->AddTx(txns.at(1), peer);
     122   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage_low_mem->TotalLatencyScore() <= orphanage_low_mem->MaxGlobalLatencyScore());
          +  -  +  -  +  
                      - ]
     123   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage_low_mem->TotalOrphanUsage() > orphanage_low_mem->MaxGlobalUsage());
          +  -  +  -  +  
                      - ]
     124                 :             : 
     125   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(CheckNumEvictions(*orphanage_low_mem), 1);
                   +  - ]
     126   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(CheckNumEvictions(*orphanage_low_ann), 1);
                   +  - ]
     127                 :             : 
     128                 :             :         // The older transaction is evicted.
     129   [ +  -  +  -  :           2 :         BOOST_CHECK(!orphanage_low_ann->HaveTx(txns.at(0)->GetWitnessHash()));
          +  -  +  -  +  
                      - ]
     130   [ +  -  +  -  :           2 :         BOOST_CHECK(!orphanage_low_mem->HaveTx(txns.at(0)->GetWitnessHash()));
          +  -  +  -  +  
                      - ]
     131   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage_low_ann->HaveTx(txns.at(1)->GetWitnessHash()));
          +  -  +  -  +  
                      - ]
     132   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage_low_mem->HaveTx(txns.at(1)->GetWitnessHash()));
             +  -  +  - ]
     133                 :           1 :     }
     134                 :             : 
     135                 :             :     // Single peer: latency score includes inputs
     136                 :           1 :     {
     137                 :             :         // Test latency score limits
     138                 :           1 :         NodeId peer{10};
     139                 :           1 :         auto orphanage_low_ann = node::MakeTxOrphanage(/*max_global_ann=*/5, /*reserved_peer_usage=*/TX_SIZE * 1000);
     140                 :             : 
     141   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(CheckNumEvictions(*orphanage_low_ann), 0);
                   +  - ]
     142                 :             : 
     143                 :             :         // Add the first transaction
     144   [ +  -  +  - ]:           1 :         orphanage_low_ann->AddTx(txns.at(0), peer);
     145                 :             : 
     146                 :             :         // Add 1 more transaction with 45 inputs. Even though there are only 2 announcements, this pushes the orphanage above its maximum latency score.
     147                 :           1 :         std::vector<COutPoint> outpoints_45;
     148         [ +  + ]:          46 :         for (unsigned int j{0}; j < 45; ++j) {
     149         [ +  - ]:          45 :             outpoints_45.emplace_back(Txid::FromUint256(det_rand.rand256()), j);
     150                 :             :         }
     151         [ +  - ]:           1 :         auto ptx = MakeTransactionSpending(outpoints_45, det_rand);
     152         [ +  - ]:           1 :         orphanage_low_ann->AddTx(ptx, peer);
     153                 :             : 
     154   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage_low_ann->TotalLatencyScore() > orphanage_low_ann->MaxGlobalLatencyScore());
          +  -  +  -  +  
                      - ]
     155   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage_low_ann->LatencyScoreFromPeer(peer) > orphanage_low_ann->MaxPeerLatencyScore());
          +  -  +  -  +  
                      - ]
     156                 :             : 
     157   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(CheckNumEvictions(*orphanage_low_ann), 1);
                   +  - ]
     158                 :             : 
     159                 :             :         // The older transaction is evicted.
     160   [ +  -  +  -  :           2 :         BOOST_CHECK(!orphanage_low_ann->HaveTx(txns.at(0)->GetWitnessHash()));
          +  -  +  -  +  
                      - ]
     161   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage_low_ann->HaveTx(ptx->GetWitnessHash()));
             +  -  +  - ]
     162                 :           1 :     }
     163                 :             : 
     164                 :             :     // Single peer: eviction order is FIFO on non-reconsiderable, then reconsiderable orphans.
     165                 :           1 :     {
     166                 :             :         // Construct parent + child pairs
     167                 :           1 :         std::vector<CTransactionRef> parents;
     168                 :           1 :         std::vector<CTransactionRef> children;
     169         [ +  + ]:          11 :         for (unsigned int i{0}; i < 10; ++i) {
     170         [ +  - ]:          10 :             CTransactionRef parent = MakeTransactionSpending({}, det_rand);
     171   [ +  -  +  -  :          20 :             CTransactionRef child = MakeTransactionSpending({{parent->GetHash(), 0}}, det_rand);
                   +  - ]
     172         [ +  - ]:          10 :             parents.emplace_back(parent);
     173         [ +  - ]:          10 :             children.emplace_back(child);
     174         [ +  - ]:          20 :         }
     175                 :             : 
     176                 :             :         // Test announcement limits
     177                 :           1 :         NodeId peer{9};
     178                 :           1 :         auto orphanage = node::MakeTxOrphanage(/*max_global_ann=*/3, /*reserved_peer_usage=*/TX_SIZE * 10);
     179                 :             : 
     180                 :             :         // First add a tx which will be made reconsiderable.
     181   [ +  -  +  - ]:           1 :         orphanage->AddTx(children.at(0), peer);
     182                 :             : 
     183                 :             :         // Then add 2 more orphans... not oversize yet.
     184   [ +  -  +  - ]:           1 :         orphanage->AddTx(children.at(1), peer);
     185   [ +  -  +  - ]:           1 :         orphanage->AddTx(children.at(2), peer);
     186                 :             : 
     187                 :             :         // Make child0 ready to reconsider
     188   [ +  -  +  - ]:           1 :         const std::vector<std::pair<Wtxid, NodeId>> expected_set_c0{std::make_pair(children.at(0)->GetWitnessHash(), peer)};
     189   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->AddChildrenToWorkSet(*parents.at(0), det_rand) == expected_set_c0);
          +  -  +  -  +  
                      - ]
     190   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->HaveTxToReconsider(peer));
             +  -  +  - ]
     191                 :             : 
     192                 :             :         // Add 1 more orphan, causing the orphanage to be oversize. child1 is evicted.
     193   [ +  -  +  - ]:           1 :         orphanage->AddTx(children.at(3), peer);
     194   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(CheckNumEvictions(*orphanage), 1);
                   +  - ]
     195   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->HaveTx(children.at(0)->GetWitnessHash()));
          +  -  +  -  +  
                      - ]
     196   [ +  -  +  -  :           2 :         BOOST_CHECK(!orphanage->HaveTx(children.at(1)->GetWitnessHash()));
          +  -  +  -  +  
                      - ]
     197   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->HaveTx(children.at(2)->GetWitnessHash()));
          +  -  +  -  +  
                      - ]
     198   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->HaveTx(children.at(3)->GetWitnessHash()));
          +  -  +  -  +  
                      - ]
     199                 :             : 
     200                 :             :         // Add 1 more... child2 is evicted.
     201   [ +  -  +  - ]:           1 :         orphanage->AddTx(children.at(4), peer);
     202   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(CheckNumEvictions(*orphanage), 1);
                   +  - ]
     203   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->HaveTx(children.at(0)->GetWitnessHash()));
          +  -  +  -  +  
                      - ]
     204   [ +  -  +  -  :           2 :         BOOST_CHECK(!orphanage->HaveTx(children.at(2)->GetWitnessHash()));
          +  -  +  -  +  
                      - ]
     205   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->HaveTx(children.at(3)->GetWitnessHash()));
          +  -  +  -  +  
                      - ]
     206   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->HaveTx(children.at(4)->GetWitnessHash()));
          +  -  +  -  +  
                      - ]
     207                 :             : 
     208                 :             :         // Eviction order is FIFO within the orphans that are read
     209   [ +  -  +  - ]:           1 :         const std::vector<std::pair<Wtxid, NodeId>> expected_set_c4{std::make_pair(children.at(4)->GetWitnessHash(), peer)};
     210   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->AddChildrenToWorkSet(*parents.at(4), det_rand) == expected_set_c4);
          +  -  +  -  +  
                      - ]
     211   [ +  -  +  - ]:           1 :         const std::vector<std::pair<Wtxid, NodeId>> expected_set_c3{std::make_pair(children.at(3)->GetWitnessHash(), peer)};
     212   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->AddChildrenToWorkSet(*parents.at(3), det_rand) == expected_set_c3);
          +  -  +  -  +  
                      - ]
     213                 :             : 
     214                 :             :         // child5 is evicted immediately because it is the only non-reconsiderable orphan.
     215   [ +  -  +  - ]:           1 :         orphanage->AddTx(children.at(5), peer);
     216   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(CheckNumEvictions(*orphanage), 1);
                   +  - ]
     217   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->HaveTx(children.at(0)->GetWitnessHash()));
          +  -  +  -  +  
                      - ]
     218   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->HaveTx(children.at(3)->GetWitnessHash()));
          +  -  +  -  +  
                      - ]
     219   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->HaveTx(children.at(4)->GetWitnessHash()));
          +  -  +  -  +  
                      - ]
     220   [ +  -  +  -  :           2 :         BOOST_CHECK(!orphanage->HaveTx(children.at(5)->GetWitnessHash()));
          +  -  +  -  +  
                      - ]
     221                 :             : 
     222                 :             :         // Transactions are marked non-reconsiderable again when returned through GetTxToReconsider
     223   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->GetTxToReconsider(peer), children.at(0));
          +  -  +  -  +  
                      - ]
     224   [ +  -  +  - ]:           1 :         orphanage->AddTx(children.at(6), peer);
     225   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(CheckNumEvictions(*orphanage), 1);
                   +  - ]
     226   [ +  -  +  -  :           2 :         BOOST_CHECK(!orphanage->HaveTx(children.at(0)->GetWitnessHash()));
          +  -  +  -  +  
                      - ]
     227   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->HaveTx(children.at(3)->GetWitnessHash()));
          +  -  +  -  +  
                      - ]
     228   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->HaveTx(children.at(4)->GetWitnessHash()));
          +  -  +  -  +  
                      - ]
     229   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->HaveTx(children.at(6)->GetWitnessHash()));
          +  -  +  -  +  
                      - ]
     230                 :             : 
     231                 :             :         // The first transaction returned from GetTxToReconsider is the older one, not the one that was marked for
     232                 :             :         // reconsideration earlier.
     233   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->GetTxToReconsider(peer), children.at(3));
          +  -  +  -  +  
                      - ]
     234   [ +  -  +  -  :           2 :         BOOST_CHECK_EQUAL(orphanage->GetTxToReconsider(peer), children.at(4));
          +  -  +  -  +  
                      - ]
     235                 :           1 :     }
     236                 :             : 
     237                 :             :     // Multiple peers: when limit is exceeded, we choose the DoSiest peer and evict their oldest transaction.
     238                 :           1 :     {
     239                 :           1 :         NodeId peer_dosy{0};
     240                 :           1 :         NodeId peer1{1};
     241                 :           1 :         NodeId peer2{2};
     242                 :             : 
     243                 :           1 :         unsigned int max_announcements = 60;
     244                 :             :         // Set a high per-peer reservation so announcement limit is always hit first.
     245                 :           1 :         auto orphanage = node::MakeTxOrphanage(max_announcements, TOTAL_SIZE * 10);
     246                 :             : 
     247                 :             :         // No evictions happen before the global limit is reached.
     248         [ +  + ]:          61 :         for (unsigned int i{0}; i < max_announcements; ++i) {
     249   [ +  -  +  - ]:          60 :             orphanage->AddTx(txns.at(i), peer_dosy);
     250   [ +  -  +  -  :          60 :             BOOST_CHECK_EQUAL(CheckNumEvictions(*orphanage), 0);
                   +  - ]
     251                 :             :         }
     252   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->AnnouncementsFromPeer(peer_dosy), max_announcements);
                   +  - ]
     253   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->AnnouncementsFromPeer(peer1), 0);
                   +  - ]
     254   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->AnnouncementsFromPeer(peer2), 0);
                   +  - ]
     255                 :             : 
     256                 :             :         // Add 10 unique transactions from peer1.
     257                 :             :         // LimitOrphans should evict from peer_dosy, because that's the one exceeding announcement limits.
     258                 :           1 :         unsigned int num_from_peer1 = 10;
     259         [ +  + ]:          11 :         for (unsigned int i{0}; i < num_from_peer1; ++i) {
     260   [ +  -  +  - ]:          10 :             orphanage->AddTx(txns.at(max_announcements + i), peer1);
     261                 :             :             // The announcement limit per peer has halved, but LimitOrphans does not evict beyond what is necessary to
     262                 :             :             // bring the total announcements within its global limit.
     263   [ +  -  +  -  :          10 :             BOOST_CHECK_EQUAL(CheckNumEvictions(*orphanage), 1);
                   +  - ]
     264   [ +  -  +  -  :          20 :             BOOST_CHECK(orphanage->AnnouncementsFromPeer(peer_dosy) > orphanage->MaxPeerLatencyScore());
          +  -  +  -  +  
                      - ]
     265                 :             : 
     266   [ +  -  +  -  :          10 :             BOOST_CHECK_EQUAL(orphanage->AnnouncementsFromPeer(peer1), i + 1);
                   +  - ]
     267   [ +  -  +  -  :          10 :             BOOST_CHECK_EQUAL(orphanage->AnnouncementsFromPeer(peer_dosy), max_announcements - i - 1);
                   +  - ]
     268                 :             : 
     269                 :             :             // Evictions are FIFO within a peer, so the ith transaction sent by peer_dosy is the one that was evicted.
     270   [ +  -  +  -  :          20 :             BOOST_CHECK(!orphanage->HaveTx(txns.at(i)->GetWitnessHash()));
             +  -  +  - ]
     271                 :             :         }
     272                 :             :         // Add 10 transactions that are duplicates of the ones sent by peer_dosy. We need to add 10 because the first 10
     273                 :             :         // were just evicted in the previous block additions.
     274         [ +  + ]:          11 :         for (unsigned int i{num_from_peer1}; i < num_from_peer1 + 10; ++i) {
     275                 :             :             // Tx has already been sent by peer_dosy
     276   [ +  -  +  -  :          20 :             BOOST_CHECK(orphanage->HaveTxFromPeer(txns.at(i)->GetWitnessHash(), peer_dosy));
          +  -  +  -  +  
                      - ]
     277   [ +  -  +  - ]:          10 :             orphanage->AddTx(txns.at(i), peer2);
     278                 :             : 
     279                 :             :             // Announcement limit is by entry, not by unique orphans
     280   [ +  -  +  -  :          10 :             BOOST_CHECK_EQUAL(CheckNumEvictions(*orphanage), 1);
                   +  - ]
     281                 :             : 
     282                 :             :             // peer_dosy is still the only one getting evicted
     283   [ +  -  +  -  :          10 :             BOOST_CHECK_EQUAL(orphanage->AnnouncementsFromPeer(peer_dosy), max_announcements - i - 1);
                   +  - ]
     284   [ +  -  +  -  :          10 :             BOOST_CHECK_EQUAL(orphanage->AnnouncementsFromPeer(peer1), num_from_peer1);
                   +  - ]
     285   [ +  -  +  -  :          10 :             BOOST_CHECK_EQUAL(orphanage->AnnouncementsFromPeer(peer2), i + 1 - num_from_peer1);
                   +  - ]
     286                 :             : 
     287                 :             :             // Evictions are FIFO within a peer, so the ith transaction sent by peer_dosy is the one that was evicted.
     288   [ +  -  +  -  :          20 :             BOOST_CHECK(!orphanage->HaveTxFromPeer(txns.at(i)->GetWitnessHash(), peer_dosy));
          +  -  +  -  +  
                      - ]
     289   [ +  -  +  -  :          20 :             BOOST_CHECK(orphanage->HaveTx(txns.at(i)->GetWitnessHash()));
             +  -  +  - ]
     290                 :             :         }
     291                 :             : 
     292                 :             :         // With 6 peers, each can add 10, and still only peer_dosy's orphans are evicted.
     293                 :           1 :         const unsigned int max_per_peer{max_announcements / 6};
     294         [ +  + ]:           4 :         for (NodeId peer{3}; peer < 6; ++peer) {
     295         [ +  + ]:          33 :             for (unsigned int i{0}; i < max_per_peer; ++i) {
     296   [ +  -  +  - ]:          30 :                 orphanage->AddTx(txns.at(peer * max_per_peer + i), peer);
     297   [ +  -  +  -  :          30 :                 BOOST_CHECK_EQUAL(CheckNumEvictions(*orphanage), 1);
                   +  - ]
     298                 :             :             }
     299                 :             :         }
     300         [ +  + ]:           7 :         for (NodeId peer{0}; peer < 6; ++peer) {
     301   [ +  -  +  -  :           6 :             BOOST_CHECK_EQUAL(orphanage->AnnouncementsFromPeer(peer), max_per_peer);
                   +  - ]
     302                 :             :         }
     303                 :           1 :     }
     304                 :             : 
     305                 :             :     // Limits change as more peers are added.
     306                 :           1 :     {
     307                 :           1 :         auto orphanage{node::MakeTxOrphanage()};
     308                 :             :         // These stay the same regardless of number of peers
     309   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->MaxGlobalLatencyScore(), node::DEFAULT_MAX_ORPHANAGE_LATENCY_SCORE);
                   +  - ]
     310   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->ReservedPeerUsage(), node::DEFAULT_RESERVED_ORPHAN_WEIGHT_PER_PEER);
                   +  - ]
     311                 :             : 
     312                 :             :         // These change with number of peers
     313   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->MaxGlobalUsage(), node::DEFAULT_RESERVED_ORPHAN_WEIGHT_PER_PEER);
                   +  - ]
     314   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->MaxPeerLatencyScore(), node::DEFAULT_MAX_ORPHANAGE_LATENCY_SCORE);
                   +  - ]
     315                 :             : 
     316                 :             :         // Number of peers = 1
     317   [ +  -  +  - ]:           1 :         orphanage->AddTx(txns.at(0), 0);
     318   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->MaxGlobalLatencyScore(), node::DEFAULT_MAX_ORPHANAGE_LATENCY_SCORE);
                   +  - ]
     319   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->ReservedPeerUsage(), node::DEFAULT_RESERVED_ORPHAN_WEIGHT_PER_PEER);
                   +  - ]
     320   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->MaxGlobalUsage(), node::DEFAULT_RESERVED_ORPHAN_WEIGHT_PER_PEER);
                   +  - ]
     321   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->MaxPeerLatencyScore(), node::DEFAULT_MAX_ORPHANAGE_LATENCY_SCORE);
                   +  - ]
     322                 :             : 
     323                 :             :         // Number of peers = 2
     324   [ +  -  +  - ]:           1 :         orphanage->AddTx(txns.at(1), 1);
     325   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->MaxGlobalLatencyScore(), node::DEFAULT_MAX_ORPHANAGE_LATENCY_SCORE);
                   +  - ]
     326   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->ReservedPeerUsage(), node::DEFAULT_RESERVED_ORPHAN_WEIGHT_PER_PEER);
                   +  - ]
     327   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->MaxGlobalUsage(), node::DEFAULT_RESERVED_ORPHAN_WEIGHT_PER_PEER * 2);
                   +  - ]
     328   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->MaxPeerLatencyScore(), node::DEFAULT_MAX_ORPHANAGE_LATENCY_SCORE / 2);
                   +  - ]
     329                 :             : 
     330                 :             :         // Number of peers = 3
     331   [ +  -  +  - ]:           1 :         orphanage->AddTx(txns.at(2), 2);
     332   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->MaxGlobalLatencyScore(), node::DEFAULT_MAX_ORPHANAGE_LATENCY_SCORE);
                   +  - ]
     333   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->ReservedPeerUsage(), node::DEFAULT_RESERVED_ORPHAN_WEIGHT_PER_PEER);
                   +  - ]
     334   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->MaxGlobalUsage(), node::DEFAULT_RESERVED_ORPHAN_WEIGHT_PER_PEER * 3);
                   +  - ]
     335   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->MaxPeerLatencyScore(), node::DEFAULT_MAX_ORPHANAGE_LATENCY_SCORE / 3);
                   +  - ]
     336                 :             : 
     337                 :             :         // Number of peers didn't change.
     338   [ +  -  +  - ]:           1 :         orphanage->AddTx(txns.at(3), 2);
     339   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->MaxGlobalLatencyScore(), node::DEFAULT_MAX_ORPHANAGE_LATENCY_SCORE);
                   +  - ]
     340   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->ReservedPeerUsage(), node::DEFAULT_RESERVED_ORPHAN_WEIGHT_PER_PEER);
                   +  - ]
     341   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->MaxGlobalUsage(), node::DEFAULT_RESERVED_ORPHAN_WEIGHT_PER_PEER * 3);
                   +  - ]
     342   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->MaxPeerLatencyScore(), node::DEFAULT_MAX_ORPHANAGE_LATENCY_SCORE / 3);
                   +  - ]
     343                 :             : 
     344                 :             :         // Once a peer has no orphans, it is not considered in the limits.
     345                 :             :         // Number of peers = 2
     346         [ +  - ]:           1 :         orphanage->EraseForPeer(2);
     347   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->MaxGlobalLatencyScore(), node::DEFAULT_MAX_ORPHANAGE_LATENCY_SCORE);
                   +  - ]
     348   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->ReservedPeerUsage(), node::DEFAULT_RESERVED_ORPHAN_WEIGHT_PER_PEER);
                   +  - ]
     349   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->MaxGlobalUsage(), node::DEFAULT_RESERVED_ORPHAN_WEIGHT_PER_PEER * 2);
                   +  - ]
     350   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->MaxPeerLatencyScore(), node::DEFAULT_MAX_ORPHANAGE_LATENCY_SCORE / 2);
                   +  - ]
     351                 :             : 
     352                 :             :         // Number of peers = 1
     353   [ +  -  +  - ]:           1 :         orphanage->EraseTx(txns.at(0)->GetWitnessHash());
     354   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->MaxGlobalLatencyScore(), node::DEFAULT_MAX_ORPHANAGE_LATENCY_SCORE);
                   +  - ]
     355   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->ReservedPeerUsage(), node::DEFAULT_RESERVED_ORPHAN_WEIGHT_PER_PEER);
                   +  - ]
     356   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->MaxGlobalUsage(), node::DEFAULT_RESERVED_ORPHAN_WEIGHT_PER_PEER);
                   +  - ]
     357   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->MaxPeerLatencyScore(), node::DEFAULT_MAX_ORPHANAGE_LATENCY_SCORE);
                   +  - ]
     358                 :           1 :     }
     359                 :             : 
     360                 :             :     // Test eviction of multiple transactions at a time
     361                 :           1 :     {
     362                 :             :         // Create a large transaction that is 10 times larger than the normal size transaction.
     363         [ +  - ]:           1 :         CMutableTransaction tx_large;
     364         [ +  - ]:           1 :         tx_large.vin.resize(1);
     365         [ +  - ]:           1 :         BulkTransaction(tx_large, 10 * TX_SIZE);
     366         [ +  - ]:           1 :         auto ptx_large = MakeTransactionRef(tx_large);
     367                 :             : 
     368                 :           1 :         const auto large_tx_size = GetTransactionWeight(*ptx_large);
     369   [ +  -  +  -  :           2 :         BOOST_CHECK(large_tx_size > 10 * TX_SIZE);
                   +  - ]
     370   [ +  -  +  - ]:           2 :         BOOST_CHECK(large_tx_size < 11 * TX_SIZE);
     371                 :             : 
     372                 :           1 :         auto orphanage = node::MakeTxOrphanage(20, large_tx_size);
     373                 :             :         // One peer sends 10 normal size transactions. The other peer sends 10 normal transactions and 1 very large one
     374                 :           1 :         NodeId peer_normal{0};
     375                 :           1 :         NodeId peer_large{1};
     376         [ +  + ]:          21 :         for (unsigned int i = 0; i < 20; i++) {
     377   [ +  +  +  -  :          30 :             orphanage->AddTx(txns.at(i), i < 10 ? peer_normal : peer_large);
                   +  - ]
     378                 :             :         }
     379   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->TotalLatencyScore() <= orphanage->MaxGlobalLatencyScore());
          +  -  +  -  +  
                      - ]
     380   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->TotalOrphanUsage() <= orphanage->MaxGlobalUsage());
          +  -  +  -  +  
                      - ]
     381   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(CheckNumEvictions(*orphanage), 0);
                   +  - ]
     382                 :             : 
     383                 :             :         // Add the large transaction. This should cause evictions of all the previous 10 transactions from that peer.
     384         [ +  - ]:           1 :         orphanage->AddTx(ptx_large, peer_large);
     385   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(CheckNumEvictions(*orphanage), 10);
                   +  - ]
     386                 :             : 
     387                 :             :         // peer_normal should still have 10 transactions, and peer_large should have 1.
     388   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->AnnouncementsFromPeer(peer_normal), 10);
                   +  - ]
     389   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->AnnouncementsFromPeer(peer_large), 1);
                   +  - ]
     390   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->HaveTxFromPeer(ptx_large->GetWitnessHash(), peer_large));
             +  -  +  - ]
     391   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->CountAnnouncements(), 11);
                   +  - ]
     392         [ +  - ]:           2 :     }
     393                 :             : 
     394                 :             :     // Test that latency score includes number of inputs.
     395                 :           1 :     {
     396                 :           1 :         auto orphanage = node::MakeTxOrphanage();
     397                 :             : 
     398                 :             :         // Add 10 transactions with 9 inputs each.
     399                 :           1 :         std::vector<COutPoint> outpoints_9;
     400         [ +  + ]:          10 :         for (unsigned int j{0}; j < 9; ++j) {
     401         [ +  - ]:           9 :             outpoints_9.emplace_back(Txid::FromUint256(m_rng.rand256()), j);
     402                 :             :         }
     403         [ +  + ]:          11 :         for (unsigned int i{0}; i < 10; ++i) {
     404         [ +  - ]:          10 :             auto ptx = MakeTransactionSpending(outpoints_9, m_rng);
     405         [ +  - ]:          10 :             orphanage->AddTx(ptx, 0);
     406                 :          10 :         }
     407   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->CountAnnouncements(), 10);
                   +  - ]
     408   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->TotalLatencyScore(), 10);
                   +  - ]
     409                 :             : 
     410                 :             :         // Add 10 transactions with 50 inputs each.
     411                 :           1 :         std::vector<COutPoint> outpoints_50;
     412         [ +  + ]:          51 :         for (unsigned int j{0}; j < 50; ++j) {
     413         [ +  - ]:          50 :             outpoints_50.emplace_back(Txid::FromUint256(m_rng.rand256()), j);
     414                 :             :         }
     415                 :             : 
     416         [ +  + ]:          11 :         for (unsigned int i{0}; i < 10; ++i) {
     417         [ +  - ]:          10 :             CMutableTransaction tx;
     418                 :          10 :             std::shuffle(outpoints_50.begin(), outpoints_50.end(), m_rng);
     419         [ +  - ]:          10 :             auto ptx = MakeTransactionSpending(outpoints_50, m_rng);
     420   [ +  -  +  -  :          20 :             BOOST_CHECK(orphanage->AddTx(ptx, 0));
             +  -  +  + ]
     421   [ +  +  +  -  :          15 :             if (i < 5) BOOST_CHECK(!orphanage->AddTx(ptx, 1));
             +  -  +  - ]
     422                 :          20 :         }
     423                 :             :         // 10 of the 9-input transactions + 10 of the 50-input transactions + 5 more announcements of the 50-input transactions
     424   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->CountAnnouncements(), 25);
                   +  - ]
     425                 :             :         // Base of 25 announcements, plus 10 * 5 for the 50-input transactions (counted just once)
     426   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->TotalLatencyScore(), 25 + 50);
                   +  - ]
     427                 :             : 
     428                 :             :         // Peer 0 sent all 20 transactions
     429   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->AnnouncementsFromPeer(0), 20);
                   +  - ]
     430   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->LatencyScoreFromPeer(0), 20 + 10 * 5);
                   +  - ]
     431                 :             : 
     432                 :             :         // Peer 1 sent 5 of the 10 transactions with many inputs
     433   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->AnnouncementsFromPeer(1), 5);
                   +  - ]
     434   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->LatencyScoreFromPeer(1), 5 + 5 * 5);
                   +  - ]
     435                 :           1 :     }
     436                 :           1 : }
     437   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(DoS_mapOrphans)
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     438                 :             : {
     439                 :             :     // This test had non-deterministic coverage due to
     440                 :             :     // randomly selected seeds.
     441                 :             :     // This seed is chosen so that all branches of the function
     442                 :             :     // ecdsa_signature_parse_der_lax are executed during this test.
     443                 :             :     // Specifically branches that run only when an ECDSA
     444                 :             :     // signature's R and S values have leading zeros.
     445                 :           1 :     m_rng.Reseed(uint256{33});
     446                 :             : 
     447                 :           1 :     std::unique_ptr<node::TxOrphanage> orphanage{node::MakeTxOrphanage()};
     448                 :           1 :     CKey key;
     449         [ +  - ]:           1 :     MakeNewKeyWithFastRandomContext(key, m_rng);
     450                 :           1 :     FillableSigningProvider keystore;
     451   [ +  -  +  -  :           2 :     BOOST_CHECK(keystore.AddKey(key));
                   +  - ]
     452                 :             : 
     453                 :             :     // Freeze time for length of test
     454                 :           1 :     auto now{GetTime<std::chrono::seconds>()};
     455         [ +  - ]:           1 :     SetMockTime(now);
     456                 :             : 
     457                 :           1 :     std::vector<CTransactionRef> orphans_added;
     458                 :             : 
     459                 :             :     // 50 orphan transactions:
     460         [ +  + ]:          51 :     for (int i = 0; i < 50; i++)
     461                 :             :     {
     462         [ +  - ]:          50 :         CMutableTransaction tx;
     463         [ +  - ]:          50 :         tx.vin.resize(1);
     464                 :          50 :         tx.vin[0].prevout.n = 0;
     465         [ +  - ]:          50 :         tx.vin[0].prevout.hash = Txid::FromUint256(m_rng.rand256());
     466         [ +  - ]:          50 :         tx.vin[0].scriptSig << OP_1;
     467         [ +  - ]:          50 :         tx.vout.resize(1);
     468         [ +  - ]:          50 :         tx.vout[0].nValue = i*CENT;
     469   [ +  -  +  -  :          50 :         tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
                   +  - ]
     470                 :             : 
     471         [ +  - ]:          50 :         auto ptx = MakeTransactionRef(tx);
     472         [ +  - ]:          50 :         orphanage->AddTx(ptx, i);
     473         [ +  - ]:          50 :         orphans_added.emplace_back(ptx);
     474                 :         100 :     }
     475                 :             : 
     476                 :             :     // ... and 50 that depend on other orphans:
     477         [ +  + ]:          51 :     for (int i = 0; i < 50; i++)
     478                 :             :     {
     479         [ +  - ]:          50 :         const auto& txPrev = orphans_added[m_rng.randrange(orphans_added.size())];
     480                 :             : 
     481         [ +  - ]:          50 :         CMutableTransaction tx;
     482         [ +  - ]:          50 :         tx.vin.resize(1);
     483         [ +  - ]:          50 :         tx.vin[0].prevout.n = 0;
     484         [ +  - ]:          50 :         tx.vin[0].prevout.hash = txPrev->GetHash();
     485         [ +  - ]:          50 :         tx.vout.resize(1);
     486         [ +  - ]:          50 :         tx.vout[0].nValue = i*CENT;
     487   [ +  -  +  -  :          50 :         tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
                   +  - ]
     488                 :          50 :         SignatureData empty;
     489   [ +  -  +  -  :         100 :         BOOST_CHECK(SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL, empty));
             +  -  +  - ]
     490                 :             : 
     491         [ +  - ]:          50 :         auto ptx = MakeTransactionRef(tx);
     492         [ +  - ]:          50 :         orphanage->AddTx(ptx, i);
     493         [ +  - ]:          50 :         orphans_added.emplace_back(ptx);
     494                 :         100 :     }
     495                 :             : 
     496                 :             :     // This really-big orphan should be ignored:
     497         [ +  + ]:          11 :     for (int i = 0; i < 10; i++)
     498                 :             :     {
     499         [ +  - ]:          10 :         const auto& txPrev = orphans_added[m_rng.randrange(orphans_added.size())];
     500                 :             : 
     501         [ +  - ]:          10 :         CMutableTransaction tx;
     502         [ +  - ]:          10 :         tx.vout.resize(1);
     503         [ +  - ]:          10 :         tx.vout[0].nValue = 1*CENT;
     504   [ +  -  +  -  :          10 :         tx.vout[0].scriptPubKey = GetScriptForDestination(PKHash(key.GetPubKey()));
                   +  - ]
     505         [ +  - ]:          10 :         tx.vin.resize(2777);
     506         [ +  + ]:       27780 :         for (unsigned int j = 0; j < tx.vin.size(); j++)
     507                 :             :         {
     508                 :       27770 :             tx.vin[j].prevout.n = j;
     509                 :       27770 :             tx.vin[j].prevout.hash = txPrev->GetHash();
     510                 :             :         }
     511                 :          10 :         SignatureData empty;
     512   [ +  -  +  -  :          20 :         BOOST_CHECK(SignSignature(keystore, *txPrev, tx, 0, SIGHASH_ALL, empty));
                   +  - ]
     513                 :             :         // Reuse same signature for other inputs
     514                 :             :         // (they don't have to be valid for this test)
     515         [ +  + ]:       27770 :         for (unsigned int j = 1; j < tx.vin.size(); j++)
     516                 :       27760 :             tx.vin[j].scriptSig = tx.vin[0].scriptSig;
     517                 :             : 
     518   [ +  -  +  -  :          40 :         BOOST_CHECK(!orphanage->AddTx(MakeTransactionRef(tx), i));
          +  -  +  -  +  
                      - ]
     519                 :          20 :     }
     520                 :             : 
     521         [ +  - ]:           1 :     size_t expected_num_orphans = orphanage->Size();
     522                 :             : 
     523                 :             :     // Non-existent peer; nothing should be deleted
     524         [ +  - ]:           1 :     orphanage->EraseForPeer(/*peer=*/-1);
     525   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(orphanage->Size(), expected_num_orphans);
                   +  - ]
     526                 :             : 
     527                 :             :     // Each of first three peers stored
     528                 :             :     // two transactions each.
     529         [ +  + ]:           4 :     for (NodeId i = 0; i < 3; i++)
     530                 :             :     {
     531         [ +  - ]:           3 :         orphanage->EraseForPeer(i);
     532                 :           3 :         expected_num_orphans -= 2;
     533   [ +  -  +  -  :           6 :         BOOST_CHECK(orphanage->Size() == expected_num_orphans);
                   +  - ]
     534                 :             :     }
     535                 :           1 : }
     536                 :             : 
     537   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(same_txid_diff_witness)
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     538                 :             : {
     539                 :           1 :     FastRandomContext det_rand{true};
     540                 :           1 :     std::unique_ptr<node::TxOrphanage> orphanage{node::MakeTxOrphanage()};
     541                 :           1 :     NodeId peer{0};
     542                 :             : 
     543                 :           1 :     std::vector<COutPoint> empty_outpoints;
     544         [ +  - ]:           1 :     auto parent = MakeTransactionSpending(empty_outpoints, det_rand);
     545                 :             : 
     546                 :             :     // Create children to go into orphanage.
     547   [ +  -  +  -  :           2 :     auto child_normal = MakeTransactionSpending({{parent->GetHash(), 0}}, det_rand);
                   +  - ]
     548         [ +  - ]:           1 :     auto child_mutated = MakeMutation(child_normal);
     549                 :             : 
     550         [ +  - ]:           1 :     const auto& normal_wtxid = child_normal->GetWitnessHash();
     551                 :           1 :     const auto& mutated_wtxid = child_mutated->GetWitnessHash();
     552   [ +  -  +  -  :           2 :     BOOST_CHECK(normal_wtxid != mutated_wtxid);
                   +  - ]
     553                 :             : 
     554   [ +  -  +  -  :           2 :     BOOST_CHECK(orphanage->AddTx(child_normal, peer));
             +  -  +  - ]
     555                 :             :     // EraseTx fails as transaction by this wtxid doesn't exist.
     556   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(orphanage->EraseTx(mutated_wtxid), 0);
                   +  - ]
     557   [ +  -  +  -  :           2 :     BOOST_CHECK(orphanage->HaveTx(normal_wtxid));
             +  -  +  - ]
     558   [ +  -  +  -  :           3 :     BOOST_CHECK(orphanage->GetTx(normal_wtxid) == child_normal);
          +  -  +  -  +  
                      - ]
     559   [ +  -  +  -  :           2 :     BOOST_CHECK(!orphanage->HaveTx(mutated_wtxid));
             +  -  +  - ]
     560   [ +  -  +  -  :           2 :     BOOST_CHECK(orphanage->GetTx(mutated_wtxid) == nullptr);
          +  -  -  +  +  
                      - ]
     561                 :             : 
     562                 :             :     // Must succeed. Both transactions should be present in orphanage.
     563   [ +  -  +  -  :           2 :     BOOST_CHECK(orphanage->AddTx(child_mutated, peer));
             +  -  +  - ]
     564   [ +  -  +  -  :           2 :     BOOST_CHECK(orphanage->HaveTx(normal_wtxid));
             +  -  +  - ]
     565   [ +  -  +  -  :           2 :     BOOST_CHECK(orphanage->HaveTx(mutated_wtxid));
             +  -  +  - ]
     566                 :             : 
     567                 :             :     // Outpoints map should track all entries: check that both are returned as children of the parent.
     568   [ +  +  +  -  :           3 :     std::set<CTransactionRef> expected_children{child_normal, child_mutated};
             -  -  -  - ]
     569   [ +  -  +  -  :           2 :     BOOST_CHECK(EqualTxns(expected_children, orphanage->GetChildrenFromSamePeer(parent, peer)));
             +  -  +  - ]
     570                 :             : 
     571                 :             :     // Erase by wtxid: mutated first
     572   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(orphanage->EraseTx(mutated_wtxid), 1);
                   +  - ]
     573   [ +  -  +  -  :           2 :     BOOST_CHECK(orphanage->HaveTx(normal_wtxid));
             +  -  +  - ]
     574   [ +  -  +  -  :           2 :     BOOST_CHECK(!orphanage->HaveTx(mutated_wtxid));
             +  -  +  - ]
     575                 :             : 
     576   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(orphanage->EraseTx(normal_wtxid), 1);
                   +  - ]
     577   [ +  -  +  -  :           2 :     BOOST_CHECK(!orphanage->HaveTx(normal_wtxid));
             +  -  +  - ]
     578   [ +  -  +  -  :           2 :     BOOST_CHECK(!orphanage->HaveTx(mutated_wtxid));
                   +  - ]
     579   [ +  -  +  -  :           7 : }
          -  +  +  -  +  
                -  +  - ]
     580                 :             : 
     581                 :             : 
     582   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(get_children)
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     583                 :             : {
     584                 :           1 :     FastRandomContext det_rand{true};
     585                 :           1 :     std::vector<COutPoint> empty_outpoints;
     586                 :             : 
     587         [ +  - ]:           1 :     auto parent1 = MakeTransactionSpending(empty_outpoints, det_rand);
     588         [ +  - ]:           1 :     auto parent2 = MakeTransactionSpending(empty_outpoints, det_rand);
     589                 :             : 
     590                 :             :     // Make sure these parents have different txids otherwise this test won't make sense.
     591         [ -  + ]:           1 :     while (parent1->GetHash() == parent2->GetHash()) {
     592   [ #  #  #  # ]:           0 :         parent2 = MakeTransactionSpending(empty_outpoints, det_rand);
     593                 :             :     }
     594                 :             : 
     595                 :             :     // Create children to go into orphanage.
     596   [ +  -  +  -  :           2 :     auto child_p1n0 = MakeTransactionSpending({{parent1->GetHash(), 0}}, det_rand);
                   +  - ]
     597   [ +  -  +  -  :           2 :     auto child_p2n1 = MakeTransactionSpending({{parent2->GetHash(), 1}}, det_rand);
                   +  - ]
     598                 :             :     // Spends the same tx twice. Should not cause duplicates.
     599   [ +  -  +  -  :           2 :     auto child_p1n0_p1n1 = MakeTransactionSpending({{parent1->GetHash(), 0}, {parent1->GetHash(), 1}}, det_rand);
                   +  - ]
     600                 :             :     // Spends the same outpoint as previous tx. Should still be returned; don't assume outpoints are unique.
     601   [ +  -  +  - ]:           2 :     auto child_p1n0_p2n0 = MakeTransactionSpending({{parent1->GetHash(), 0}, {parent2->GetHash(), 0}}, det_rand);
     602                 :             : 
     603                 :           1 :     const NodeId node0{0};
     604                 :           1 :     const NodeId node1{1};
     605                 :           1 :     const NodeId node2{2};
     606                 :           1 :     const NodeId node3{3};
     607                 :             : 
     608                 :             :     // All orphans provided by node1
     609                 :           1 :     {
     610                 :           1 :         auto orphanage{node::MakeTxOrphanage()};
     611   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->AddTx(child_p1n0, node1));
             +  -  +  - ]
     612   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->AddTx(child_p2n1, node1));
             +  -  +  - ]
     613   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->AddTx(child_p1n0_p1n1, node1));
             +  -  +  - ]
     614   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->AddTx(child_p1n0_p2n0, node1));
             +  -  +  - ]
     615                 :             : 
     616                 :             :         // Also add some other announcers for the same transactions
     617   [ +  -  +  -  :           2 :         BOOST_CHECK(!orphanage->AddTx(child_p1n0_p1n1, node0));
             +  -  +  - ]
     618   [ +  -  +  -  :           2 :         BOOST_CHECK(!orphanage->AddTx(child_p2n1, node0));
             +  -  +  - ]
     619   [ +  -  +  -  :           2 :         BOOST_CHECK(!orphanage->AddTx(child_p1n0, node3));
             +  -  +  - ]
     620                 :             : 
     621                 :             : 
     622   [ +  +  +  -  :           4 :         std::vector<CTransactionRef> expected_parent1_children{child_p1n0_p2n0, child_p1n0_p1n1, child_p1n0};
             -  -  -  - ]
     623   [ +  +  +  -  :           3 :         std::vector<CTransactionRef> expected_parent2_children{child_p1n0_p2n0, child_p2n1};
             -  -  -  - ]
     624                 :             : 
     625   [ +  -  +  -  :           2 :         BOOST_CHECK(expected_parent1_children == orphanage->GetChildrenFromSamePeer(parent1, node1));
             +  -  +  - ]
     626   [ +  -  +  -  :           2 :         BOOST_CHECK(expected_parent2_children == orphanage->GetChildrenFromSamePeer(parent2, node1));
             +  -  +  - ]
     627                 :             : 
     628                 :             :         // The peer must match
     629   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->GetChildrenFromSamePeer(parent1, node2).empty());
             +  -  +  - ]
     630   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->GetChildrenFromSamePeer(parent2, node2).empty());
             +  -  +  - ]
     631                 :             : 
     632                 :             :         // There shouldn't be any children of this tx in the orphanage
     633   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->GetChildrenFromSamePeer(child_p1n0_p2n0, node1).empty());
             +  -  +  - ]
     634   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->GetChildrenFromSamePeer(child_p1n0_p2n0, node2).empty());
                   +  - ]
     635                 :           1 :     }
     636                 :             : 
     637                 :             :     // Orphans provided by node1 and node2
     638                 :           1 :     {
     639                 :           1 :         std::unique_ptr<node::TxOrphanage> orphanage{node::MakeTxOrphanage()};
     640   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->AddTx(child_p1n0, node1));
             +  -  +  - ]
     641   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->AddTx(child_p2n1, node1));
             +  -  +  - ]
     642   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->AddTx(child_p1n0_p1n1, node2));
             +  -  +  - ]
     643   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->AddTx(child_p1n0_p2n0, node2));
             +  -  +  - ]
     644                 :             : 
     645                 :             :         // +----------------+---------------+----------------------------------+
     646                 :             :         // |                | sender=node1  |           sender=node2           |
     647                 :             :         // +----------------+---------------+----------------------------------+
     648                 :             :         // | spends parent1 | child_p1n0    | child_p1n0_p1n1, child_p1n0_p2n0 |
     649                 :             :         // | spends parent2 | child_p2n1    | child_p1n0_p2n0                  |
     650                 :             :         // +----------------+---------------+----------------------------------+
     651                 :             : 
     652                 :             :         // Children of parent1 from node1:
     653                 :           1 :         {
     654   [ +  +  +  -  :           2 :             std::set<CTransactionRef> expected_parent1_node1{child_p1n0};
             -  -  -  - ]
     655                 :             : 
     656   [ +  -  +  -  :           1 :             BOOST_CHECK_EQUAL(orphanage->GetChildrenFromSamePeer(parent1, node1).size(), 1);
                   +  - ]
     657   [ +  -  +  -  :           2 :             BOOST_CHECK(orphanage->HaveTxFromPeer(child_p1n0->GetWitnessHash(), node1));
             +  -  +  - ]
     658   [ +  -  +  -  :           2 :             BOOST_CHECK(EqualTxns(expected_parent1_node1, orphanage->GetChildrenFromSamePeer(parent1, node1)));
                   +  - ]
     659                 :           0 :         }
     660                 :             : 
     661                 :             :         // Children of parent2 from node1:
     662                 :           1 :         {
     663   [ +  +  +  -  :           2 :             std::set<CTransactionRef> expected_parent2_node1{child_p2n1};
             -  -  -  - ]
     664                 :             : 
     665   [ +  -  +  -  :           2 :             BOOST_CHECK(EqualTxns(expected_parent2_node1, orphanage->GetChildrenFromSamePeer(parent2, node1)));
                   +  - ]
     666                 :           0 :         }
     667                 :             : 
     668                 :             :         // Children of parent1 from node2: newest returned first.
     669                 :           1 :         {
     670   [ +  +  +  -  :           3 :             std::vector<CTransactionRef> expected_parent1_node2{child_p1n0_p2n0, child_p1n0_p1n1};
             -  -  -  - ]
     671   [ +  -  +  -  :           2 :             BOOST_CHECK(orphanage->HaveTxFromPeer(child_p1n0_p1n1->GetWitnessHash(), node2));
             +  -  +  - ]
     672   [ +  -  +  -  :           2 :             BOOST_CHECK(orphanage->HaveTxFromPeer(child_p1n0_p2n0->GetWitnessHash(), node2));
             +  -  +  - ]
     673   [ +  -  +  -  :           2 :             BOOST_CHECK(expected_parent1_node2 == orphanage->GetChildrenFromSamePeer(parent1, node2));
                   +  - ]
     674                 :           1 :         }
     675                 :             : 
     676                 :             :         // Children of parent2 from node2:
     677                 :           1 :         {
     678   [ +  +  +  -  :           2 :             std::set<CTransactionRef> expected_parent2_node2{child_p1n0_p2n0};
             -  -  -  - ]
     679                 :             : 
     680   [ +  -  +  -  :           1 :             BOOST_CHECK_EQUAL(1, orphanage->GetChildrenFromSamePeer(parent2, node2).size());
                   +  - ]
     681   [ +  -  +  -  :           2 :             BOOST_CHECK(orphanage->HaveTxFromPeer(child_p1n0_p2n0->GetWitnessHash(), node2));
             +  -  +  - ]
     682   [ +  -  +  -  :           2 :             BOOST_CHECK(EqualTxns(expected_parent2_node2, orphanage->GetChildrenFromSamePeer(parent2, node2)));
                   +  - ]
     683                 :           0 :         }
     684         [ +  - ]:           1 :     }
     685   [ +  -  +  -  :          22 : }
          +  -  -  +  +  
          -  +  -  -  +  
          +  -  -  +  +  
          -  -  +  +  -  
          +  -  -  +  +  
          -  -  +  +  -  
          +  -  +  -  +  
                -  +  - ]
     686                 :             : 
     687   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(too_large_orphan_tx)
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     688                 :             : {
     689                 :           1 :     std::unique_ptr<node::TxOrphanage> orphanage{node::MakeTxOrphanage()};
     690         [ +  - ]:           1 :     CMutableTransaction tx;
     691         [ +  - ]:           1 :     tx.vin.resize(1);
     692                 :             : 
     693                 :             :     // check that txs larger than MAX_STANDARD_TX_WEIGHT are not added to the orphanage
     694         [ +  - ]:           1 :     BulkTransaction(tx, MAX_STANDARD_TX_WEIGHT + 4);
     695   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(GetTransactionWeight(CTransaction(tx)), MAX_STANDARD_TX_WEIGHT + 4);
                   +  - ]
     696   [ +  -  +  -  :           4 :     BOOST_CHECK(!orphanage->AddTx(MakeTransactionRef(tx), 0));
          +  -  +  -  +  
                      - ]
     697                 :             : 
     698                 :           1 :     tx.vout.clear();
     699         [ +  - ]:           1 :     BulkTransaction(tx, MAX_STANDARD_TX_WEIGHT);
     700   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(GetTransactionWeight(CTransaction(tx)), MAX_STANDARD_TX_WEIGHT);
                   +  - ]
     701   [ +  -  +  -  :           4 :     BOOST_CHECK(orphanage->AddTx(MakeTransactionRef(tx), 0));
          +  -  +  -  +  
                      - ]
     702                 :           1 : }
     703                 :             : 
     704   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(process_block)
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     705                 :             : {
     706                 :           1 :     FastRandomContext det_rand{true};
     707                 :           1 :     std::unique_ptr<node::TxOrphanage> orphanage{node::MakeTxOrphanage()};
     708                 :             : 
     709                 :             :     // Create outpoints that will be spent by transactions in the block
     710                 :           1 :     std::vector<COutPoint> outpoints;
     711                 :           1 :     const uint32_t num_outpoints{6};
     712         [ +  - ]:           1 :     outpoints.reserve(num_outpoints);
     713         [ +  + ]:           7 :     for (uint32_t i{0}; i < num_outpoints; ++i) {
     714                 :             :         // All the hashes should be different, but change the n just in case.
     715         [ +  - ]:           6 :         outpoints.emplace_back(Txid::FromUint256(det_rand.rand256()), i);
     716                 :             :     }
     717                 :             : 
     718                 :           1 :     CBlock block;
     719                 :           1 :     const NodeId node{0};
     720                 :             : 
     721         [ +  - ]:           1 :     auto control_tx = MakeTransactionSpending({}, det_rand);
     722   [ +  -  +  -  :           2 :     BOOST_CHECK(orphanage->AddTx(control_tx, node));
             +  -  +  - ]
     723                 :             : 
     724   [ +  -  +  -  :           2 :     auto bo_tx_same_txid = MakeTransactionSpending({outpoints.at(0)}, det_rand);
             +  -  +  - ]
     725   [ +  -  +  -  :           2 :     BOOST_CHECK(orphanage->AddTx(bo_tx_same_txid, node));
             +  -  +  - ]
     726         [ +  - ]:           1 :     block.vtx.emplace_back(bo_tx_same_txid);
     727                 :             : 
     728                 :             :     // 2 transactions with the same txid but different witness
     729   [ +  -  +  -  :           2 :     auto b_tx_same_txid_diff_witness = MakeTransactionSpending({outpoints.at(1)}, det_rand);
             +  -  +  - ]
     730         [ +  - ]:           1 :     block.vtx.emplace_back(b_tx_same_txid_diff_witness);
     731                 :             : 
     732         [ +  - ]:           1 :     auto o_tx_same_txid_diff_witness = MakeMutation(b_tx_same_txid_diff_witness);
     733   [ +  -  +  -  :           2 :     BOOST_CHECK(orphanage->AddTx(o_tx_same_txid_diff_witness, node));
             +  -  +  - ]
     734                 :             : 
     735                 :             :     // 2 different transactions that spend the same input.
     736   [ +  -  +  -  :           2 :     auto b_tx_conflict = MakeTransactionSpending({outpoints.at(2)}, det_rand);
             +  -  +  - ]
     737         [ +  - ]:           1 :     block.vtx.emplace_back(b_tx_conflict);
     738                 :             : 
     739   [ +  -  +  -  :           2 :     auto o_tx_conflict = MakeTransactionSpending({outpoints.at(2)}, det_rand);
             +  -  +  - ]
     740   [ +  -  +  -  :           2 :     BOOST_CHECK(orphanage->AddTx(o_tx_conflict, node));
             +  -  +  - ]
     741                 :             : 
     742                 :             :     // 2 different transactions that have 1 overlapping input.
     743   [ +  -  +  -  :           2 :     auto b_tx_conflict_partial = MakeTransactionSpending({outpoints.at(3), outpoints.at(4)}, det_rand);
          +  -  +  -  +  
                      - ]
     744         [ +  - ]:           1 :     block.vtx.emplace_back(b_tx_conflict_partial);
     745                 :             : 
     746   [ +  -  +  -  :           2 :     auto o_tx_conflict_partial_2 = MakeTransactionSpending({outpoints.at(4), outpoints.at(5)}, det_rand);
          +  -  +  -  +  
                      - ]
     747   [ +  -  +  -  :           2 :     BOOST_CHECK(orphanage->AddTx(o_tx_conflict_partial_2, node));
             +  -  +  - ]
     748                 :             : 
     749         [ +  - ]:           1 :     orphanage->EraseForBlock(block);
     750   [ +  -  +  -  :          17 :     for (const auto& expected_removed : {bo_tx_same_txid, o_tx_same_txid_diff_witness, o_tx_conflict, o_tx_conflict_partial_2}) {
          +  -  +  -  +  
             +  +  -  -  
                      - ]
     751         [ +  - ]:           4 :         const auto& expected_removed_wtxid = expected_removed->GetWitnessHash();
     752   [ +  -  +  -  :           8 :         BOOST_CHECK(!orphanage->HaveTx(expected_removed_wtxid));
                   +  - ]
     753   [ +  +  -  - ]:           5 :     }
     754                 :             :     // Only remaining tx is control_tx
     755   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(orphanage->Size(), 1);
                   +  - ]
     756   [ +  -  +  -  :           2 :     BOOST_CHECK(orphanage->HaveTx(control_tx->GetWitnessHash()));
             +  -  +  - ]
     757   [ +  -  +  -  :           8 : }
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     758                 :             : 
     759   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(multiple_announcers)
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     760                 :             : {
     761                 :           1 :     const NodeId node0{0};
     762                 :           1 :     const NodeId node1{1};
     763                 :           1 :     const NodeId node2{2};
     764                 :           1 :     size_t expected_total_count{0};
     765                 :           1 :     FastRandomContext det_rand{true};
     766                 :           1 :     std::unique_ptr<node::TxOrphanage> orphanage{node::MakeTxOrphanage()};
     767                 :             : 
     768                 :             :     // Check accounting per peer.
     769                 :             :     // Check that EraseForPeer works with multiple announcers.
     770                 :           1 :     {
     771         [ +  - ]:           1 :         auto ptx = MakeTransactionSpending({}, det_rand);
     772         [ +  - ]:           1 :         const auto& wtxid = ptx->GetWitnessHash();
     773   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->AddTx(ptx, node0));
             +  -  +  - ]
     774   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->HaveTx(wtxid));
             +  -  +  - ]
     775                 :           1 :         expected_total_count += 1;
     776   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->Size(), expected_total_count);
                   +  - ]
     777                 :             : 
     778                 :             :         // Adding again should do nothing.
     779   [ +  -  +  -  :           2 :         BOOST_CHECK(!orphanage->AddTx(ptx, node0));
             +  -  +  - ]
     780   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->Size(), expected_total_count);
                   +  - ]
     781                 :             : 
     782                 :             :         // We can add another tx with the same txid but different witness.
     783         [ +  - ]:           1 :         auto ptx_mutated{MakeMutation(ptx)};
     784   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->AddTx(ptx_mutated, node0));
             +  -  +  - ]
     785   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->HaveTx(ptx_mutated->GetWitnessHash()));
             +  -  +  - ]
     786                 :           1 :         expected_total_count += 1;
     787                 :             : 
     788   [ +  -  +  -  :           2 :         BOOST_CHECK(!orphanage->AddTx(ptx, node0));
             +  -  +  - ]
     789                 :             : 
     790                 :             :         // Adding a new announcer should not change overall accounting.
     791   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->AddAnnouncer(ptx->GetWitnessHash(), node2));
             +  -  +  - ]
     792   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->Size(), expected_total_count);
                   +  - ]
     793                 :             : 
     794                 :             :         // If we already have this announcer, AddAnnouncer returns false.
     795   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->HaveTxFromPeer(ptx->GetWitnessHash(), node2));
             +  -  +  - ]
     796   [ +  -  +  -  :           2 :         BOOST_CHECK(!orphanage->AddAnnouncer(ptx->GetWitnessHash(), node2));
             +  -  +  - ]
     797                 :             : 
     798                 :             :         // Same with using AddTx for an existing tx, which is equivalent to using AddAnnouncer
     799   [ +  -  +  -  :           2 :         BOOST_CHECK(!orphanage->AddTx(ptx, node1));
             +  -  +  - ]
     800   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->Size(), expected_total_count);
                   +  - ]
     801                 :             : 
     802                 :             :         // if EraseForPeer is called for an orphan with multiple announcers, the orphanage should only
     803                 :             :         // erase that peer from the announcers set.
     804         [ +  - ]:           1 :         orphanage->EraseForPeer(node0);
     805   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->HaveTx(ptx->GetWitnessHash()));
             +  -  +  - ]
     806   [ +  -  +  -  :           2 :         BOOST_CHECK(!orphanage->HaveTxFromPeer(ptx->GetWitnessHash(), node0));
             +  -  +  - ]
     807                 :             :         // node0 is the only one that announced ptx_mutated
     808   [ +  -  +  -  :           2 :         BOOST_CHECK(!orphanage->HaveTx(ptx_mutated->GetWitnessHash()));
             +  -  +  - ]
     809                 :           1 :         expected_total_count -= 1;
     810   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->Size(), expected_total_count);
                   +  - ]
     811                 :             : 
     812                 :             :         // EraseForPeer should delete the orphan if it's the only announcer left.
     813         [ +  - ]:           1 :         orphanage->EraseForPeer(node1);
     814   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->Size(), expected_total_count);
                   +  - ]
     815   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->HaveTx(ptx->GetWitnessHash()));
             +  -  +  - ]
     816         [ +  - ]:           1 :         orphanage->EraseForPeer(node2);
     817                 :           1 :         expected_total_count -= 1;
     818   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->Size(), expected_total_count);
                   +  - ]
     819   [ +  -  +  -  :           2 :         BOOST_CHECK(!orphanage->HaveTx(ptx->GetWitnessHash()));
             +  -  +  - ]
     820         [ +  - ]:           1 :     }
     821                 :             : 
     822                 :             :     // Check that erasure for blocks removes for all peers.
     823                 :           1 :     {
     824                 :           1 :         CBlock block;
     825         [ +  - ]:           1 :         auto tx_block = MakeTransactionSpending({}, det_rand);
     826         [ +  - ]:           1 :         block.vtx.emplace_back(tx_block);
     827   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->AddTx(tx_block, node0));
             +  -  +  - ]
     828   [ +  -  +  -  :           2 :         BOOST_CHECK(!orphanage->AddTx(tx_block, node1));
             +  -  +  - ]
     829                 :             : 
     830                 :           1 :         expected_total_count += 1;
     831                 :             : 
     832   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->Size(), expected_total_count);
                   +  - ]
     833                 :             : 
     834         [ +  - ]:           1 :         orphanage->EraseForBlock(block);
     835                 :             : 
     836                 :           1 :         expected_total_count -= 1;
     837                 :             : 
     838   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->Size(), expected_total_count);
             +  -  +  - ]
     839                 :           1 :     }
     840                 :           1 : }
     841   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(peer_worksets)
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     842                 :             : {
     843                 :           1 :     const NodeId node0{0};
     844                 :           1 :     const NodeId node1{1};
     845                 :           1 :     const NodeId node2{2};
     846                 :           1 :     FastRandomContext det_rand{true};
     847                 :           1 :     std::unique_ptr<node::TxOrphanage> orphanage{node::MakeTxOrphanage()};
     848                 :             :     // AddChildrenToWorkSet should pick an announcer randomly
     849                 :           1 :     {
     850         [ +  - ]:           1 :         auto tx_missing_parent = MakeTransactionSpending({}, det_rand);
     851   [ +  -  +  -  :           2 :         auto tx_orphan = MakeTransactionSpending({COutPoint{tx_missing_parent->GetHash(), 0}}, det_rand);
                   +  - ]
     852         [ +  - ]:           1 :         const auto& orphan_wtxid = tx_orphan->GetWitnessHash();
     853                 :             : 
     854                 :             :         // All 3 peers are announcers.
     855   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->AddTx(tx_orphan, node0));
             +  -  +  - ]
     856   [ +  -  +  -  :           2 :         BOOST_CHECK(!orphanage->AddTx(tx_orphan, node1));
             +  -  +  - ]
     857   [ +  -  +  -  :           2 :         BOOST_CHECK(orphanage->AddAnnouncer(orphan_wtxid, node2));
                   +  - ]
     858         [ +  + ]:           4 :         for (NodeId node = node0; node <= node2; ++node) {
     859   [ +  -  +  -  :           6 :             BOOST_CHECK(orphanage->HaveTxFromPeer(orphan_wtxid, node));
                   +  - ]
     860                 :             :         }
     861                 :             : 
     862                 :             :         // Parent accepted: child is added to 1 of 3 worksets.
     863         [ +  - ]:           1 :         auto newly_reconsiderable = orphanage->AddChildrenToWorkSet(*tx_missing_parent, det_rand);
     864   [ +  -  +  - ]:           1 :         BOOST_CHECK_EQUAL(newly_reconsiderable.size(), 1);
     865         [ +  - ]:           1 :         int node0_reconsider = orphanage->HaveTxToReconsider(node0);
     866         [ +  - ]:           1 :         int node1_reconsider = orphanage->HaveTxToReconsider(node1);
     867         [ +  - ]:           1 :         int node2_reconsider = orphanage->HaveTxToReconsider(node2);
     868   [ +  -  +  - ]:           1 :         BOOST_CHECK_EQUAL(node0_reconsider + node1_reconsider + node2_reconsider, 1);
     869                 :             : 
     870                 :           1 :         NodeId assigned_peer;
     871         [ +  - ]:           1 :         if (node0_reconsider) {
     872                 :             :             assigned_peer = node0;
     873         [ -  + ]:           1 :         } else if (node1_reconsider) {
     874                 :             :             assigned_peer = node1;
     875                 :             :         } else {
     876   [ #  #  #  # ]:           0 :             BOOST_CHECK(node2_reconsider);
     877                 :           0 :             assigned_peer = node2;
     878                 :             :         }
     879                 :             : 
     880                 :             :         // EraseForPeer also removes that tx from the workset.
     881         [ +  - ]:           1 :         orphanage->EraseForPeer(assigned_peer);
     882   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->GetTxToReconsider(node0), nullptr);
             +  -  -  + ]
     883                 :             : 
     884                 :             :         // Delete this tx, clearing the orphanage.
     885   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->EraseTx(orphan_wtxid), 1);
                   +  - ]
     886   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(orphanage->Size(), 0);
                   +  - ]
     887         [ +  + ]:           4 :         for (NodeId node = node0; node <= node2; ++node) {
     888   [ +  -  +  -  :           3 :             BOOST_CHECK_EQUAL(orphanage->GetTxToReconsider(node), nullptr);
             +  -  -  + ]
     889   [ +  -  +  -  :           6 :             BOOST_CHECK(!orphanage->HaveTxFromPeer(orphan_wtxid, node));
                   +  - ]
     890                 :             :         }
     891   [ +  -  +  - ]:           2 :     }
     892                 :           1 : }
     893                 :             : BOOST_AUTO_TEST_SUITE_END()
        

Generated by: LCOV version 2.0-1