LCOV - code coverage report
Current view: top level - src/test - private_broadcast_tests.cpp (source / functions) Coverage Total Hit
Test: test_bitcoin_coverage.info Lines: 97.0 % 197 191
Test Date: 2026-08-25 06:16:57 Functions: 92.9 % 14 13
Branches: 50.5 % 1116 564

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2025-present The Bitcoin Core developers
       2                 :             : // Distributed under the MIT software license, see the accompanying
       3                 :             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4                 :             : 
       5                 :             : #include <primitives/transaction.h>
       6                 :             : #include <private_broadcast.h>
       7                 :             : #include <test/util/setup_common.h>
       8                 :             : #include <test/util/time.h>
       9                 :             : #include <util/time.h>
      10                 :             : 
      11                 :             : #include <algorithm>
      12                 :             : #include <ostream>
      13                 :             : #include <boost/test/unit_test.hpp>
      14                 :             : 
      15                 :           0 : std::ostream& operator<<(std::ostream& os, PrivateBroadcast::AddResult r)
      16                 :             : {
      17   [ #  #  #  # ]:           0 :     switch (r) {
      18                 :           0 :     case PrivateBroadcast::AddResult::Added: return os << "Added";
      19                 :           0 :     case PrivateBroadcast::AddResult::AlreadyPresent: return os << "AlreadyPresent";
      20                 :           0 :     case PrivateBroadcast::AddResult::QueueFull: return os << "QueueFull";
      21                 :             :     } // no default case, so the compiler can warn about missing cases
      22                 :           0 :     assert(false);
      23                 :             : }
      24                 :             : 
      25                 :             : BOOST_FIXTURE_TEST_SUITE(private_broadcast_tests, BasicTestingSetup)
      26                 :             : 
      27                 :       10013 : static CTransactionRef MakeDummyTx(uint32_t id, size_t num_witness)
      28                 :             : {
      29                 :       10013 :     CMutableTransaction mtx;
      30         [ +  - ]:       10013 :     mtx.vin.resize(1);
      31         [ +  + ]:       10013 :     mtx.vin[0].nSequence = id;
      32         [ +  + ]:       10013 :     if (num_witness > 0) {
      33                 :           1 :         mtx.vin[0].scriptWitness = CScriptWitness{};
      34         [ +  - ]:           1 :         mtx.vin[0].scriptWitness.stack.resize(num_witness);
      35                 :             :     }
      36         [ +  - ]:       20026 :     return MakeTransactionRef(mtx);
      37                 :       10013 : }
      38                 :             : 
      39   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(basic)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
      40                 :             : {
      41                 :           1 :     FakeNodeClock clock{};
      42                 :             : 
      43         [ +  - ]:           1 :     PrivateBroadcast pb;
      44                 :           1 :     const NodeId recipient1{1};
      45                 :           1 :     in_addr ipv4Addr;
      46                 :           1 :     ipv4Addr.s_addr = 0xa0b0c001;
      47         [ +  - ]:           1 :     const CService addr1{ipv4Addr, 1111};
      48                 :             : 
      49                 :             :     // No transactions initially.
      50   [ +  -  +  -  :           2 :     BOOST_CHECK(!pb.PickTxForSend(/*will_send_to_nodeid=*/recipient1, /*will_send_to_address=*/addr1).has_value());
             +  -  +  - ]
      51   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.GetStale().size(), 0);
                   +  - ]
      52   [ +  -  +  -  :           2 :     BOOST_CHECK(!pb.HavePendingTransactions());
             +  -  +  - ]
      53   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.GetBroadcastInfo().size(), 0);
                   +  - ]
      54                 :             : 
      55                 :             :     // Make a transaction and add it.
      56         [ +  - ]:           1 :     const auto tx1{MakeDummyTx(/*id=*/1, /*num_witness=*/0)};
      57                 :             : 
      58   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(pb.Add(tx1), PrivateBroadcast::AddResult::Added);
                   +  - ]
      59   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(pb.Add(tx1), PrivateBroadcast::AddResult::AlreadyPresent);
                   +  - ]
      60                 :             : 
      61                 :             :     // Make another transaction with same txid, different wtxid and add it.
      62         [ +  - ]:           1 :     const auto tx2{MakeDummyTx(/*id=*/1, /*num_witness=*/1)};
      63   [ +  -  -  +  :           2 :     BOOST_REQUIRE(tx1->GetHash() == tx2->GetHash());
             +  -  +  - ]
      64   [ +  -  +  -  :           3 :     BOOST_REQUIRE(tx1->GetWitnessHash() != tx2->GetWitnessHash());
             +  -  +  - ]
      65                 :             : 
      66   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(pb.Add(tx2), PrivateBroadcast::AddResult::Added);
                   +  - ]
      67                 :           7 :     const auto find_tx_info{[](auto& infos, const CTransactionRef& tx) -> const PrivateBroadcast::TxBroadcastInfo& {
      68         [ +  + ]:          15 :         const auto it{std::ranges::find(infos, tx->GetWitnessHash(), [](const auto& info) { return info.tx->GetWitnessHash(); })};
      69         [ +  - ]:          12 :         BOOST_REQUIRE(it != infos.end());
      70                 :           6 :         return *it;
      71                 :             :     }};
      72                 :           3 :     const auto check_peer_counts{[&](size_t tx1_peer_count, size_t tx2_peer_count) {
      73                 :           2 :         const auto infos{pb.GetBroadcastInfo()};
      74   [ +  -  -  +  :           2 :         BOOST_CHECK_EQUAL(infos.size(), 2);
                   +  - ]
      75   [ +  -  +  -  :           2 :         BOOST_CHECK_EQUAL(find_tx_info(infos, tx1).peers.size(), tx1_peer_count);
             -  +  +  - ]
      76   [ +  -  +  -  :           2 :         BOOST_CHECK_EQUAL(find_tx_info(infos, tx2).peers.size(), tx2_peer_count);
             -  +  +  - ]
      77                 :           3 :     }};
      78                 :             : 
      79         [ +  - ]:           1 :     check_peer_counts(/*tx1_peer_count=*/0, /*tx2_peer_count=*/0);
      80                 :             : 
      81         [ +  - ]:           2 :     const auto tx_for_recipient1{pb.PickTxForSend(/*will_send_to_nodeid=*/recipient1, /*will_send_to_address=*/addr1).value()};
      82   [ +  -  +  -  :           3 :     BOOST_CHECK(tx_for_recipient1 == tx1 || tx_for_recipient1 == tx2);
          +  -  +  -  +  
                      - ]
      83                 :             : 
      84                 :             :     // A second pick must return the other transaction.
      85                 :           1 :     const NodeId recipient2{2};
      86         [ +  - ]:           1 :     const CService addr2{ipv4Addr, 2222};
      87         [ +  - ]:           2 :     const auto tx_for_recipient2{pb.PickTxForSend(/*will_send_to_nodeid=*/recipient2, /*will_send_to_address=*/addr2).value()};
      88   [ +  -  -  +  :           2 :     BOOST_CHECK(tx_for_recipient2 == tx1 || tx_for_recipient2 == tx2);
          -  -  +  -  +  
                      - ]
      89   [ +  -  +  - ]:           1 :     BOOST_CHECK_NE(tx_for_recipient1, tx_for_recipient2);
      90                 :             : 
      91         [ +  - ]:           1 :     check_peer_counts(/*tx1_peer_count=*/1, /*tx2_peer_count=*/1);
      92                 :             : 
      93                 :           1 :     const NodeId nonexistent_recipient{0};
      94                 :             : 
      95                 :             :     // Confirm transactions <-> recipients mapping is correct.
      96   [ +  -  +  -  :           2 :     BOOST_CHECK(!pb.GetTxForNode(nonexistent_recipient).has_value());
             +  -  +  - ]
      97   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.GetTxForNode(recipient1).value(), tx_for_recipient1);
                   +  - ]
      98   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.GetTxForNode(recipient2).value(), tx_for_recipient2);
                   +  - ]
      99                 :             : 
     100                 :             :     // Confirm none of the transactions' reception have been confirmed.
     101   [ +  -  +  -  :           2 :     BOOST_CHECK(!pb.DidNodeConfirmReception(recipient1));
             +  -  +  - ]
     102   [ +  -  +  -  :           2 :     BOOST_CHECK(!pb.DidNodeConfirmReception(recipient2));
             +  -  +  - ]
     103   [ +  -  +  -  :           2 :     BOOST_CHECK(!pb.DidNodeConfirmReception(nonexistent_recipient));
             +  -  +  - ]
     104                 :             : 
     105                 :             :     // 1. Freshly added transactions should NOT be stale yet.
     106   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.GetStale().size(), 0);
                   +  - ]
     107                 :             : 
     108                 :             :     // 2. Fast-forward the mock clock past the INITIAL_STALE_DURATION.
     109         [ +  - ]:           1 :     clock += PrivateBroadcast::INITIAL_STALE_DURATION + 1min;
     110                 :             : 
     111                 :             :     // 3. Now that the initial duration has passed, both unconfirmed transactions should be stale.
     112   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.GetStale().size(), 2);
                   +  - ]
     113                 :             : 
     114                 :             :     // Confirm reception by recipient1.
     115         [ +  - ]:           1 :     pb.NodeConfirmedReception(nonexistent_recipient); // Dummy call.
     116         [ +  - ]:           1 :     pb.NodeConfirmedReception(recipient1);
     117                 :             : 
     118   [ +  -  +  -  :           2 :     BOOST_CHECK(pb.DidNodeConfirmReception(recipient1));
             +  -  +  - ]
     119   [ +  -  +  -  :           2 :     BOOST_CHECK(!pb.DidNodeConfirmReception(recipient2));
             +  -  +  - ]
     120                 :             : 
     121         [ +  - ]:           1 :     const auto infos{pb.GetBroadcastInfo()};
     122   [ +  -  -  +  :           1 :     BOOST_CHECK_EQUAL(infos.size(), 2);
                   +  - ]
     123                 :           1 :     {
     124         [ +  - ]:           1 :         const auto& peers{find_tx_info(infos, tx_for_recipient1).peers};
     125   [ +  -  -  +  :           1 :         BOOST_CHECK_EQUAL(peers.size(), 1);
                   +  - ]
     126   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(peers[0].address.ToStringAddrPort(), addr1.ToStringAddrPort());
             +  -  +  - ]
     127   [ +  -  +  -  :           2 :         BOOST_CHECK(peers[0].received.has_value());
                   +  - ]
     128                 :             :     }
     129                 :           1 :     {
     130         [ +  - ]:           1 :         const auto& peers{find_tx_info(infos, tx_for_recipient2).peers};
     131   [ +  -  -  +  :           1 :         BOOST_CHECK_EQUAL(peers.size(), 1);
                   +  - ]
     132   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(peers[0].address.ToStringAddrPort(), addr2.ToStringAddrPort());
             +  -  +  - ]
     133   [ +  -  +  -  :           2 :         BOOST_CHECK(!peers[0].received.has_value());
                   +  - ]
     134                 :             :     }
     135                 :             : 
     136         [ +  - ]:           1 :     const auto stale_state{pb.GetStale()};
     137   [ +  -  -  +  :           1 :     BOOST_CHECK_EQUAL(stale_state.size(), 1);
                   +  - ]
     138   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(stale_state[0], tx_for_recipient2);
     139                 :             : 
     140         [ +  - ]:           1 :     clock += 10h;
     141                 :             : 
     142   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.GetStale().size(), 2);
                   +  - ]
     143                 :             : 
     144   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.Remove(tx_for_recipient1).value(), 1);
                   +  - ]
     145   [ +  -  +  -  :           2 :     BOOST_CHECK(!pb.Remove(tx_for_recipient1).has_value());
             +  -  +  - ]
     146   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.Remove(tx_for_recipient2).value(), 0);
                   +  - ]
     147   [ +  -  +  -  :           2 :     BOOST_CHECK(!pb.Remove(tx_for_recipient2).has_value());
             +  -  +  - ]
     148                 :             : 
     149   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.GetBroadcastInfo().size(), 0);
                   +  - ]
     150         [ +  - ]:           1 :     const CService addr_nonexistent{ipv4Addr, 3333};
     151   [ +  -  +  -  :           2 :     BOOST_CHECK(!pb.PickTxForSend(/*will_send_to_nodeid=*/nonexistent_recipient, /*will_send_to_address=*/addr_nonexistent).has_value());
                   +  - ]
     152   [ +  -  +  -  :           5 : }
             +  -  +  - ]
     153                 :             : 
     154   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(stale_unpicked_tx)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     155                 :             : {
     156                 :           1 :     FakeNodeClock clock{};
     157                 :             : 
     158         [ +  - ]:           1 :     PrivateBroadcast pb;
     159         [ +  - ]:           1 :     const auto tx{MakeDummyTx(/*id=*/42, /*num_witness=*/0)};
     160   [ +  -  +  -  :           1 :     BOOST_REQUIRE_EQUAL(pb.Add(tx), PrivateBroadcast::AddResult::Added);
                   +  - ]
     161                 :             : 
     162                 :             :     // Unpicked transactions use the longer INITIAL_STALE_DURATION.
     163   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.GetStale().size(), 0);
                   +  - ]
     164         [ +  - ]:           1 :     clock += PrivateBroadcast::INITIAL_STALE_DURATION - 1min;
     165   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.GetStale().size(), 0);
                   +  - ]
     166         [ +  - ]:           1 :     clock += 2min;
     167         [ +  - ]:           1 :     const auto stale_state{pb.GetStale()};
     168   [ +  -  -  +  :           1 :     BOOST_REQUIRE_EQUAL(stale_state.size(), 1);
                   +  - ]
     169   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(stale_state[0], tx);
     170         [ +  - ]:           2 : }
     171                 :             : 
     172   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(send_attempt_limit)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     173                 :             : {
     174                 :           1 :     FakeNodeClock clock{};
     175                 :             : 
     176                 :           1 :     constexpr size_t max_attempts{5};
     177         [ +  - ]:           1 :     PrivateBroadcast pb{PrivateBroadcast::MAX_TRANSACTIONS, max_attempts};
     178         [ +  - ]:           1 :     const auto tx{MakeDummyTx(/*id=*/1, /*num_witness=*/0)};
     179   [ +  -  +  -  :           1 :     BOOST_REQUIRE_EQUAL(pb.Add(tx), PrivateBroadcast::AddResult::Added);
                   +  - ]
     180                 :             : 
     181                 :           1 :     in_addr ipv4_addr;
     182                 :           1 :     ipv4_addr.s_addr = 0xa0b0c001;
     183         [ +  - ]:           1 :     const CService address{ipv4_addr, 1111};
     184                 :             : 
     185                 :             :     NodeId node_id{0};
     186         [ +  + ]:           6 :     for (size_t attempt{0}; attempt < max_attempts; ++attempt) {
     187   [ +  -  +  -  :          10 :         BOOST_CHECK(pb.HavePendingTransactions());
             +  -  +  - ]
     188   [ +  -  +  -  :          10 :         BOOST_REQUIRE_EQUAL(pb.PickTxForSend(/*will_send_to_nodeid=*/node_id++, address).value(), tx);
                   +  - ]
     189                 :             :     }
     190                 :             : 
     191                 :             :     // The transaction and its complete send history remain available, but no
     192                 :             :     // further connections should be opened for it.
     193   [ +  -  +  -  :           2 :     BOOST_CHECK(!pb.HavePendingTransactions());
             +  -  +  - ]
     194   [ +  -  +  -  :           2 :     BOOST_CHECK(!pb.PickTxForSend(/*will_send_to_nodeid=*/node_id++, address).has_value());
             +  -  +  - ]
     195         [ +  - ]:           1 :     const auto info{pb.GetBroadcastInfo()};
     196   [ +  -  -  +  :           1 :     BOOST_REQUIRE_EQUAL(info.size(), 1);
                   +  - ]
     197   [ +  -  -  +  :           1 :     BOOST_CHECK_EQUAL(info[0].peers.size(), max_attempts);
                   +  - ]
     198   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(info[0].attempts_remaining, 0);
     199                 :             : 
     200         [ +  - ]:           1 :     clock += PrivateBroadcast::INITIAL_STALE_DURATION + 1min;
     201   [ +  -  +  -  :           2 :     BOOST_CHECK(pb.GetStale().empty());
             +  -  +  - ]
     202                 :             : 
     203                 :             :     // An exhausted transaction does not prevent another transaction from being sent.
     204         [ +  - ]:           1 :     const auto next_tx{MakeDummyTx(/*id=*/2, /*num_witness=*/0)};
     205   [ +  -  +  -  :           1 :     BOOST_REQUIRE_EQUAL(pb.Add(next_tx), PrivateBroadcast::AddResult::Added);
                   +  - ]
     206   [ +  -  +  -  :           2 :     BOOST_CHECK(pb.HavePendingTransactions());
             +  -  +  - ]
     207   [ +  -  +  -  :           2 :     BOOST_REQUIRE_EQUAL(pb.PickTxForSend(/*will_send_to_nodeid=*/node_id++, address).value(), next_tx);
                   +  - ]
     208                 :             : 
     209                 :             :     // Re-adding an exhausted transaction resets its state and starts a fresh
     210                 :             :     // initial stale period.
     211   [ +  -  +  -  :           1 :     BOOST_REQUIRE_EQUAL(pb.Add(tx), PrivateBroadcast::AddResult::Added);
                   +  - ]
     212   [ +  -  +  -  :           2 :     BOOST_CHECK(pb.HavePendingTransactions());
             +  -  +  - ]
     213   [ +  -  +  -  :           2 :     BOOST_CHECK(pb.GetStale().empty());
             +  -  +  - ]
     214         [ +  - ]:           1 :     const auto reset_info{pb.GetBroadcastInfo()};
     215         [ +  + ]:           3 :     const auto reset_tx_info{std::ranges::find(reset_info, tx->GetWitnessHash(), [](const auto& entry) { return entry.tx->GetWitnessHash(); })};
     216   [ +  -  +  -  :           2 :     BOOST_REQUIRE(reset_tx_info != reset_info.end());
                   +  - ]
     217   [ +  -  +  -  :           2 :     BOOST_CHECK(reset_tx_info->peers.empty());
                   +  - ]
     218   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(reset_tx_info->attempts_remaining, max_attempts);
     219   [ +  -  +  -  :           2 :     BOOST_REQUIRE_EQUAL(pb.PickTxForSend(/*will_send_to_nodeid=*/node_id++, address).value(), tx);
                   +  - ]
     220   [ +  -  +  - ]:           3 : }
     221                 :             : 
     222   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(reset_with_equivalent_transaction_reference)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     223                 :             : {
     224         [ +  - ]:           1 :     PrivateBroadcast pb{PrivateBroadcast::MAX_TRANSACTIONS, /*max_send_attempts=*/1};
     225         [ +  - ]:           1 :     const auto tx{MakeDummyTx(/*id=*/1, /*num_witness=*/0)};
     226         [ +  - ]:           1 :     const auto equivalent_tx{MakeDummyTx(/*id=*/1, /*num_witness=*/0)};
     227   [ +  -  +  -  :           2 :     BOOST_REQUIRE(tx != equivalent_tx);
                   +  - ]
     228   [ +  -  -  +  :           2 :     BOOST_REQUIRE(tx->GetWitnessHash() == equivalent_tx->GetWitnessHash());
             +  -  +  - ]
     229                 :             : 
     230                 :           1 :     in_addr ipv4_addr;
     231                 :           1 :     ipv4_addr.s_addr = 0xa0b0c001;
     232         [ +  - ]:           1 :     const CService address{ipv4_addr, 1111};
     233   [ +  -  +  -  :           1 :     BOOST_REQUIRE_EQUAL(pb.Add(tx), PrivateBroadcast::AddResult::Added);
                   +  - ]
     234   [ +  -  +  -  :           2 :     BOOST_REQUIRE_EQUAL(pb.PickTxForSend(/*will_send_to_nodeid=*/0, address).value(), tx);
                   +  - ]
     235         [ +  - ]:           1 :     pb.NodeConfirmedReception(/*nodeid=*/0);
     236   [ +  -  +  -  :           2 :     BOOST_CHECK(pb.DidNodeConfirmReception(/*nodeid=*/0));
             +  -  +  - ]
     237   [ +  -  +  -  :           2 :     BOOST_CHECK(!pb.HavePendingTransactions());
             +  -  +  - ]
     238                 :             : 
     239                 :             :     // A distinct CTransactionRef with the same WTXID must reset the exhausted
     240                 :             :     // transaction, including its send and confirmation history.
     241   [ +  -  +  -  :           1 :     BOOST_REQUIRE_EQUAL(pb.Add(equivalent_tx), PrivateBroadcast::AddResult::Added);
                   +  - ]
     242   [ +  -  +  -  :           2 :     BOOST_CHECK(pb.HavePendingTransactions());
             +  -  +  - ]
     243   [ +  -  +  -  :           2 :     BOOST_CHECK(!pb.GetTxForNode(/*nodeid=*/0).has_value());
             +  -  +  - ]
     244   [ +  -  +  -  :           2 :     BOOST_CHECK(!pb.DidNodeConfirmReception(/*nodeid=*/0));
             +  -  +  - ]
     245         [ +  - ]:           1 :     const auto info{pb.GetBroadcastInfo()};
     246   [ +  -  -  +  :           1 :     BOOST_REQUIRE_EQUAL(info.size(), 1);
                   +  - ]
     247   [ +  -  -  +  :           2 :     BOOST_CHECK(info[0].tx->GetWitnessHash() == tx->GetWitnessHash());
             +  -  +  - ]
     248   [ +  -  +  -  :           2 :     BOOST_CHECK(info[0].peers.empty());
                   +  - ]
     249   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.Remove(equivalent_tx).value(), 0);
                   +  - ]
     250   [ +  -  +  - ]:           3 : }
     251                 :             : 
     252   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(rejection_at_cap)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     253                 :             : {
     254         [ +  - ]:           1 :     PrivateBroadcast pb;
     255                 :           1 :     constexpr size_t num_cap{PrivateBroadcast::MAX_TRANSACTIONS};
     256                 :           1 :     constexpr size_t num_over{5};
     257                 :             : 
     258                 :             :     // Fill the queue exactly to the cap; every distinct Add() succeeds.
     259                 :           1 :     std::vector<CTransactionRef> txs;
     260         [ +  - ]:           1 :     txs.reserve(num_cap);
     261         [ +  + ]:       10001 :     for (size_t i{0}; i < num_cap; ++i) {
     262         [ +  - ]:       10000 :         auto tx{MakeDummyTx(/*id=*/static_cast<uint32_t>(i), /*num_witness=*/0)};
     263   [ +  -  +  -  :       10000 :         BOOST_REQUIRE_EQUAL(pb.Add(tx), PrivateBroadcast::AddResult::Added);
                   +  - ]
     264   [ +  -  -  + ]:       10000 :         txs.push_back(std::move(tx));
     265                 :       10000 :     }
     266   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.GetBroadcastInfo().size(), num_cap);
                   +  - ]
     267                 :             : 
     268                 :             :     // Further distinct transactions are rejected, and the queue is unchanged.
     269         [ +  + ]:           6 :     for (size_t i{0}; i < num_over; ++i) {
     270         [ +  - ]:           5 :         const auto tx{MakeDummyTx(/*id=*/static_cast<uint32_t>(num_cap + i), /*num_witness=*/0)};
     271   [ +  -  +  -  :           5 :         BOOST_CHECK_EQUAL(pb.Add(tx), PrivateBroadcast::AddResult::QueueFull);
             +  -  +  - ]
     272                 :           5 :     }
     273   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.GetBroadcastInfo().size(), num_cap);
                   +  - ]
     274                 :             : 
     275                 :             :     // Nothing was evicted: all originally-added transactions are still present.
     276         [ +  - ]:           1 :     const auto infos{pb.GetBroadcastInfo()};
     277                 :           1 :     std::set<uint256> present_wtxids;
     278         [ +  + ]:       10001 :     for (const auto& info : infos) {
     279         [ +  - ]:       10000 :         present_wtxids.insert(info.tx->GetWitnessHash().ToUint256());
     280                 :             :     }
     281   [ +  -  -  +  :           1 :     BOOST_CHECK_EQUAL(present_wtxids.size(), infos.size());
                   +  - ]
     282         [ +  + ]:       10001 :     for (size_t i{0}; i < num_cap; ++i) {
     283   [ +  -  +  - ]:       20000 :         BOOST_CHECK_MESSAGE(present_wtxids.contains(txs[i]->GetWitnessHash().ToUint256()),
     284                 :             :                             "tx index " << i << " should still be present");
     285                 :             :     }
     286                 :             : 
     287                 :             :     // Re-adding an already-present tx is AlreadyPresent even at the cap (not QueueFull).
     288   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(pb.Add(txs[0]), PrivateBroadcast::AddResult::AlreadyPresent);
                   +  - ]
     289   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.GetBroadcastInfo().size(), num_cap);
                   +  - ]
     290                 :             : 
     291                 :             :     // Removing one frees exactly one slot for a new transaction.
     292   [ +  -  +  -  :           2 :     BOOST_REQUIRE(pb.Remove(txs[0]).has_value());
             +  -  +  - ]
     293   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.GetBroadcastInfo().size(), num_cap - 1);
                   +  - ]
     294         [ +  - ]:           1 :     const auto fresh{MakeDummyTx(/*id=*/0xffffffff, /*num_witness=*/0)};
     295   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(pb.Add(fresh), PrivateBroadcast::AddResult::Added);
                   +  - ]
     296   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.GetBroadcastInfo().size(), num_cap);
                   +  - ]
     297                 :             : 
     298                 :             :     // A previously-removed tx can be added again as a brand-new entry.
     299   [ +  -  +  -  :           2 :     BOOST_REQUIRE(pb.Remove(fresh).has_value());
             +  -  +  - ]
     300   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(pb.Add(fresh), PrivateBroadcast::AddResult::Added);
                   +  - ]
     301   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.GetBroadcastInfo().size(), num_cap);
             +  -  +  - ]
     302                 :           1 : }
     303                 :             : 
     304                 :             : BOOST_AUTO_TEST_SUITE_END()
        

Generated by: LCOV version 2.0-1