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