19#include <unordered_set>
24 return static_cast<size_t>(tx->GetWitnessHash().ToUint256().GetUint64(0));
31 return a->GetWitnessHash() == b->GetWitnessHash();
46 std::unordered_map<CTransactionRef, size_t, CTransactionRefHash, CTransactionRefComp> transactions;
49 std::unordered_set<NodeId> nodes_sent_to;
52 std::unordered_set<NodeId> nodes_that_confirmed_reception;
56 const auto ExistentOrNewNodeId = [&next_nodeid, &fdp](){
69 tx = MakeTransactionRef(ConsumeTransaction(fdp, std::nullopt));
71 tx = PickIterator(fdp, transactions)->first;
74 const bool present_before{transactions.contains(tx)};
75 const auto res{pb.Add(tx)};
78 }
else if (transactions.size() >= cap) {
82 transactions.emplace(tx, 0);
86 if (transactions.empty()) {
89 const auto transactions_it{
PickIterator(fdp, transactions)};
92 size_t num_nodes_that_confirmed_tx{0};
95 for (
auto it = nodes_sent_to.begin(); it != nodes_sent_to.end();) {
97 const auto opt_tx_for_node{pb.GetTxForNode(nodeid)};
98 if (opt_tx_for_node.has_value() && opt_tx_for_node.value() == tx) {
99 it = nodes_sent_to.erase(it);
100 if (nodes_that_confirmed_reception.erase(nodeid) > 0) {
101 ++num_nodes_that_confirmed_tx;
108 const auto opt_num_confirmed{pb.Remove(tx)};
110 Assert(opt_num_confirmed.has_value());
111 Assert(opt_num_confirmed.value() == num_nodes_that_confirmed_tx);
112 Assert(!pb.Remove(tx).has_value());
113 transactions.erase(transactions_it);
117 const NodeId will_send_to_nodeid{next_nodeid++};
120 const auto opt_tx{pb.PickTxForSend(will_send_to_nodeid, will_send_to_address)};
122 if (opt_tx.has_value()) {
123 Assert(transactions.contains(opt_tx.value()));
129 const size_t min_picked{std::ranges::min_element(
130 transactions, {}, [](
const auto& el) {
return el.second; })->second};
131 const auto picked_it{transactions.find(opt_tx.value())};
132 Assert(picked_it != transactions.end());
133 Assert(picked_it->second == min_picked);
136 const auto& [
_, inserted]{nodes_sent_to.emplace(will_send_to_nodeid)};
139 Assert(transactions.empty());
143 const NodeId nodeid{ExistentOrNewNodeId()};
145 const auto opt_tx{pb.GetTxForNode(nodeid)};
147 if (nodes_sent_to.contains(nodeid)) {
148 Assert(opt_tx.has_value());
149 Assert(transactions.contains(opt_tx.value()));
151 Assert(!opt_tx.has_value());
155 const NodeId nodeid{ExistentOrNewNodeId()};
157 pb.NodeConfirmedReception(nodeid);
159 if (nodes_sent_to.contains(nodeid)) {
163 nodes_that_confirmed_reception.emplace(nodeid);
167 const NodeId nodeid{ExistentOrNewNodeId()};
169 const bool confirmed{pb.DidNodeConfirmReception(nodeid)};
171 if (nodes_that_confirmed_reception.contains(nodeid)) {
178 if (pb.HavePendingTransactions()) {
179 Assert(!transactions.empty());
181 Assert(transactions.empty());
185 const auto stale{pb.GetStale()};
187 Assert(stale.size() <= transactions.size());
189 for (
const auto& stale_tx : stale) {
190 Assert(transactions.contains(stale_tx));
194 const auto all_broadcast_info{pb.GetBroadcastInfo()};
196 Assert(all_broadcast_info.size() == transactions.size());
198 for (
const auto& info : all_broadcast_info) {
199 const auto it{transactions.find(info.tx)};
200 Assert(it != transactions.end());
201 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.
@ QueueFull
Rejected: the queue is already at MAX_TRANSACTIONS.
@ AlreadyPresent
The transaction was already present; no change.
@ Added
The transaction was newly added.
LIMITED_WHILE(provider.remaining_bytes(), 10000)
std::shared_ptr< const CTransaction > CTransactionRef
bool operator()(const CTransactionRef &a, const CTransactionRef &b) const
size_t operator()(const CTransactionRef &tx) const
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)
auto PickIterator(FuzzedDataProvider &fuzzed_data_provider, Collection &col)
@ ZEROS
Seed with a compile time constant of zeros.
consteval auto _(util::TranslatedLiteral str)