Bitcoin Core 30.99.0
P2P Digital Currency
private_broadcast.cpp
Go to the documentation of this file.
1// Copyright (c) 2023-present The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or https://opensource.org/license/mit/.
4
5#include <private_broadcast.h>
6#include <util/check.h>
7
8#include <algorithm>
9
12static constexpr auto STALE_DURATION{1min};
13
16{
17 LOCK(m_mutex);
18 const bool inserted{m_transactions.try_emplace(tx).second};
19 return inserted;
20}
21
22std::optional<size_t> PrivateBroadcast::Remove(const CTransactionRef& tx)
24{
25 LOCK(m_mutex);
26 const auto handle{m_transactions.extract(tx)};
27 if (handle) {
28 const auto p{DerivePriority(handle.mapped())};
29 return p.num_confirmed;
30 }
31 return std::nullopt;
32}
33
34std::optional<CTransactionRef> PrivateBroadcast::PickTxForSend(const NodeId& will_send_to_nodeid)
36{
37 LOCK(m_mutex);
38
39 const auto it{std::ranges::max_element(
40 m_transactions,
41 [](const auto& a, const auto& b) { return a < b; },
42 [](const auto& el) { return DerivePriority(el.second); })};
43
44 if (it != m_transactions.end()) {
45 auto& [tx, sent_to]{*it};
46 sent_to.emplace_back(will_send_to_nodeid, NodeClock::now());
47 return tx;
48 }
49
50 return std::nullopt;
51}
52
53std::optional<CTransactionRef> PrivateBroadcast::GetTxForNode(const NodeId& nodeid)
55{
56 LOCK(m_mutex);
57 const auto tx_and_status{GetSendStatusByNode(nodeid)};
58 if (tx_and_status.has_value()) {
59 return tx_and_status.value().tx;
60 }
61 return std::nullopt;
62}
63
66{
67 LOCK(m_mutex);
68 const auto tx_and_status{GetSendStatusByNode(nodeid)};
69 if (tx_and_status.has_value()) {
70 tx_and_status.value().send_status.confirmed = NodeClock::now();
71 }
72}
73
76{
77 LOCK(m_mutex);
78 const auto tx_and_status{GetSendStatusByNode(nodeid)};
79 if (tx_and_status.has_value()) {
80 return tx_and_status.value().send_status.confirmed.has_value();
81 }
82 return false;
83}
84
87{
89 return !m_transactions.empty();
90}
91
92std::vector<CTransactionRef> PrivateBroadcast::GetStale() const
94{
96 const auto stale_time{NodeClock::now() - STALE_DURATION};
97 std::vector<CTransactionRef> stale;
98 for (const auto& [tx, send_status] : m_transactions) {
99 const Priority p{DerivePriority(send_status)};
100 if (p.last_confirmed < stale_time) {
101 stale.push_back(tx);
102 }
103 }
104 return stale;
105}
106
108{
109 Priority p;
110 p.num_picked = sent_to.size();
111 for (const auto& send_status : sent_to) {
112 p.last_picked = std::max(p.last_picked, send_status.picked);
113 if (send_status.confirmed.has_value()) {
114 ++p.num_confirmed;
115 p.last_confirmed = std::max(p.last_confirmed, send_status.confirmed.value());
116 }
117 }
118 return p;
119}
120
121std::optional<PrivateBroadcast::TxAndSendStatusForNode> PrivateBroadcast::GetSendStatusByNode(const NodeId& nodeid)
123{
124 AssertLockHeld(m_mutex);
125 for (auto& [tx, sent_to] : m_transactions) {
126 for (auto& send_status : sent_to) {
127 if (send_status.nodeid == nodeid) {
128 return TxAndSendStatusForNode{.tx = tx, .send_status = send_status};
129 }
130 }
131 }
132 return std::nullopt;
133}
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...
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) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Pick the transaction with the fewest send attempts, and confirmations, and oldest send/confirm times.
std::optional< TxAndSendStatusForNode > GetSendStatusByNode(const NodeId &nodeid) EXCLUSIVE_LOCKS_REQUIRED(m_mutex)
Find which transaction we sent to a given node (marked by 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().
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.
int64_t NodeId
Definition: net.h:103
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:403
static constexpr auto STALE_DURATION
If a transaction is not received back from the network for this duration after it is broadcast,...
static time_point now() noexcept
Return current system time or mocked time, if set.
Definition: time.cpp:26
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.
NodeClock::time_point last_confirmed
The most recent time when the transaction was confirmed.
size_t num_confirmed
Number of nodes that have confirmed reception of a transaction (by PONG).
NodeClock::time_point last_picked
The most recent time when the transaction was picked for sending.
A pair of a transaction and a sent status for a given node. Convenience return type of GetSendStatusB...
#define LOCK(cs)
Definition: sync.h:259
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:51
AssertLockHeld(pool.cs)