19 const auto& state{entry.second};
20 return state.resolved && !IsPending(state) &&
21 std::ranges::all_of(state.send_statuses, [](
const auto& status) { return status.disconnected; });
25 if (it->second.send_statuses.size() < m_max_send_attempts)
return AddResult::AlreadyPresent;
29 it->second.send_statuses.clear();
30 it->second.planned_sends = INITIAL_CONNECTION_COUNT;
31 it->second.resolved =
false;
32 return AddResult::Added;
35 if (
m_transactions.size() >= m_max_transactions)
return AddResult::QueueFull;
38 return AddResult::Added;
47 const auto& state{
handle.mapped()};
48 const size_t planned{std::min(state.planned_sends, m_max_send_attempts)};
49 const size_t actual{state.send_statuses.size()};
60 it->second.resolved =
true;
68 entry->send_status.disconnected =
true;
77 it->second.resolved ||
80 ++it->second.planned_sends;
95 const auto it{std::ranges::max_element(
97 [](
const auto&
a,
const auto& b) {
return a < b; },
98 [](
const auto&
el) {
return DerivePriority(
el.second.send_statuses); })};
101 auto& [tx, state]{*it};
142 std::vector<CTransactionRef>
stale;
146 if (
p.num_confirmed == 0) {
159 std::vector<TxBroadcastInfo> entries;
163 if (state.resolved)
continue;
164 std::vector<PeerSendInfo> peers;
165 peers.reserve(state.send_statuses.size());
166 for (
const auto& status : state.send_statuses) {
167 peers.emplace_back(
PeerSendInfo{.
address = status.address, .sent = status.picked, .received = status.confirmed});
170 entries.emplace_back(
TxBroadcastInfo{.
tx = tx, .time_added = state.time_added, .attempts_remaining = attempts_remaining, .peers = std::move(peers)});
187 for (
const auto& send_status :
sent_to) {
188 p.last_picked = std::max(
p.last_picked, send_status.picked);
189 if (send_status.confirmed.has_value()) {
191 p.last_confirmed = std::max(
p.last_confirmed, send_status.confirmed.value());
202 for (
auto& send_status : state.send_statuses) {
203 if (send_status.nodeid == nodeid) {
#define Assume(val)
Assume is the identity function.
A combination of a network address (CNetAddr) and a (TCP) port.
static Priority DerivePriority(const std::vector< SendStatus > &sent_to)
Derive the sending priority of a transaction.
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().
bool HavePendingTransactions() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Check if there are transactions with send attempts remaining.
static constexpr auto STALE_DURATION
If a transaction is not received back from the network for this duration after it is broadcast,...
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 IsPending(const TxSendStatus &status) const
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...
std::optional< TxAndSendStatusForNode > GetSendStatusByNode(const NodeId &nodeid) EXCLUSIVE_LOCKS_REQUIRED(m_mutex)
Find which transaction we sent to a given node (marked by PickTxForSend()).
const size_t m_max_send_attempts
Cap on the number of send attempts per transaction (see PickTxForSend()).
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 auto INITIAL_STALE_DURATION
If a transaction is not sent to any peer for this duration, then we consider it stale / for rebroadca...
std::shared_ptr< const CTransaction > CTransactionRef
static time_point now() noexcept
Return current system time or mocked time, if set.
Cumulative stats from all the send attempts for a transaction. Used to prioritize transactions.
size_t num_picked
Number of times the transaction was picked for sending.
A pair of a transaction and a sent status for a given node. Convenience return type of GetSendStatusB...
const CTransactionRef & tx
std::vector< SendStatus > send_statuses
size_t planned_sends
Total number of sends granted, including initial count.
#define AssertLockHeld(cs)
#define EXCLUSIVE_LOCKS_REQUIRED(...)
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.