13#include <boost/test/unit_test.hpp>
31 mtx.
vin[0].nSequence = id;
32 if (num_witness > 0) {
34 mtx.
vin[0].scriptWitness.stack.resize(num_witness);
36 return MakeTransactionRef(mtx);
44 const NodeId recipient1{1};
46 ipv4Addr.s_addr = 0xa0b0c001;
47 const CService addr1{ipv4Addr, 1111};
63 BOOST_REQUIRE(tx1->GetHash() == tx2->GetHash());
64 BOOST_REQUIRE(tx1->GetWitnessHash() != tx2->GetWitnessHash());
68 const auto it{std::ranges::find(infos, tx->GetWitnessHash(), [](
const auto& info) { return info.tx->GetWitnessHash(); })};
69 BOOST_REQUIRE(it != infos.end());
72 const auto check_peer_counts{[&](
size_t tx1_peer_count,
size_t tx2_peer_count) {
79 check_peer_counts(0, 0);
81 const auto tx_for_recipient1{pb.
PickTxForSend(recipient1, addr1).value()};
82 BOOST_CHECK(tx_for_recipient1 == tx1 || tx_for_recipient1 == tx2);
85 const NodeId recipient2{2};
86 const CService addr2{ipv4Addr, 2222};
87 const auto tx_for_recipient2{pb.
PickTxForSend(recipient2, addr2).value()};
88 BOOST_CHECK(tx_for_recipient2 == tx1 || tx_for_recipient2 == tx2);
91 check_peer_counts(1, 1);
93 const NodeId nonexistent_recipient{0};
102 BOOST_CHECK(std::ranges::none_of(info.peers, [](
const auto& peer) { return peer.received.has_value(); }));
121 const auto& peers{find_tx_info(infos, tx_for_recipient1).peers};
127 const auto& peers{find_tx_info(infos, tx_for_recipient2).peers};
133 const auto stale_state{pb.
GetStale()};
147 const CService addr_nonexistent{ipv4Addr, 3333};
158 ipv4_addr.s_addr = 0xa0b0c001;
159 const CService address{ipv4_addr, 1111};
162 BOOST_REQUIRE_EQUAL(pb.
PickTxForSend(1, address).value(), tx);
170 BOOST_REQUIRE_EQUAL(pb.
PickTxForSend(2, address).value(), tx);
171 BOOST_REQUIRE_EQUAL(pb.
PickTxForSend(3, address).value(), tx);
191 const auto stale_state{pb.
GetStale()};
192 BOOST_REQUIRE_EQUAL(stale_state.size(), 1);
200 constexpr size_t max_attempts{5};
206 ipv4_addr.s_addr = 0xa0b0c001;
207 const CService address{ipv4_addr, 1111};
210 for (
size_t attempt{0}; attempt < max_attempts; ++attempt) {
215 BOOST_REQUIRE_EQUAL(pb.
PickTxForSend(node_id++, address).value(), tx);
224 BOOST_REQUIRE_EQUAL(info.size(), 1);
235 BOOST_REQUIRE_EQUAL(pb.
PickTxForSend(node_id++, address).value(), next_tx);
243 const auto reset_tx_info{std::ranges::find(reset_info, tx->GetWitnessHash(), [](
const auto& entry) { return entry.tx->GetWitnessHash(); })};
244 BOOST_REQUIRE(reset_tx_info != reset_info.end());
247 BOOST_REQUIRE_EQUAL(pb.
PickTxForSend(node_id++, address).value(), tx);
255 BOOST_REQUIRE(tx != equivalent_tx);
256 BOOST_REQUIRE(tx->GetWitnessHash() == equivalent_tx->GetWitnessHash());
259 ipv4_addr.s_addr = 0xa0b0c001;
260 const CService address{ipv4_addr, 1111};
262 BOOST_REQUIRE_EQUAL(pb.
PickTxForSend(0, address).value(), tx);
265 BOOST_REQUIRE_EQUAL(confirmed_info.size(), 1);
266 BOOST_REQUIRE_EQUAL(confirmed_info[0].peers.size(), 1);
267 BOOST_CHECK(confirmed_info[0].peers[0].received.has_value());
276 BOOST_REQUIRE_EQUAL(info.size(), 1);
277 BOOST_CHECK(info[0].tx->GetWitnessHash() == tx->GetWitnessHash());
286 constexpr size_t num_over{5};
289 std::vector<CTransactionRef> txs;
290 txs.reserve(num_cap);
291 for (
size_t i{0}; i < num_cap; ++i) {
294 txs.push_back(std::move(tx));
299 for (
size_t i{0}; i < num_over; ++i) {
300 const auto tx{
MakeDummyTx(
static_cast<uint32_t
>(num_cap + i), 0)};
307 std::set<uint256> present_wtxids;
308 for (
const auto& info : infos) {
309 present_wtxids.insert(info.tx->GetWitnessHash().ToUint256());
312 for (
size_t i{0}; i < num_cap; ++i) {
313 BOOST_CHECK_MESSAGE(present_wtxids.contains(txs[i]->GetWitnessHash().ToUint256()),
314 "tx index " << i <<
" should still be present");
322 BOOST_REQUIRE(pb.
Remove(txs[0]).has_value());
329 BOOST_REQUIRE(pb.
Remove(fresh).has_value());
QDataStream & operator<<(QDataStream &out, const BitcoinUnit &unit)
A combination of a network address (CNetAddr) and a (TCP) port.
std::string ToStringAddrPort() const
Helper to initialize the global NodeClock, let a duration elapse, and reset it after use in a test.
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...
AddResult Add(const CTransactionRef &tx) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Add a transaction to the storage, or reset an exhausted transaction so it can be broadcast again.
std::vector< TxBroadcastInfo > GetBroadcastInfo() const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Get stats about all transactions currently being privately broadcast.
bool MarkResolved(const CTransactionRef &tx) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Mark a transaction as resolved because it was received back from the network or is no longer acceptab...
AddResult
Outcome of Add().
@ QueueFull
Rejected: the queue is already at MAX_TRANSACTIONS.
@ AlreadyPresent
The transaction was already present with send attempts remaining; no change.
@ Added
The transaction was newly added or reset after exhausting its send attempts.
bool HavePendingTransactions() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Check if there are transactions with send attempts remaining.
std::optional< size_t > Remove(const CTransactionRef &tx) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Forget a transaction.
void NodeDisconnected(NodeId nodeid) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Mark a connection finished.
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.
bool TryGrantRetry(const CTransactionRef &tx) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Grant one additional send attempt if the transaction is unresolved, all planned sends have been picke...
static constexpr size_t MAX_TRANSACTIONS
Maximum number of transactions tracked simultaneously.
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().
std::vector< CTransactionRef > GetStale() const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Get the transactions that have not been broadcast recently and have send attempts remaining.
static constexpr size_t INITIAL_CONNECTION_COUNT
Number of connections to make for initial broadcast.
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_AUTO_TEST_CASE(ipc_tests)
#define BOOST_CHECK_EQUAL(v1, v2)
#define BOOST_CHECK(expr)
std::shared_ptr< const CTransaction > CTransactionRef
static CTransactionRef MakeDummyTx(uint32_t id, size_t num_witness)
A mutable version of CTransaction.
BOOST_CHECK_NE(OneL.ToString(), ArrayToString(ZeroArray, 32))