Bitcoin Core 31.99.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 <test/util/time.h>
9#include <util/time.h>
10
11#include <algorithm>
12#include <boost/test/unit_test.hpp>
13
14BOOST_FIXTURE_TEST_SUITE(private_broadcast_tests, BasicTestingSetup)
15
16static CTransactionRef MakeDummyTx(uint32_t id, size_t num_witness)
17{
19 mtx.vin.resize(1);
20 mtx.vin[0].nSequence = id;
21 if (num_witness > 0) {
22 mtx.vin[0].scriptWitness = CScriptWitness{};
23 mtx.vin[0].scriptWitness.stack.resize(num_witness);
24 }
25 return MakeTransactionRef(mtx);
26}
27
29{
30 FakeNodeClock clock{};
31
33 const NodeId recipient1{1};
34 in_addr ipv4Addr;
35 ipv4Addr.s_addr = 0xa0b0c001;
36 const CService addr1{ipv4Addr, 1111};
37
38 // No transactions initially.
39 BOOST_CHECK(!pb.PickTxForSend(/*will_send_to_nodeid=*/recipient1, /*will_send_to_address=*/addr1).has_value());
40 BOOST_CHECK_EQUAL(pb.GetStale().size(), 0);
42 BOOST_CHECK_EQUAL(pb.GetBroadcastInfo().size(), 0);
43
44 // Make a transaction and add it.
45 const auto tx1{MakeDummyTx(/*id=*/1, /*num_witness=*/0)};
46
47 BOOST_CHECK(pb.Add(tx1));
48 BOOST_CHECK(!pb.Add(tx1));
49
50 // Make another transaction with same txid, different wtxid and add it.
51 const auto tx2{MakeDummyTx(/*id=*/1, /*num_witness=*/1)};
52 BOOST_REQUIRE(tx1->GetHash() == tx2->GetHash());
53 BOOST_REQUIRE(tx1->GetWitnessHash() != tx2->GetWitnessHash());
54
55 BOOST_CHECK(pb.Add(tx2));
56 const auto find_tx_info{[](auto& infos, const CTransactionRef& tx) -> const PrivateBroadcast::TxBroadcastInfo& {
57 const auto it{std::ranges::find(infos, tx->GetWitnessHash(), [](const auto& info) { return info.tx->GetWitnessHash(); })};
58 BOOST_REQUIRE(it != infos.end());
59 return *it;
60 }};
61 const auto check_peer_counts{[&](size_t tx1_peer_count, size_t tx2_peer_count) {
62 const auto infos{pb.GetBroadcastInfo()};
63 BOOST_CHECK_EQUAL(infos.size(), 2);
64 BOOST_CHECK_EQUAL(find_tx_info(infos, tx1).peers.size(), tx1_peer_count);
65 BOOST_CHECK_EQUAL(find_tx_info(infos, tx2).peers.size(), tx2_peer_count);
66 }};
67
68 check_peer_counts(/*tx1_peer_count=*/0, /*tx2_peer_count=*/0);
69
70 const auto tx_for_recipient1{pb.PickTxForSend(/*will_send_to_nodeid=*/recipient1, /*will_send_to_address=*/addr1).value()};
71 BOOST_CHECK(tx_for_recipient1 == tx1 || tx_for_recipient1 == tx2);
72
73 // A second pick must return the other transaction.
74 const NodeId recipient2{2};
75 const CService addr2{ipv4Addr, 2222};
76 const auto tx_for_recipient2{pb.PickTxForSend(/*will_send_to_nodeid=*/recipient2, /*will_send_to_address=*/addr2).value()};
77 BOOST_CHECK(tx_for_recipient2 == tx1 || tx_for_recipient2 == tx2);
78 BOOST_CHECK_NE(tx_for_recipient1, tx_for_recipient2);
79
80 check_peer_counts(/*tx1_peer_count=*/1, /*tx2_peer_count=*/1);
81
82 const NodeId nonexistent_recipient{0};
83
84 // Confirm transactions <-> recipients mapping is correct.
85 BOOST_CHECK(!pb.GetTxForNode(nonexistent_recipient).has_value());
86 BOOST_CHECK_EQUAL(pb.GetTxForNode(recipient1).value(), tx_for_recipient1);
87 BOOST_CHECK_EQUAL(pb.GetTxForNode(recipient2).value(), tx_for_recipient2);
88
89 // Confirm none of the transactions' reception have been confirmed.
90 BOOST_CHECK(!pb.DidNodeConfirmReception(recipient1));
91 BOOST_CHECK(!pb.DidNodeConfirmReception(recipient2));
92 BOOST_CHECK(!pb.DidNodeConfirmReception(nonexistent_recipient));
93
94 // 1. Freshly added transactions should NOT be stale yet.
95 BOOST_CHECK_EQUAL(pb.GetStale().size(), 0);
96
97 // 2. Fast-forward the mock clock past the INITIAL_STALE_DURATION.
99
100 // 3. Now that the initial duration has passed, both unconfirmed transactions should be stale.
101 BOOST_CHECK_EQUAL(pb.GetStale().size(), 2);
102
103 // Confirm reception by recipient1.
104 pb.NodeConfirmedReception(nonexistent_recipient); // Dummy call.
105 pb.NodeConfirmedReception(recipient1);
106
107 BOOST_CHECK(pb.DidNodeConfirmReception(recipient1));
108 BOOST_CHECK(!pb.DidNodeConfirmReception(recipient2));
109
110 const auto infos{pb.GetBroadcastInfo()};
111 BOOST_CHECK_EQUAL(infos.size(), 2);
112 {
113 const auto& peers{find_tx_info(infos, tx_for_recipient1).peers};
114 BOOST_CHECK_EQUAL(peers.size(), 1);
115 BOOST_CHECK_EQUAL(peers[0].address.ToStringAddrPort(), addr1.ToStringAddrPort());
116 BOOST_CHECK(peers[0].received.has_value());
117 }
118 {
119 const auto& peers{find_tx_info(infos, tx_for_recipient2).peers};
120 BOOST_CHECK_EQUAL(peers.size(), 1);
121 BOOST_CHECK_EQUAL(peers[0].address.ToStringAddrPort(), addr2.ToStringAddrPort());
122 BOOST_CHECK(!peers[0].received.has_value());
123 }
124
125 const auto stale_state{pb.GetStale()};
126 BOOST_CHECK_EQUAL(stale_state.size(), 1);
127 BOOST_CHECK_EQUAL(stale_state[0], tx_for_recipient2);
128
129 clock += 10h;
130
131 BOOST_CHECK_EQUAL(pb.GetStale().size(), 2);
132
133 BOOST_CHECK_EQUAL(pb.Remove(tx_for_recipient1).value(), 1);
134 BOOST_CHECK(!pb.Remove(tx_for_recipient1).has_value());
135 BOOST_CHECK_EQUAL(pb.Remove(tx_for_recipient2).value(), 0);
136 BOOST_CHECK(!pb.Remove(tx_for_recipient2).has_value());
137
138 BOOST_CHECK_EQUAL(pb.GetBroadcastInfo().size(), 0);
139 const CService addr_nonexistent{ipv4Addr, 3333};
140 BOOST_CHECK(!pb.PickTxForSend(/*will_send_to_nodeid=*/nonexistent_recipient, /*will_send_to_address=*/addr_nonexistent).has_value());
141}
142
143BOOST_AUTO_TEST_CASE(stale_unpicked_tx)
144{
145 FakeNodeClock clock{};
146
148 const auto tx{MakeDummyTx(/*id=*/42, /*num_witness=*/0)};
149 BOOST_REQUIRE(pb.Add(tx));
150
151 // Unpicked transactions use the longer INITIAL_STALE_DURATION.
152 BOOST_CHECK_EQUAL(pb.GetStale().size(), 0);
154 BOOST_CHECK_EQUAL(pb.GetStale().size(), 0);
155 clock += 2min;
156 const auto stale_state{pb.GetStale()};
157 BOOST_REQUIRE_EQUAL(stale_state.size(), 1);
158 BOOST_CHECK_EQUAL(stale_state[0], tx);
159}
160
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:530
Helper to initialize the global NodeClock, let a duration elapse, and reset it after use in a test.
Definition: time.h:54
Store a list of transactions to be broadcast privately.
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< TxBroadcastInfo > GetBroadcastInfo() const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Get stats about all transactions currently being privately broadcast.
bool HavePendingTransactions() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Check if there are transactions that need to be broadcast.
bool DidNodeConfirmReception(const NodeId &nodeid) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Check if the node has confirmed reception of the transaction.
std::optional< size_t > Remove(const CTransactionRef &tx) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Forget a transaction.
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.
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().
bool Add(const CTransactionRef &tx) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Add a transaction to the storage.
std::vector< CTransactionRef > GetStale() const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Get the transactions that have not been broadcast recently.
static constexpr auto INITIAL_STALE_DURATION
If a transaction is not sent to any peer for this duration, then we consider it stale / for rebroadca...
BOOST_FIXTURE_TEST_SUITE(cuckoocache_tests, BasicTestingSetup)
Test Suite for CuckooCache.
BOOST_AUTO_TEST_SUITE_END()
BOOST_CHECK_EQUAL(headers.FindFirst("key"), "value")
static const std::string addr1
Definition: key_tests.cpp:31
static const std::string addr2
Definition: key_tests.cpp:32
int64_t NodeId
Definition: net.h:103
#define BOOST_CHECK(expr)
Definition: object.cpp:16
static CTransactionRef MakeTransactionRef(Tx &&txIn)
Definition: transaction.h:404
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:403
static CTransactionRef MakeDummyTx(uint32_t id, size_t num_witness)
BOOST_AUTO_TEST_CASE(basic)
Basic testing setup.
Definition: setup_common.h:58
A mutable version of CTransaction.
Definition: transaction.h:358
std::vector< CTxIn > vin
Definition: transaction.h:359