LCOV - code coverage report
Current view: top level - src/test - orphanage_tests.cpp (source / functions) Coverage Total Hit
Test: test_bitcoin_coverage.info Lines: 98.9 % 537 531
Test Date: 2025-08-13 04:26:42 Functions: 100.0 % 20 20
Branches: 50.7 % 2658 1347

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

Generated by: LCOV version 2.0-1