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