Bitcoin Core  31.0.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 
12 static constexpr auto STALE_DURATION{1min};
13 
15  EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
16 {
17  LOCK(m_mutex);
18  const bool inserted{m_transactions.try_emplace(tx).second};
19  return inserted;
20 }
21 
22 std::optional<size_t> PrivateBroadcast::Remove(const CTransactionRef& tx)
23  EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
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 
34 std::optional<CTransactionRef> PrivateBroadcast::PickTxForSend(const NodeId& will_send_to_nodeid, const CService& will_send_to_address)
35  EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
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, will_send_to_address, NodeClock::now());
47  return tx;
48  }
49 
50  return std::nullopt;
51 }
52 
53 std::optional<CTransactionRef> PrivateBroadcast::GetTxForNode(const NodeId& nodeid)
54  EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
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 
65  EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
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 
75  EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
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 
86  EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
87 {
88  LOCK(m_mutex);
89  return !m_transactions.empty();
90 }
91 
92 std::vector<CTransactionRef> PrivateBroadcast::GetStale() const
93  EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
94 {
95  LOCK(m_mutex);
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 
107 std::vector<PrivateBroadcast::TxBroadcastInfo> PrivateBroadcast::GetBroadcastInfo() const
108  EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
109 {
110  LOCK(m_mutex);
111  std::vector<TxBroadcastInfo> entries;
112  entries.reserve(m_transactions.size());
113 
114  for (const auto& [tx, sent_to] : m_transactions) {
115  std::vector<PeerSendInfo> peers;
116  peers.reserve(sent_to.size());
117  for (const auto& status : sent_to) {
118  peers.emplace_back(PeerSendInfo{.address = status.address, .sent = status.picked, .received = status.confirmed});
119  }
120  entries.emplace_back(TxBroadcastInfo{.tx = tx, .peers = std::move(peers)});
121  }
122 
123  return entries;
124 }
125 
126 PrivateBroadcast::Priority PrivateBroadcast::DerivePriority(const std::vector<SendStatus>& sent_to)
127 {
128  Priority p;
129  p.num_picked = sent_to.size();
130  for (const auto& send_status : sent_to) {
131  p.last_picked = std::max(p.last_picked, send_status.picked);
132  if (send_status.confirmed.has_value()) {
133  ++p.num_confirmed;
134  p.last_confirmed = std::max(p.last_confirmed, send_status.confirmed.value());
135  }
136  }
137  return p;
138 }
139 
140 std::optional<PrivateBroadcast::TxAndSendStatusForNode> PrivateBroadcast::GetSendStatusByNode(const NodeId& nodeid)
141  EXCLUSIVE_LOCKS_REQUIRED(m_mutex)
142 {
143  AssertLockHeld(m_mutex);
144  for (auto& [tx, sent_to] : m_transactions) {
145  for (auto& send_status : sent_to) {
146  if (send_status.nodeid == nodeid) {
147  return TxAndSendStatusForNode{.tx = tx, .send_status = send_status};
148  }
149  }
150  }
151  return std::nullopt;
152 }
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:403
A pair of a transaction and a sent status for a given node. Convenience return type of GetSendStatusB...
AssertLockHeld(pool.cs)
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...
std::optional< size_t > Remove(const CTransactionRef &tx) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Forget a transaction.
std::vector< TxBroadcastInfo > GetBroadcastInfo() const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Get stats about all transactions currently being privately broadcast.
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 HavePendingTransactions() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Check if there are transactions that need to be broadcast.
#define LOCK(cs)
Definition: sync.h:258
std::optional< TxAndSendStatusForNode > GetSendStatusByNode(const NodeId &nodeid) EXCLUSIVE_LOCKS_REQUIRED(m_mutex)
Find which transaction we sent to a given node (marked by PickTxForSend()).
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:529
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...
NodeClock::time_point last_picked
The most recent time when the transaction was picked for sending.
static Priority DerivePriority(const std::vector< SendStatus > &sent_to)
Derive the sending priority of a transaction.
int64_t NodeId
Definition: net.h:103
Cumulative stats from all the send attempts for a transaction. Used to prioritize transactions...
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:30
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:51
bool DidNodeConfirmReception(const NodeId &nodeid) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Check if the node has confirmed reception of the transaction.
size_t num_confirmed
Number of nodes that have confirmed reception of a transaction (by PONG).
std::vector< CTransactionRef > GetStale() const EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Get the transactions that have not been broadcast recently.
bool Add(const CTransactionRef &tx) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
Add a transaction to the storage.
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.