Branch data Line data Source code
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 : :
7 : : #include <util/check.h>
8 : :
9 : : #include <algorithm>
10 : :
11 : :
12 : 20027 : PrivateBroadcast::AddResult PrivateBroadcast::Add(const CTransactionRef& tx)
13 : : EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
14 : : {
15 : 20027 : LOCK(m_mutex);
16 : : // Re-adding an already-tracked transaction is a no-op regardless of the cap.
17 [ + + ]: 20027 : if (m_transactions.contains(tx)) return AddResult::AlreadyPresent;
18 : :
19 [ + + ]: 20023 : if (m_transactions.size() >= m_max_transactions) return AddResult::QueueFull;
20 : :
21 [ + - ]: 20013 : m_transactions.try_emplace(tx);
22 : : return AddResult::Added;
23 : 20027 : }
24 : :
25 : 15905 : std::optional<size_t> PrivateBroadcast::Remove(const CTransactionRef& tx)
26 : : EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
27 : : {
28 : 15905 : LOCK(m_mutex);
29 : 15905 : const auto handle{m_transactions.extract(tx)};
30 [ + + ]: 15905 : if (handle) {
31 [ + - ]: 8 : const auto p{DerivePriority(handle.mapped().send_statuses)};
32 : 8 : return p.num_confirmed;
33 : : }
34 : 15897 : return std::nullopt;
35 [ + - ]: 31810 : }
36 : :
37 : 17 : std::optional<CTransactionRef> PrivateBroadcast::PickTxForSend(const NodeId& will_send_to_nodeid, const CService& will_send_to_address)
38 : : EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
39 : : {
40 : 17 : LOCK(m_mutex);
41 : :
42 [ + - - + ]: 17 : if (GetSendStatusByNode(will_send_to_nodeid).has_value()) { // nodeid reuse, shouldn't send >1 tx to a given node
43 : 0 : Assume(false);
44 : 0 : return std::nullopt;
45 : : }
46 : :
47 : 17 : const auto it{std::ranges::max_element(
48 [ + - ]: 17 : m_transactions,
49 : 5 : [](const auto& a, const auto& b) { return a < b; },
50 : 5 : [](const auto& el) { return DerivePriority(el.second.send_statuses); })};
51 : :
52 [ + + ]: 17 : if (it != m_transactions.end()) {
53 : 15 : auto& [tx, state]{*it};
54 [ + - ]: 15 : state.send_statuses.emplace_back(will_send_to_nodeid, will_send_to_address, NodeClock::now());
55 : 15 : return tx;
56 : : }
57 : :
58 : 2 : return std::nullopt;
59 : 17 : }
60 : :
61 : 16 : std::optional<CTransactionRef> PrivateBroadcast::GetTxForNode(const NodeId& nodeid)
62 : : EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
63 : : {
64 : 16 : LOCK(m_mutex);
65 [ + - ]: 16 : const auto tx_and_status{GetSendStatusByNode(nodeid)};
66 [ + + ]: 16 : if (tx_and_status.has_value()) {
67 : 15 : return tx_and_status.value().tx;
68 : : }
69 : 1 : return std::nullopt;
70 : 16 : }
71 : :
72 : 15 : void PrivateBroadcast::NodeConfirmedReception(const NodeId& nodeid)
73 : : EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
74 : : {
75 : 15 : LOCK(m_mutex);
76 [ + - ]: 15 : const auto tx_and_status{GetSendStatusByNode(nodeid)};
77 [ + + ]: 15 : if (tx_and_status.has_value()) {
78 [ - + + - ]: 29 : tx_and_status.value().send_status.confirmed = NodeClock::now();
79 : : }
80 : 15 : }
81 : :
82 : 23 : bool PrivateBroadcast::DidNodeConfirmReception(const NodeId& nodeid)
83 : : EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
84 : : {
85 : 23 : LOCK(m_mutex);
86 [ + - ]: 23 : const auto tx_and_status{GetSendStatusByNode(nodeid)};
87 [ + + ]: 23 : if (tx_and_status.has_value()) {
88 : 17 : return tx_and_status.value().send_status.confirmed.has_value();
89 : : }
90 : : return false;
91 : 23 : }
92 : :
93 : 6 : bool PrivateBroadcast::HavePendingTransactions()
94 : : EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
95 : : {
96 : 6 : LOCK(m_mutex);
97 [ + - ]: 6 : return !m_transactions.empty();
98 : 6 : }
99 : :
100 : 15 : std::vector<CTransactionRef> PrivateBroadcast::GetStale() const
101 : : EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
102 : : {
103 : 15 : LOCK(m_mutex);
104 : 15 : const auto now{NodeClock::now()};
105 : 15 : std::vector<CTransactionRef> stale;
106 [ + + + - ]: 28 : for (const auto& [tx, state] : m_transactions) {
107 [ + - ]: 13 : const Priority p{DerivePriority(state.send_statuses)};
108 [ + + ]: 13 : if (p.num_confirmed == 0) {
109 [ + + + - ]: 9 : if (state.time_added < now - INITIAL_STALE_DURATION) stale.push_back(tx);
110 : : } else {
111 [ + + + - ]: 4 : if (p.last_confirmed < now - STALE_DURATION) stale.push_back(tx);
112 : : }
113 : : }
114 [ + - ]: 15 : return stale;
115 : 15 : }
116 : :
117 : 27 : std::vector<PrivateBroadcast::TxBroadcastInfo> PrivateBroadcast::GetBroadcastInfo() const
118 : : EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
119 : : {
120 : 27 : LOCK(m_mutex);
121 : 27 : std::vector<TxBroadcastInfo> entries;
122 [ + - ]: 27 : entries.reserve(m_transactions.size());
123 : :
124 [ + + - + ]: 130050 : for (const auto& [tx, state] : m_transactions) {
125 : 130023 : std::vector<PeerSendInfo> peers;
126 [ + - - + ]: 130023 : peers.reserve(state.send_statuses.size());
127 [ + + ]: 130059 : for (const auto& status : state.send_statuses) {
128 [ + - ]: 72 : peers.emplace_back(PeerSendInfo{.address = status.address, .sent = status.picked, .received = status.confirmed});
129 : : }
130 [ + - + - ]: 260046 : entries.emplace_back(TxBroadcastInfo{.tx = tx, .time_added = state.time_added, .peers = std::move(peers)});
131 : 130023 : }
132 : :
133 [ + - ]: 27 : return entries;
134 : 27 : }
135 : :
136 : 31 : PrivateBroadcast::Priority PrivateBroadcast::DerivePriority(const std::vector<SendStatus>& sent_to)
137 : : {
138 : 31 : Priority p;
139 [ - + ]: 31 : p.num_picked = sent_to.size();
140 [ + + ]: 66 : for (const auto& send_status : sent_to) {
141 : 35 : p.last_picked = std::max(p.last_picked, send_status.picked);
142 [ + + ]: 35 : if (send_status.confirmed.has_value()) {
143 : 27 : ++p.num_confirmed;
144 : 27 : p.last_confirmed = std::max(p.last_confirmed, send_status.confirmed.value());
145 : : }
146 : : }
147 : 31 : return p;
148 : : }
149 : :
150 : 71 : std::optional<PrivateBroadcast::TxAndSendStatusForNode> PrivateBroadcast::GetSendStatusByNode(const NodeId& nodeid)
151 : : EXCLUSIVE_LOCKS_REQUIRED(m_mutex)
152 : : {
153 : 71 : AssertLockHeld(m_mutex);
154 [ + + ]: 106 : for (auto& [tx, state] : m_transactions) {
155 [ + + ]: 170 : for (auto& send_status : state.send_statuses) {
156 [ + + ]: 135 : if (send_status.nodeid == nodeid) {
157 : 46 : return TxAndSendStatusForNode{.tx = tx, .send_status = send_status};
158 : : }
159 : : }
160 : : }
161 : 25 : return std::nullopt;
162 : : }
|