Bitcoin Core  31.0.0
P2P Digital Currency
private_broadcast_tests.cpp
Go to the documentation of this file.
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 
6 #include <private_broadcast.h>
8 #include <util/time.h>
9 
10 #include <algorithm>
11 #include <boost/test/unit_test.hpp>
12 
13 BOOST_FIXTURE_TEST_SUITE(private_broadcast_tests, BasicTestingSetup)
14 
15 static CTransactionRef MakeDummyTx(uint32_t id, size_t num_witness)
16 {
18  mtx.vin.resize(1);
19  mtx.vin[0].nSequence = id;
20  if (num_witness > 0) {
21  mtx.vin[0].scriptWitness = CScriptWitness{};
22  mtx.vin[0].scriptWitness.stack.resize(num_witness);
23  }
24  return MakeTransactionRef(mtx);
25 }
26 
28 {
29  SetMockTime(Now<NodeSeconds>());
30 
32  const NodeId recipient1{1};
33  in_addr ipv4Addr;
34  ipv4Addr.s_addr = 0xa0b0c001;
35  const CService addr1{ipv4Addr, 1111};
36 
37  // No transactions initially.
38  BOOST_CHECK(!pb.PickTxForSend(/*will_send_to_nodeid=*/recipient1, /*will_send_to_address=*/addr1).has_value());
39  BOOST_CHECK_EQUAL(pb.GetStale().size(), 0);
41  BOOST_CHECK_EQUAL(pb.GetBroadcastInfo().size(), 0);
42 
43  // Make a transaction and add it.
44  const auto tx1{MakeDummyTx(/*id=*/1, /*num_witness=*/0)};
45 
46  BOOST_CHECK(pb.Add(tx1));
47  BOOST_CHECK(!pb.Add(tx1));
48 
49  // Make another transaction with same txid, different wtxid and add it.
50  const auto tx2{MakeDummyTx(/*id=*/1, /*num_witness=*/1)};
51  BOOST_REQUIRE(tx1->GetHash() == tx2->GetHash());
52  BOOST_REQUIRE(tx1->GetWitnessHash() != tx2->GetWitnessHash());
53 
54  BOOST_CHECK(pb.Add(tx2));
55  const auto find_tx_info{[](auto& infos, const CTransactionRef& tx) -> const PrivateBroadcast::TxBroadcastInfo& {
56  const auto it{std::ranges::find(infos, tx->GetWitnessHash(), [](const auto& info) { return info.tx->GetWitnessHash(); })};
57  BOOST_REQUIRE(it != infos.end());
58  return *it;
59  }};
60  const auto check_peer_counts{[&](size_t tx1_peer_count, size_t tx2_peer_count) {
61  const auto infos{pb.GetBroadcastInfo()};
62  BOOST_CHECK_EQUAL(infos.size(), 2);
63  BOOST_CHECK_EQUAL(find_tx_info(infos, tx1).peers.size(), tx1_peer_count);
64  BOOST_CHECK_EQUAL(find_tx_info(infos, tx2).peers.size(), tx2_peer_count);
65  }};
66 
67  check_peer_counts(/*tx1_peer_count=*/0, /*tx2_peer_count=*/0);
68 
69  const auto tx_for_recipient1{pb.PickTxForSend(/*will_send_to_nodeid=*/recipient1, /*will_send_to_address=*/addr1).value()};
70  BOOST_CHECK(tx_for_recipient1 == tx1 || tx_for_recipient1 == tx2);
71 
72  // A second pick must return the other transaction.
73  const NodeId recipient2{2};
74  const CService addr2{ipv4Addr, 2222};
75  const auto tx_for_recipient2{pb.PickTxForSend(/*will_send_to_nodeid=*/recipient2, /*will_send_to_address=*/addr2).value()};
76  BOOST_CHECK(tx_for_recipient2 == tx1 || tx_for_recipient2 == tx2);
77  BOOST_CHECK_NE(tx_for_recipient1, tx_for_recipient2);
78 
79  check_peer_counts(/*tx1_peer_count=*/1, /*tx2_peer_count=*/1);
80 
81  const NodeId nonexistent_recipient{0};
82 
83  // Confirm transactions <-> recipients mapping is correct.
84  BOOST_CHECK(!pb.GetTxForNode(nonexistent_recipient).has_value());
85  BOOST_CHECK_EQUAL(pb.GetTxForNode(recipient1).value(), tx_for_recipient1);
86  BOOST_CHECK_EQUAL(pb.GetTxForNode(recipient2).value(), tx_for_recipient2);
87 
88  // Confirm none of the transactions' reception have been confirmed.
89  BOOST_CHECK(!pb.DidNodeConfirmReception(recipient1));
90  BOOST_CHECK(!pb.DidNodeConfirmReception(recipient2));
91  BOOST_CHECK(!pb.DidNodeConfirmReception(nonexistent_recipient));
92 
93  BOOST_CHECK_EQUAL(pb.GetStale().size(), 2);
94 
95  // Confirm reception by recipient1.
96  pb.NodeConfirmedReception(nonexistent_recipient); // Dummy call.
97  pb.NodeConfirmedReception(recipient1);
98 
99  BOOST_CHECK(pb.DidNodeConfirmReception(recipient1));
100  BOOST_CHECK(!pb.DidNodeConfirmReception(recipient2));
101 
102  const auto infos{pb.GetBroadcastInfo()};
103  BOOST_CHECK_EQUAL(infos.size(), 2);
104  {
105  const auto& [tx, peers]{find_tx_info(infos, tx_for_recipient1)};
106  BOOST_CHECK_EQUAL(peers.size(), 1);
107  BOOST_CHECK_EQUAL(peers[0].address.ToStringAddrPort(), addr1.ToStringAddrPort());
108  BOOST_CHECK(peers[0].received.has_value());
109  }
110  {
111  const auto& [tx, peers]{find_tx_info(infos, tx_for_recipient2)};
112  BOOST_CHECK_EQUAL(peers.size(), 1);
113  BOOST_CHECK_EQUAL(peers[0].address.ToStringAddrPort(), addr2.ToStringAddrPort());
114  BOOST_CHECK(!peers[0].received.has_value());
115  }
116 
117  BOOST_CHECK_EQUAL(pb.GetStale().size(), 1);
118  BOOST_CHECK_EQUAL(pb.GetStale()[0], tx_for_recipient2);
119 
120  SetMockTime(Now<NodeSeconds>() + 10h);
121 
122  BOOST_CHECK_EQUAL(pb.GetStale().size(), 2);
123 
124  BOOST_CHECK_EQUAL(pb.Remove(tx_for_recipient1).value(), 1);
125  BOOST_CHECK(!pb.Remove(tx_for_recipient1).has_value());
126  BOOST_CHECK_EQUAL(pb.Remove(tx_for_recipient2).value(), 0);
127  BOOST_CHECK(!pb.Remove(tx_for_recipient2).has_value());
128 
129  BOOST_CHECK_EQUAL(pb.GetBroadcastInfo().size(), 0);
130  const CService addr_nonexistent{ipv4Addr, 3333};
131  BOOST_CHECK(!pb.PickTxForSend(/*will_send_to_nodeid=*/nonexistent_recipient, /*will_send_to_address=*/addr_nonexistent).has_value());
132 }
133 
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:403
void NodeConfirmedReception(const NodeId &nodeid) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Mark that the node has confirmed reception of the transaction we sent it by responding with PONG to o...
std::vector< CTxIn > vin
Definition: transaction.h:359
std::optional< size_t > Remove(const CTransactionRef &tx) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Forget a transaction.
std::vector< TxBroadcastInfo > GetBroadcastInfo() const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Get stats about all transactions currently being privately broadcast.
BOOST_AUTO_TEST_CASE(basic)
Basic testing setup.
Definition: setup_common.h:64
std::optional< CTransactionRef > GetTxForNode(const NodeId &nodeid) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Get the transaction that was picked for sending to a given node by PickTxForSend().
static const std::string addr2
Definition: key_tests.cpp:32
bool HavePendingTransactions() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Check if there are transactions that need to be broadcast.
static const std::string addr1
Definition: key_tests.cpp:31
BOOST_FIXTURE_TEST_SUITE(cuckoocache_tests, BasicTestingSetup)
Test Suite for CuckooCache.
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:529
BOOST_AUTO_TEST_SUITE_END()
std::optional< CTransactionRef > PickTxForSend(const NodeId &will_send_to_nodeid, const CService &will_send_to_address) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Pick the transaction with the fewest send attempts, and confirmations, and oldest send/confirm times...
int64_t NodeId
Definition: net.h:103
static CTransactionRef MakeTransactionRef(Tx &&txIn)
Definition: transaction.h:404
bool DidNodeConfirmReception(const NodeId &nodeid) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Check if the node has confirmed reception of the transaction.
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:17
std::vector< CTransactionRef > GetStale() const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Get the transactions that have not been broadcast recently.
bool Add(const CTransactionRef &tx) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Add a transaction to the storage.
static CTransactionRef MakeDummyTx(uint32_t id, size_t num_witness)
Store a list of transactions to be broadcast privately.
void SetMockTime(int64_t nMockTimeIn)
DEPRECATED Use SetMockTime with chrono type.
Definition: time.cpp:44
A mutable version of CTransaction.
Definition: transaction.h:357
#define BOOST_CHECK(expr)
Definition: object.cpp:16