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