19#include <unordered_set>
24 return static_cast<size_t>(tx->GetWitnessHash().ToUint256().GetUint64(0));
31 return a->GetWitnessHash() == b->GetWitnessHash();
45 std::unordered_map<CTransactionRef, size_t, CTransactionRefHash, CTransactionRefComp> transactions;
48 std::unordered_set<NodeId> nodes_sent_to;
51 std::unordered_set<NodeId> nodes_that_confirmed_reception;
55 const auto ExistentOrNewNodeId = [&next_nodeid, &fdp](){
67 bool from_transactions{
false};
69 tx = MakeTransactionRef(ConsumeTransaction(fdp, std::nullopt));
71 tx = PickIterator(fdp, transactions)->first;
72 from_transactions = true;
75 Assert(!from_transactions);
76 transactions.emplace(tx, 0);
80 if (transactions.empty()) {
83 const auto transactions_it{PickIterator(fdp, transactions)};
86 size_t num_nodes_that_confirmed_tx{0};
89 for (
auto it = nodes_sent_to.begin(); it != nodes_sent_to.end();) {
90 const NodeId nodeid{*it};
91 const auto opt_tx_for_node{pb.GetTxForNode(nodeid)};
92 if (opt_tx_for_node.has_value() && opt_tx_for_node.value() == tx) {
93 it = nodes_sent_to.erase(it);
94 if (nodes_that_confirmed_reception.erase(nodeid) > 0) {
95 ++num_nodes_that_confirmed_tx;
102 const auto opt_num_confirmed{pb.
Remove(tx)};
104 Assert(opt_num_confirmed.has_value());
105 Assert(opt_num_confirmed.value() == num_nodes_that_confirmed_tx);
107 transactions.erase(transactions_it);
111 const NodeId will_send_to_nodeid{next_nodeid++};
114 const auto opt_tx{pb.PickTxForSend(will_send_to_nodeid, will_send_to_address)};
116 if (opt_tx.has_value()) {
117 Assert(transactions.contains(opt_tx.value()));
123 const size_t min_picked{std::ranges::min_element(
124 transactions, {}, [](
const auto& el) {
return el.second; })->second};
125 const auto picked_it{transactions.find(opt_tx.value())};
126 Assert(picked_it != transactions.end());
127 Assert(picked_it->second == min_picked);
130 const auto& [
_, inserted]{nodes_sent_to.emplace(will_send_to_nodeid)};
133 Assert(transactions.empty());
137 const NodeId nodeid{ExistentOrNewNodeId()};
139 const auto opt_tx{pb.GetTxForNode(nodeid)};
141 if (nodes_sent_to.contains(nodeid)) {
142 Assert(opt_tx.has_value());
143 Assert(transactions.contains(opt_tx.value()));
145 Assert(!opt_tx.has_value());
149 const NodeId nodeid{ExistentOrNewNodeId()};
151 pb.NodeConfirmedReception(nodeid);
153 if (nodes_sent_to.contains(nodeid)) {
157 nodes_that_confirmed_reception.emplace(nodeid);
161 const NodeId nodeid{ExistentOrNewNodeId()};
163 const bool confirmed{pb.DidNodeConfirmReception(nodeid)};
165 if (nodes_that_confirmed_reception.contains(nodeid)) {
172 if (pb.HavePendingTransactions()) {
173 Assert(!transactions.empty());
175 Assert(transactions.empty());
179 const auto stale{pb.GetStale()};
181 Assert(stale.size() <= transactions.size());
183 for (
const auto& stale_tx : stale) {
184 Assert(transactions.contains(stale_tx));
188 const auto all_broadcast_info{pb.GetBroadcastInfo()};
190 Assert(all_broadcast_info.size() == transactions.size());
192 for (
const auto& info : all_broadcast_info) {
193 const auto it{transactions.find(info.tx)};
194 Assert(it != transactions.end());
195 Assert(info.peers.size() == it->second);
#define Assert(val)
Identity function.
A combination of a network address (CNetAddr) and a (TCP) port.
Helper to initialize the global NodeClock, let a duration elapse, and reset it after use in a test.
T ConsumeIntegralInRange(T min, T max)
Store a list of transactions to be broadcast privately.
std::optional< size_t > Remove(const CTransactionRef &tx) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Forget a transaction.
bool Add(const CTransactionRef &tx) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Add a transaction to the storage.
#define LIMITED_WHILE(condition, limit)
Can be used to limit a theoretically unbounded loop.
std::shared_ptr< const CTransaction > CTransactionRef
bool operator()(const CTransactionRef &a, const CTransactionRef &b) const
size_t operator()(const CTransactionRef &tx) const
for(size_t start{0};start< num_entries;start+=SEED_BATCH_SIZE)
SeedRandomStateForTest(SeedRand::ZEROS)
FUZZ_TARGET(private_broadcast)
CService ConsumeService(FuzzedDataProvider &fuzzed_data_provider) noexcept
NodeSeconds ConsumeTime(FuzzedDataProvider &fuzzed_data_provider, const std::optional< int64_t > &min, const std::optional< int64_t > &max) noexcept
size_t CallOneOf(FuzzedDataProvider &fuzzed_data_provider, Callables... callables)
@ ZEROS
Seed with a compile time constant of zeros.
consteval auto _(util::TranslatedLiteral str)