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 : : #include <ranges>
11 : :
12 : :
13 : 21781 : PrivateBroadcast::AddResult PrivateBroadcast::Add(const CTransactionRef& tx)
14 : : EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
15 : : {
16 : 21781 : LOCK(m_mutex);
17 [ + + ]: 21781 : if (const auto it{m_transactions.find(tx)}; it != m_transactions.end()) {
18 [ + - + + ]: 6885 : if (IsPending(it->second)) return AddResult::AlreadyPresent;
19 : :
20 : : // An exhausted transaction can be explicitly retried by adding it again.
21 : 1475 : it->second.time_added = NodeClock::now();
22 : 1475 : it->second.send_statuses.clear();
23 : 1475 : return AddResult::Added;
24 : : }
25 : :
26 [ + + ]: 14896 : if (m_transactions.size() >= m_max_transactions) return AddResult::QueueFull;
27 : :
28 [ + - ]: 12499 : m_transactions.try_emplace(tx);
29 : : return AddResult::Added;
30 : 21781 : }
31 : :
32 : 162596 : std::optional<size_t> PrivateBroadcast::Remove(const CTransactionRef& tx)
33 : : EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
34 : : {
35 : 162596 : LOCK(m_mutex);
36 : 162596 : const auto handle{m_transactions.extract(tx)};
37 [ + + ]: 162596 : if (handle) {
38 [ + - ]: 7503 : const auto p{DerivePriority(handle.mapped().send_statuses)};
39 : 7503 : return p.num_confirmed;
40 : : }
41 : 155093 : return std::nullopt;
42 [ + - ]: 325192 : }
43 : :
44 : 55423 : std::optional<CTransactionRef> PrivateBroadcast::PickTxForSend(const NodeId& will_send_to_nodeid, const CService& will_send_to_address)
45 : : EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
46 : : {
47 : 55423 : LOCK(m_mutex);
48 : :
49 [ + - - + ]: 55423 : if (GetSendStatusByNode(will_send_to_nodeid).has_value()) { // nodeid reuse, shouldn't send >1 tx to a given node
50 : 0 : Assume(false);
51 : : return std::nullopt;
52 : : }
53 : :
54 [ + - ]: 216360 : auto pending_transactions{m_transactions | std::views::filter([this](const auto& entry) { return IsPending(entry.second); })};
55 [ + - ]: 55423 : const auto it{std::ranges::max_element(
56 : : pending_transactions,
57 : 67095 : [](const auto& a, const auto& b) { return a < b; },
58 : 67095 : [](const auto& el) { return DerivePriority(el.second.send_statuses); })};
59 : :
60 [ + + ]: 55423 : if (it != pending_transactions.end()) {
61 : 24290 : auto& [tx, state]{*it};
62 [ + - ]: 24290 : state.send_statuses.emplace_back(will_send_to_nodeid, will_send_to_address, NodeClock::now());
63 : 24290 : return tx;
64 : : }
65 : :
66 : 31133 : return std::nullopt;
67 : 55423 : }
68 : :
69 : 37892 : std::optional<CTransactionRef> PrivateBroadcast::GetTxForNode(const NodeId& nodeid)
70 : : EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
71 : : {
72 : 37892 : LOCK(m_mutex);
73 [ + - ]: 37892 : const auto tx_and_status{GetSendStatusByNode(nodeid)};
74 [ + + ]: 37892 : if (tx_and_status.has_value()) {
75 : 1533 : return tx_and_status.value().tx;
76 : : }
77 : 36359 : return std::nullopt;
78 : 37892 : }
79 : :
80 : 11119 : void PrivateBroadcast::NodeConfirmedReception(const NodeId& nodeid)
81 : : EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
82 : : {
83 : 11119 : LOCK(m_mutex);
84 [ + - ]: 11119 : const auto tx_and_status{GetSendStatusByNode(nodeid)};
85 [ + + ]: 11119 : if (tx_and_status.has_value()) {
86 [ + + + - ]: 14264 : tx_and_status.value().send_status.confirmed = NodeClock::now();
87 : : }
88 : 11119 : }
89 : :
90 : 71390 : bool PrivateBroadcast::DidNodeConfirmReception(const NodeId& nodeid)
91 : : EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
92 : : {
93 : 71390 : LOCK(m_mutex);
94 [ + - ]: 71390 : const auto tx_and_status{GetSendStatusByNode(nodeid)};
95 [ + + ]: 71390 : if (tx_and_status.has_value()) {
96 : 2947 : return tx_and_status.value().send_status.confirmed.has_value();
97 : : }
98 : : return false;
99 : 71390 : }
100 : :
101 : 11893 : bool PrivateBroadcast::HavePendingTransactions()
102 : : EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
103 : : {
104 : 11893 : LOCK(m_mutex);
105 [ + - + - ]: 30752 : return std::ranges::any_of(m_transactions, [this](const auto& entry) { return IsPending(entry.second); });
106 : 11893 : }
107 : :
108 : 15147 : std::vector<CTransactionRef> PrivateBroadcast::GetStale() const
109 : : EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
110 : : {
111 : 15147 : LOCK(m_mutex);
112 : 15147 : const auto now{NodeClock::now()};
113 : 15147 : std::vector<CTransactionRef> stale;
114 [ + + + - ]: 99570 : for (const auto& [tx, state] : m_transactions) {
115 [ + + + - ]: 84423 : if (!IsPending(state)) continue;
116 [ + - ]: 62592 : const Priority p{DerivePriority(state.send_statuses)};
117 [ + + ]: 62592 : if (p.num_confirmed == 0) {
118 [ + + + - ]: 51630 : if (state.time_added < now - INITIAL_STALE_DURATION) stale.push_back(tx);
119 : : } else {
120 [ + + + - ]: 10962 : if (p.last_confirmed < now - STALE_DURATION) stale.push_back(tx);
121 : : }
122 : : }
123 [ + - ]: 15147 : return stale;
124 : 15147 : }
125 : :
126 : 2229 : std::vector<PrivateBroadcast::TxBroadcastInfo> PrivateBroadcast::GetBroadcastInfo() const
127 : : EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
128 : : {
129 : 2229 : LOCK(m_mutex);
130 : 2229 : std::vector<TxBroadcastInfo> entries;
131 [ + - ]: 2229 : entries.reserve(m_transactions.size());
132 : :
133 [ + + - + ]: 9230 : for (const auto& [tx, state] : m_transactions) {
134 : 7001 : std::vector<PeerSendInfo> peers;
135 [ + - - + ]: 7001 : peers.reserve(state.send_statuses.size());
136 [ + + ]: 24902 : for (const auto& status : state.send_statuses) {
137 [ + - ]: 35802 : peers.emplace_back(PeerSendInfo{.address = status.address, .sent = status.picked, .received = status.confirmed});
138 : : }
139 [ - + + - ]: 7001 : const size_t attempts_remaining{m_max_send_attempts - std::min(state.send_statuses.size(), m_max_send_attempts)};
140 [ + - + - ]: 14002 : entries.emplace_back(TxBroadcastInfo{.tx = tx, .time_added = state.time_added, .attempts_remaining = attempts_remaining, .peers = std::move(peers)});
141 : 7001 : }
142 : :
143 [ + - ]: 2229 : return entries;
144 : 2229 : }
145 : :
146 : 271104 : bool PrivateBroadcast::IsPending(const TxSendStatus& status) const
147 : : {
148 [ - + ]: 271104 : return status.send_statuses.size() < m_max_send_attempts;
149 : : }
150 : :
151 : 204285 : PrivateBroadcast::Priority PrivateBroadcast::DerivePriority(const std::vector<SendStatus>& sent_to)
152 : : {
153 : 204285 : Priority p;
154 [ - + ]: 204285 : p.num_picked = sent_to.size();
155 [ + + ]: 876568 : for (const auto& send_status : sent_to) {
156 : 672283 : p.last_picked = std::max(p.last_picked, send_status.picked);
157 [ + + ]: 672283 : if (send_status.confirmed.has_value()) {
158 : 59200 : ++p.num_confirmed;
159 : 59200 : p.last_confirmed = std::max(p.last_confirmed, send_status.confirmed.value());
160 : : }
161 : : }
162 : 204285 : return p;
163 : : }
164 : :
165 : 175824 : std::optional<PrivateBroadcast::TxAndSendStatusForNode> PrivateBroadcast::GetSendStatusByNode(const NodeId& nodeid)
166 : : EXCLUSIVE_LOCKS_REQUIRED(m_mutex)
167 : : {
168 : 175824 : AssertLockHeld(m_mutex);
169 [ + + ]: 664053 : for (auto& [tx, state] : m_transactions) {
170 [ + + ]: 3070747 : for (auto& send_status : state.send_statuses) {
171 [ + + ]: 2582518 : if (send_status.nodeid == nodeid) {
172 : 7625 : return TxAndSendStatusForNode{.tx = tx, .send_status = send_status};
173 : : }
174 : : }
175 : : }
176 : 168199 : return std::nullopt;
177 : : }
|