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 : : /// If a transaction is not received back from the network for this duration
11 : : /// after it is broadcast, then we consider it stale / for rebroadcasting.
12 : : static constexpr auto STALE_DURATION{1min};
13 : :
14 : 3 : bool PrivateBroadcast::Add(const CTransactionRef& tx)
15 : : EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
16 : : {
17 : 3 : LOCK(m_mutex);
18 [ + - ]: 3 : const bool inserted{m_transactions.try_emplace(tx).second};
19 [ + - ]: 3 : return inserted;
20 : 3 : }
21 : :
22 : 4 : std::optional<size_t> PrivateBroadcast::Remove(const CTransactionRef& tx)
23 : : EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
24 : : {
25 : 4 : LOCK(m_mutex);
26 : 4 : const auto handle{m_transactions.extract(tx)};
27 [ + + ]: 4 : if (handle) {
28 [ + - ]: 2 : const auto p{DerivePriority(handle.mapped())};
29 : 2 : return p.num_confirmed;
30 : : }
31 : 2 : return std::nullopt;
32 [ + - ]: 8 : }
33 : :
34 : 4 : std::optional<CTransactionRef> PrivateBroadcast::PickTxForSend(const NodeId& will_send_to_nodeid)
35 : : EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
36 : : {
37 : 4 : LOCK(m_mutex);
38 : :
39 : 4 : const auto it{std::ranges::max_element(
40 [ + - ]: 4 : m_transactions,
41 : 2 : [](const auto& a, const auto& b) { return a < b; },
42 : 2 : [](const auto& el) { return DerivePriority(el.second); })};
43 : :
44 [ + + ]: 4 : if (it != m_transactions.end()) {
45 : 2 : auto& [tx, sent_to]{*it};
46 [ + - ]: 2 : sent_to.emplace_back(will_send_to_nodeid, NodeClock::now());
47 : 2 : return tx;
48 : : }
49 : :
50 : 2 : return std::nullopt;
51 : 4 : }
52 : :
53 : 3 : std::optional<CTransactionRef> PrivateBroadcast::GetTxForNode(const NodeId& nodeid)
54 : : EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
55 : : {
56 : 3 : LOCK(m_mutex);
57 [ + - ]: 3 : const auto tx_and_status{GetSendStatusByNode(nodeid)};
58 [ + + ]: 3 : if (tx_and_status.has_value()) {
59 : 2 : return tx_and_status.value().tx;
60 : : }
61 : 1 : return std::nullopt;
62 : 3 : }
63 : :
64 : 2 : void PrivateBroadcast::NodeConfirmedReception(const NodeId& nodeid)
65 : : EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
66 : : {
67 : 2 : LOCK(m_mutex);
68 [ + - ]: 2 : const auto tx_and_status{GetSendStatusByNode(nodeid)};
69 [ + + ]: 2 : if (tx_and_status.has_value()) {
70 [ - + + - ]: 3 : tx_and_status.value().send_status.confirmed = NodeClock::now();
71 : : }
72 : 2 : }
73 : :
74 : 5 : bool PrivateBroadcast::DidNodeConfirmReception(const NodeId& nodeid)
75 : : EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
76 : : {
77 : 5 : LOCK(m_mutex);
78 [ + - ]: 5 : const auto tx_and_status{GetSendStatusByNode(nodeid)};
79 [ + + ]: 5 : if (tx_and_status.has_value()) {
80 : 4 : return tx_and_status.value().send_status.confirmed.has_value();
81 : : }
82 : : return false;
83 : 5 : }
84 : :
85 : 1 : bool PrivateBroadcast::HavePendingTransactions()
86 : : EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
87 : : {
88 : 1 : LOCK(m_mutex);
89 [ + - ]: 1 : return !m_transactions.empty();
90 : 1 : }
91 : :
92 : 5 : std::vector<CTransactionRef> PrivateBroadcast::GetStale() const
93 : : EXCLUSIVE_LOCKS_REQUIRED(!m_mutex)
94 : : {
95 : 5 : LOCK(m_mutex);
96 : 5 : const auto stale_time{NodeClock::now() - STALE_DURATION};
97 : 5 : std::vector<CTransactionRef> stale;
98 [ + + + - ]: 13 : for (const auto& [tx, send_status] : m_transactions) {
99 [ + - ]: 8 : const Priority p{DerivePriority(send_status)};
100 [ + + ]: 8 : if (p.last_confirmed < stale_time) {
101 [ + - ]: 6 : stale.push_back(tx);
102 : : }
103 : : }
104 [ + - ]: 5 : return stale;
105 : 5 : }
106 : :
107 : 14 : PrivateBroadcast::Priority PrivateBroadcast::DerivePriority(const std::vector<SendStatus>& sent_to)
108 : : {
109 : 14 : Priority p;
110 [ - + ]: 14 : p.num_picked = sent_to.size();
111 [ + + ]: 25 : for (const auto& send_status : sent_to) {
112 : 11 : p.last_picked = std::max(p.last_picked, send_status.picked);
113 [ + + ]: 11 : if (send_status.confirmed.has_value()) {
114 : 4 : ++p.num_confirmed;
115 : 4 : p.last_confirmed = std::max(p.last_confirmed, send_status.confirmed.value());
116 : : }
117 : : }
118 : 14 : return p;
119 : : }
120 : :
121 : 10 : std::optional<PrivateBroadcast::TxAndSendStatusForNode> PrivateBroadcast::GetSendStatusByNode(const NodeId& nodeid)
122 : : EXCLUSIVE_LOCKS_REQUIRED(m_mutex)
123 : : {
124 : 10 : AssertLockHeld(m_mutex);
125 [ + + ]: 19 : for (auto& [tx, sent_to] : m_transactions) {
126 [ + + ]: 25 : for (auto& send_status : sent_to) {
127 [ + + ]: 16 : if (send_status.nodeid == nodeid) {
128 : 7 : return TxAndSendStatusForNode{.tx = tx, .send_status = send_status};
129 : : }
130 : : }
131 : : }
132 : 3 : return std::nullopt;
133 : : }
|