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: 100.0 % 98 98
Test Date: 2026-06-27 07:07:37 Functions: 100.0 % 7 7
Branches: 50.4 % 524 264

             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 <boost/test/unit_test.hpp>
      13                 :             : 
      14                 :             : BOOST_FIXTURE_TEST_SUITE(private_broadcast_tests, BasicTestingSetup)
      15                 :             : 
      16                 :           3 : static CTransactionRef MakeDummyTx(uint32_t id, size_t num_witness)
      17                 :             : {
      18                 :           3 :     CMutableTransaction mtx;
      19         [ +  - ]:           3 :     mtx.vin.resize(1);
      20         [ +  + ]:           3 :     mtx.vin[0].nSequence = id;
      21         [ +  + ]:           3 :     if (num_witness > 0) {
      22                 :           1 :         mtx.vin[0].scriptWitness = CScriptWitness{};
      23         [ +  - ]:           1 :         mtx.vin[0].scriptWitness.stack.resize(num_witness);
      24                 :             :     }
      25         [ +  - ]:           6 :     return MakeTransactionRef(mtx);
      26                 :           3 : }
      27                 :             : 
      28   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(basic)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
      29                 :             : {
      30                 :           1 :     FakeNodeClock clock{};
      31                 :             : 
      32         [ +  - ]:           1 :     PrivateBroadcast pb;
      33                 :           1 :     const NodeId recipient1{1};
      34                 :           1 :     in_addr ipv4Addr;
      35                 :           1 :     ipv4Addr.s_addr = 0xa0b0c001;
      36         [ +  - ]:           1 :     const CService addr1{ipv4Addr, 1111};
      37                 :             : 
      38                 :             :     // No transactions initially.
      39   [ +  -  +  -  :           2 :     BOOST_CHECK(!pb.PickTxForSend(/*will_send_to_nodeid=*/recipient1, /*will_send_to_address=*/addr1).has_value());
             +  -  +  - ]
      40   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.GetStale().size(), 0);
                   +  - ]
      41   [ +  -  +  -  :           2 :     BOOST_CHECK(!pb.HavePendingTransactions());
             +  -  +  - ]
      42   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.GetBroadcastInfo().size(), 0);
                   +  - ]
      43                 :             : 
      44                 :             :     // Make a transaction and add it.
      45         [ +  - ]:           1 :     const auto tx1{MakeDummyTx(/*id=*/1, /*num_witness=*/0)};
      46                 :             : 
      47   [ +  -  +  -  :           2 :     BOOST_CHECK(pb.Add(tx1));
             +  -  +  - ]
      48   [ +  -  +  -  :           2 :     BOOST_CHECK(!pb.Add(tx1));
             +  -  +  - ]
      49                 :             : 
      50                 :             :     // Make another transaction with same txid, different wtxid and add it.
      51         [ +  - ]:           1 :     const auto tx2{MakeDummyTx(/*id=*/1, /*num_witness=*/1)};
      52   [ +  -  +  -  :           2 :     BOOST_REQUIRE(tx1->GetHash() == tx2->GetHash());
                   +  - ]
      53   [ +  -  +  -  :           2 :     BOOST_REQUIRE(tx1->GetWitnessHash() != tx2->GetWitnessHash());
                   +  - ]
      54                 :             : 
      55   [ +  -  +  -  :           2 :     BOOST_CHECK(pb.Add(tx2));
             +  -  +  - ]
      56                 :           7 :     const auto find_tx_info{[](auto& infos, const CTransactionRef& tx) -> const PrivateBroadcast::TxBroadcastInfo& {
      57         [ +  + ]:          15 :         const auto it{std::ranges::find(infos, tx->GetWitnessHash(), [](const auto& info) { return info.tx->GetWitnessHash(); })};
      58         [ +  - ]:          12 :         BOOST_REQUIRE(it != infos.end());
      59                 :           6 :         return *it;
      60                 :             :     }};
      61                 :           3 :     const auto check_peer_counts{[&](size_t tx1_peer_count, size_t tx2_peer_count) {
      62                 :           2 :         const auto infos{pb.GetBroadcastInfo()};
      63   [ +  -  -  +  :           2 :         BOOST_CHECK_EQUAL(infos.size(), 2);
                   +  - ]
      64   [ +  -  +  -  :           2 :         BOOST_CHECK_EQUAL(find_tx_info(infos, tx1).peers.size(), tx1_peer_count);
             -  +  +  - ]
      65   [ +  -  +  -  :           2 :         BOOST_CHECK_EQUAL(find_tx_info(infos, tx2).peers.size(), tx2_peer_count);
             -  +  +  - ]
      66                 :           3 :     }};
      67                 :             : 
      68         [ +  - ]:           1 :     check_peer_counts(/*tx1_peer_count=*/0, /*tx2_peer_count=*/0);
      69                 :             : 
      70         [ +  - ]:           2 :     const auto tx_for_recipient1{pb.PickTxForSend(/*will_send_to_nodeid=*/recipient1, /*will_send_to_address=*/addr1).value()};
      71   [ +  -  +  -  :           3 :     BOOST_CHECK(tx_for_recipient1 == tx1 || tx_for_recipient1 == tx2);
          +  -  +  -  +  
                      - ]
      72                 :             : 
      73                 :             :     // A second pick must return the other transaction.
      74                 :           1 :     const NodeId recipient2{2};
      75         [ +  - ]:           1 :     const CService addr2{ipv4Addr, 2222};
      76         [ +  - ]:           2 :     const auto tx_for_recipient2{pb.PickTxForSend(/*will_send_to_nodeid=*/recipient2, /*will_send_to_address=*/addr2).value()};
      77   [ +  -  -  +  :           2 :     BOOST_CHECK(tx_for_recipient2 == tx1 || tx_for_recipient2 == tx2);
          -  -  +  -  +  
                      - ]
      78   [ +  -  +  - ]:           1 :     BOOST_CHECK_NE(tx_for_recipient1, tx_for_recipient2);
      79                 :             : 
      80         [ +  - ]:           1 :     check_peer_counts(/*tx1_peer_count=*/1, /*tx2_peer_count=*/1);
      81                 :             : 
      82                 :           1 :     const NodeId nonexistent_recipient{0};
      83                 :             : 
      84                 :             :     // Confirm transactions <-> recipients mapping is correct.
      85   [ +  -  +  -  :           2 :     BOOST_CHECK(!pb.GetTxForNode(nonexistent_recipient).has_value());
             +  -  +  - ]
      86   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.GetTxForNode(recipient1).value(), tx_for_recipient1);
                   +  - ]
      87   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.GetTxForNode(recipient2).value(), tx_for_recipient2);
                   +  - ]
      88                 :             : 
      89                 :             :     // Confirm none of the transactions' reception have been confirmed.
      90   [ +  -  +  -  :           2 :     BOOST_CHECK(!pb.DidNodeConfirmReception(recipient1));
             +  -  +  - ]
      91   [ +  -  +  -  :           2 :     BOOST_CHECK(!pb.DidNodeConfirmReception(recipient2));
             +  -  +  - ]
      92   [ +  -  +  -  :           2 :     BOOST_CHECK(!pb.DidNodeConfirmReception(nonexistent_recipient));
             +  -  +  - ]
      93                 :             : 
      94                 :             :     // 1. Freshly added transactions should NOT be stale yet.
      95   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.GetStale().size(), 0);
                   +  - ]
      96                 :             : 
      97                 :             :     // 2. Fast-forward the mock clock past the INITIAL_STALE_DURATION.
      98         [ +  - ]:           1 :     clock += PrivateBroadcast::INITIAL_STALE_DURATION + 1min;
      99                 :             : 
     100                 :             :     // 3. Now that the initial duration has passed, both unconfirmed transactions should be stale.
     101   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.GetStale().size(), 2);
                   +  - ]
     102                 :             : 
     103                 :             :     // Confirm reception by recipient1.
     104         [ +  - ]:           1 :     pb.NodeConfirmedReception(nonexistent_recipient); // Dummy call.
     105         [ +  - ]:           1 :     pb.NodeConfirmedReception(recipient1);
     106                 :             : 
     107   [ +  -  +  -  :           2 :     BOOST_CHECK(pb.DidNodeConfirmReception(recipient1));
             +  -  +  - ]
     108   [ +  -  +  -  :           2 :     BOOST_CHECK(!pb.DidNodeConfirmReception(recipient2));
             +  -  +  - ]
     109                 :             : 
     110         [ +  - ]:           1 :     const auto infos{pb.GetBroadcastInfo()};
     111   [ +  -  -  +  :           1 :     BOOST_CHECK_EQUAL(infos.size(), 2);
                   +  - ]
     112                 :           1 :     {
     113         [ +  - ]:           1 :         const auto& peers{find_tx_info(infos, tx_for_recipient1).peers};
     114   [ +  -  -  +  :           1 :         BOOST_CHECK_EQUAL(peers.size(), 1);
                   +  - ]
     115   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(peers[0].address.ToStringAddrPort(), addr1.ToStringAddrPort());
             +  -  +  - ]
     116   [ +  -  +  -  :           2 :         BOOST_CHECK(peers[0].received.has_value());
                   +  - ]
     117                 :             :     }
     118                 :           1 :     {
     119         [ +  - ]:           1 :         const auto& peers{find_tx_info(infos, tx_for_recipient2).peers};
     120   [ +  -  -  +  :           1 :         BOOST_CHECK_EQUAL(peers.size(), 1);
                   +  - ]
     121   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(peers[0].address.ToStringAddrPort(), addr2.ToStringAddrPort());
             +  -  +  - ]
     122   [ +  -  +  -  :           2 :         BOOST_CHECK(!peers[0].received.has_value());
                   +  - ]
     123                 :             :     }
     124                 :             : 
     125         [ +  - ]:           1 :     const auto stale_state{pb.GetStale()};
     126   [ +  -  -  +  :           1 :     BOOST_CHECK_EQUAL(stale_state.size(), 1);
                   +  - ]
     127   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(stale_state[0], tx_for_recipient2);
     128                 :             : 
     129         [ +  - ]:           1 :     clock += 10h;
     130                 :             : 
     131   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.GetStale().size(), 2);
                   +  - ]
     132                 :             : 
     133   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.Remove(tx_for_recipient1).value(), 1);
                   +  - ]
     134   [ +  -  +  -  :           2 :     BOOST_CHECK(!pb.Remove(tx_for_recipient1).has_value());
             +  -  +  - ]
     135   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.Remove(tx_for_recipient2).value(), 0);
                   +  - ]
     136   [ +  -  +  -  :           2 :     BOOST_CHECK(!pb.Remove(tx_for_recipient2).has_value());
             +  -  +  - ]
     137                 :             : 
     138   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.GetBroadcastInfo().size(), 0);
                   +  - ]
     139         [ +  - ]:           1 :     const CService addr_nonexistent{ipv4Addr, 3333};
     140   [ +  -  +  -  :           2 :     BOOST_CHECK(!pb.PickTxForSend(/*will_send_to_nodeid=*/nonexistent_recipient, /*will_send_to_address=*/addr_nonexistent).has_value());
                   +  - ]
     141   [ +  -  +  -  :           5 : }
             +  -  +  - ]
     142                 :             : 
     143   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(stale_unpicked_tx)
          +  -  +  -  -  
          +  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
                      - ]
     144                 :             : {
     145                 :           1 :     FakeNodeClock clock{};
     146                 :             : 
     147         [ +  - ]:           1 :     PrivateBroadcast pb;
     148         [ +  - ]:           1 :     const auto tx{MakeDummyTx(/*id=*/42, /*num_witness=*/0)};
     149   [ +  -  +  -  :           2 :     BOOST_REQUIRE(pb.Add(tx));
             +  -  +  - ]
     150                 :             : 
     151                 :             :     // Unpicked transactions use the longer INITIAL_STALE_DURATION.
     152   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.GetStale().size(), 0);
                   +  - ]
     153         [ +  - ]:           1 :     clock += PrivateBroadcast::INITIAL_STALE_DURATION - 1min;
     154   [ +  -  +  -  :           2 :     BOOST_CHECK_EQUAL(pb.GetStale().size(), 0);
                   +  - ]
     155         [ +  - ]:           1 :     clock += 2min;
     156         [ +  - ]:           1 :     const auto stale_state{pb.GetStale()};
     157   [ +  -  -  +  :           1 :     BOOST_REQUIRE_EQUAL(stale_state.size(), 1);
                   +  - ]
     158   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(stale_state[0], tx);
     159         [ +  - ]:           2 : }
     160                 :             : 
     161                 :             : BOOST_AUTO_TEST_SUITE_END()
        

Generated by: LCOV version 2.0-1