/tmp/bitcoin/src/node/txdownloadman_impl.cpp
Line | Count | Source |
1 | | // Copyright (c) 2024-present The Bitcoin Core developers |
2 | | // Distributed under the MIT software license, see the accompanying |
3 | | // file COPYING or http://www.opensource.org/licenses/mit-license.php. |
4 | | |
5 | | #include <node/txdownloadman_impl.h> |
6 | | #include <node/txdownloadman.h> |
7 | | |
8 | | #include <chain.h> |
9 | | #include <consensus/validation.h> |
10 | | #include <txmempool.h> |
11 | | #include <util/log.h> |
12 | | #include <validation.h> |
13 | | #include <validationinterface.h> |
14 | | |
15 | | namespace node { |
16 | | // TxDownloadManager wrappers |
17 | | TxDownloadManager::TxDownloadManager(const TxDownloadOptions& options) : |
18 | 1.26k | m_impl{std::make_unique<TxDownloadManagerImpl>(options)} |
19 | 1.26k | {} |
20 | 1.26k | TxDownloadManager::~TxDownloadManager() = default; |
21 | | |
22 | | void TxDownloadManager::ActiveTipChange() |
23 | 74.7k | { |
24 | 74.7k | m_impl->ActiveTipChange(); |
25 | 74.7k | } |
26 | | void TxDownloadManager::BlockConnected(const std::shared_ptr<const CBlock>& pblock) |
27 | 79.2k | { |
28 | 79.2k | m_impl->BlockConnected(pblock); |
29 | 79.2k | } |
30 | | void TxDownloadManager::BlockDisconnected() |
31 | 9.54k | { |
32 | 9.54k | m_impl->BlockDisconnected(); |
33 | 9.54k | } |
34 | | void TxDownloadManager::ConnectedPeer(NodeId nodeid, const TxDownloadConnectionInfo& info) |
35 | 1.61k | { |
36 | 1.61k | m_impl->ConnectedPeer(nodeid, info); |
37 | 1.61k | } |
38 | | void TxDownloadManager::DisconnectedPeer(NodeId nodeid) |
39 | 1.78k | { |
40 | 1.78k | m_impl->DisconnectedPeer(nodeid); |
41 | 1.78k | } |
42 | | bool TxDownloadManager::AddTxAnnouncement(NodeId peer, const GenTxid& gtxid, std::chrono::microseconds now) |
43 | 27.3k | { |
44 | 27.3k | return m_impl->AddTxAnnouncement(peer, gtxid, now); |
45 | 27.3k | } |
46 | | std::vector<GenTxid> TxDownloadManager::GetRequestsToSend(NodeId nodeid, std::chrono::microseconds current_time) |
47 | 338k | { |
48 | 338k | return m_impl->GetRequestsToSend(nodeid, current_time); |
49 | 338k | } |
50 | | void TxDownloadManager::ReceivedNotFound(NodeId nodeid, const std::vector<GenTxid>& gtxids) |
51 | 8 | { |
52 | 8 | m_impl->ReceivedNotFound(nodeid, gtxids); |
53 | 8 | } |
54 | | void TxDownloadManager::MempoolAcceptedTx(const CTransactionRef& tx) |
55 | 12.0k | { |
56 | 12.0k | m_impl->MempoolAcceptedTx(tx); |
57 | 12.0k | } |
58 | | RejectedTxTodo TxDownloadManager::MempoolRejectedTx(const CTransactionRef& ptx, const TxValidationState& state, NodeId nodeid, bool first_time_failure) |
59 | 843 | { |
60 | 843 | return m_impl->MempoolRejectedTx(ptx, state, nodeid, first_time_failure); |
61 | 843 | } |
62 | | void TxDownloadManager::MempoolRejectedPackage(const Package& package) |
63 | 3 | { |
64 | 3 | m_impl->MempoolRejectedPackage(package); |
65 | 3 | } |
66 | | std::pair<bool, std::optional<PackageToValidate>> TxDownloadManager::ReceivedTx(NodeId nodeid, const CTransactionRef& ptx) |
67 | 16.4k | { |
68 | 16.4k | return m_impl->ReceivedTx(nodeid, ptx); |
69 | 16.4k | } |
70 | | bool TxDownloadManager::HaveMoreWork(NodeId nodeid) const |
71 | 138k | { |
72 | 138k | return m_impl->HaveMoreWork(nodeid); |
73 | 138k | } |
74 | | CTransactionRef TxDownloadManager::GetTxToReconsider(NodeId nodeid) |
75 | 342k | { |
76 | 342k | return m_impl->GetTxToReconsider(nodeid); |
77 | 342k | } |
78 | | void TxDownloadManager::CheckIsEmpty() const |
79 | 917 | { |
80 | 917 | m_impl->CheckIsEmpty(); |
81 | 917 | } |
82 | | void TxDownloadManager::CheckIsEmpty(NodeId nodeid) const |
83 | 1.78k | { |
84 | 1.78k | m_impl->CheckIsEmpty(nodeid); |
85 | 1.78k | } |
86 | | std::vector<TxOrphanage::OrphanInfo> TxDownloadManager::GetOrphanTransactions() const |
87 | 228 | { |
88 | 228 | return m_impl->GetOrphanTransactions(); |
89 | 228 | } |
90 | | |
91 | | // TxDownloadManagerImpl |
92 | | void TxDownloadManagerImpl::ActiveTipChange() |
93 | 74.7k | { |
94 | 74.7k | RecentRejectsFilter().reset(); |
95 | 74.7k | RecentRejectsReconsiderableFilter().reset(); |
96 | 74.7k | } |
97 | | |
98 | | void TxDownloadManagerImpl::BlockConnected(const std::shared_ptr<const CBlock>& pblock) |
99 | 79.2k | { |
100 | 79.2k | m_orphanage->EraseForBlock(*pblock); |
101 | | |
102 | 125k | for (const auto& ptx : pblock->vtx) { |
103 | | // Reconsider potential child transactions. |
104 | 125k | m_orphanage->AddChildrenToWorkSet(*ptx, m_rng); |
105 | | |
106 | 125k | RecentConfirmedTransactionsFilter().insert(ptx->GetHash().ToUint256()); |
107 | 125k | if (ptx->HasWitness()) { |
108 | 97.3k | RecentConfirmedTransactionsFilter().insert(ptx->GetWitnessHash().ToUint256()); |
109 | 97.3k | } |
110 | 125k | m_txrequest.ForgetTxHash(ptx->GetHash().ToUint256()); |
111 | 125k | m_txrequest.ForgetTxHash(ptx->GetWitnessHash().ToUint256()); |
112 | 125k | } |
113 | 79.2k | } |
114 | | |
115 | | void TxDownloadManagerImpl::BlockDisconnected() |
116 | 9.54k | { |
117 | | // To avoid relay problems with transactions that were previously |
118 | | // confirmed, clear our filter of recently confirmed transactions whenever |
119 | | // there's a reorg. |
120 | | // This means that in a 1-block reorg (where 1 block is disconnected and |
121 | | // then another block reconnected), our filter will drop to having only one |
122 | | // block's worth of transactions in it, but that should be fine, since |
123 | | // presumably the most common case of relaying a confirmed transaction |
124 | | // should be just after a new block containing it is found. |
125 | 9.54k | RecentConfirmedTransactionsFilter().reset(); |
126 | 9.54k | } |
127 | | |
128 | | bool TxDownloadManagerImpl::AlreadyHaveTx(const GenTxid& gtxid, bool include_reconsiderable) |
129 | 67.6k | { |
130 | 67.6k | const uint256& hash = gtxid.ToUint256(); |
131 | | |
132 | | // Never query by txid: it is possible that the transaction in the orphanage has the same |
133 | | // txid but a different witness, which would give us a false positive result. If we decided |
134 | | // not to request the transaction based on this result, an attacker could prevent us from |
135 | | // downloading a transaction by intentionally creating a malleated version of it. While |
136 | | // only one (or none!) of these transactions can ultimately be confirmed, we have no way of |
137 | | // discerning which one that is, so the orphanage can store multiple transactions with the |
138 | | // same txid. |
139 | | // |
140 | | // While we won't query by txid, we can try to "guess" what the wtxid is based on the txid. |
141 | | // A non-segwit transaction's txid == wtxid. Query this txhash "casted" to a wtxid. This will |
142 | | // help us find non-segwit transactions, saving bandwidth, and should have no false positives. |
143 | 67.6k | if (m_orphanage->HaveTx(Wtxid::FromUint256(hash))) return true; |
144 | | |
145 | 64.6k | if (include_reconsiderable && RecentRejectsReconsiderableFilter().contains(hash)) return true; |
146 | | |
147 | 64.6k | if (RecentConfirmedTransactionsFilter().contains(hash)) return true; |
148 | | |
149 | 64.5k | return RecentRejectsFilter().contains(hash) || std::visit([&](const auto& id) { return m_mempool.exists(id); }, gtxid);txdownloadman_impl.cpp:_ZZN4node21TxDownloadManagerImpl13AlreadyHaveTxERK7GenTxidbENK3$_0clI22transaction_identifierILb0EEEEDaRKT_ Line | Count | Source | 149 | 975 | return RecentRejectsFilter().contains(hash) || std::visit([&](const auto& id) { return m_mempool.exists(id); }, gtxid); |
txdownloadman_impl.cpp:_ZZN4node21TxDownloadManagerImpl13AlreadyHaveTxERK7GenTxidbENK3$_0clI22transaction_identifierILb1EEEEDaRKT_ Line | Count | Source | 149 | 63.4k | return RecentRejectsFilter().contains(hash) || std::visit([&](const auto& id) { return m_mempool.exists(id); }, gtxid); |
|
150 | 64.6k | } |
151 | | |
152 | | void TxDownloadManagerImpl::ConnectedPeer(NodeId nodeid, const TxDownloadConnectionInfo& info) |
153 | 1.68k | { |
154 | | // If already connected (shouldn't happen in practice), exit early. |
155 | 1.68k | if (m_peer_info.contains(nodeid)) return; |
156 | | |
157 | 1.68k | m_peer_info.try_emplace(nodeid, info); |
158 | 1.68k | if (info.m_wtxid_relay) m_num_wtxid_peers += 1; |
159 | 1.68k | } |
160 | | |
161 | | void TxDownloadManagerImpl::DisconnectedPeer(NodeId nodeid) |
162 | 1.78k | { |
163 | 1.78k | m_orphanage->EraseForPeer(nodeid); |
164 | 1.78k | m_txrequest.DisconnectedPeer(nodeid); |
165 | | |
166 | 1.78k | if (auto it = m_peer_info.find(nodeid); it != m_peer_info.end()) { |
167 | 1.61k | if (it->second.m_connection_info.m_wtxid_relay) m_num_wtxid_peers -= 1; |
168 | 1.61k | m_peer_info.erase(it); |
169 | 1.61k | } |
170 | | |
171 | 1.78k | } |
172 | | |
173 | | bool TxDownloadManagerImpl::AddTxAnnouncement(NodeId peer, const GenTxid& gtxid, std::chrono::microseconds now) |
174 | 27.4k | { |
175 | | // If this is an orphan we are trying to resolve, consider this peer as a orphan resolution candidate instead. |
176 | | // - is wtxid matching something in orphanage |
177 | | // - exists in orphanage |
178 | | // - peer can be an orphan resolution candidate |
179 | 27.4k | if (const auto* wtxid = std::get_if<Wtxid>(>xid)) { |
180 | 27.3k | if (auto orphan_tx{m_orphanage->GetTx(*wtxid)}) { |
181 | 7 | auto unique_parents{GetUniqueParents(*orphan_tx)}; |
182 | 8 | std::erase_if(unique_parents, [&](const auto& txid) { |
183 | 8 | return AlreadyHaveTx(txid, /*include_reconsiderable=*/false); |
184 | 8 | }); |
185 | | |
186 | | // The missing parents may have all been rejected or accepted since the orphan was added to the orphanage. |
187 | | // Do not delete from the orphanage, as it may be queued for processing. |
188 | 7 | if (unique_parents.empty()) { |
189 | 0 | return true; |
190 | 0 | } |
191 | | |
192 | 7 | if (MaybeAddOrphanResolutionCandidate(unique_parents, *wtxid, peer, now)) { |
193 | 3 | m_orphanage->AddAnnouncer(orphan_tx->GetWitnessHash(), peer); |
194 | 3 | } |
195 | | |
196 | | // Return even if the peer isn't an orphan resolution candidate. This would be caught by AlreadyHaveTx. |
197 | 7 | return true; |
198 | 7 | } |
199 | 27.3k | } |
200 | | |
201 | | // If this is an inv received from a peer and we already have it, we can drop it. |
202 | 27.4k | if (AlreadyHaveTx(gtxid, /*include_reconsiderable=*/true)) return true; |
203 | | |
204 | 23.6k | auto it = m_peer_info.find(peer); |
205 | 23.6k | if (it == m_peer_info.end()) return false; |
206 | 23.6k | const auto& info = it->second.m_connection_info; |
207 | 23.6k | if (!info.m_relay_permissions && m_txrequest.Count(peer) >= MAX_PEER_TX_ANNOUNCEMENTS) { |
208 | | // Too many queued announcements for this peer |
209 | 1 | return false; |
210 | 1 | } |
211 | | // Decide the TxRequestTracker parameters for this announcement: |
212 | | // - "preferred": if fPreferredDownload is set (= outbound, or NetPermissionFlags::NoBan permission) |
213 | | // - "reqtime": current time plus delays for: |
214 | | // - NONPREF_PEER_TX_DELAY for announcements from non-preferred connections |
215 | | // - TXID_RELAY_DELAY for txid announcements while wtxid peers are available |
216 | | // - OVERLOADED_PEER_TX_DELAY for announcements from peers which have at least |
217 | | // MAX_PEER_TX_REQUEST_IN_FLIGHT requests in flight (and don't have NetPermissionFlags::Relay). |
218 | 23.6k | auto delay{0us}; |
219 | 23.6k | if (!info.m_preferred) delay += NONPREF_PEER_TX_DELAY; |
220 | 23.6k | if (!gtxid.IsWtxid() && m_num_wtxid_peers > 0) delay += TXID_RELAY_DELAY; |
221 | 23.6k | const bool overloaded = !info.m_relay_permissions && m_txrequest.CountInFlight(peer) >= MAX_PEER_TX_REQUEST_IN_FLIGHT; |
222 | 23.6k | if (overloaded) delay += OVERLOADED_PEER_TX_DELAY; |
223 | | |
224 | 23.6k | m_txrequest.ReceivedInv(peer, gtxid, info.m_preferred, now + delay); |
225 | | |
226 | 23.6k | return false; |
227 | 23.6k | } |
228 | | |
229 | | bool TxDownloadManagerImpl::MaybeAddOrphanResolutionCandidate(const std::vector<Txid>& unique_parents, const Wtxid& wtxid, NodeId nodeid, std::chrono::microseconds now) |
230 | 679 | { |
231 | 679 | auto it_peer = m_peer_info.find(nodeid); |
232 | 679 | if (it_peer == m_peer_info.end()) return false; |
233 | 679 | if (m_orphanage->HaveTxFromPeer(wtxid, nodeid)) return false; |
234 | | |
235 | 675 | const auto& peer_entry = m_peer_info.at(nodeid); |
236 | 675 | const auto& info = peer_entry.m_connection_info; |
237 | | |
238 | | // TODO: add delays and limits based on the amount of orphan resolution we are already doing |
239 | | // with this peer, how much they are using the orphanage, etc. |
240 | 675 | if (!info.m_relay_permissions) { |
241 | | // This mirrors the delaying and dropping behavior in AddTxAnnouncement in order to preserve |
242 | | // existing behavior: drop if we are tracking too many invs for this peer already. Each |
243 | | // orphan resolution involves at least 1 transaction request which may or may not be |
244 | | // currently tracked in m_txrequest, so we include that in the count. |
245 | 675 | if (m_txrequest.Count(nodeid) + unique_parents.size() > MAX_PEER_TX_ANNOUNCEMENTS) return false; |
246 | 675 | } |
247 | | |
248 | 675 | std::chrono::seconds delay{0s}; |
249 | 675 | if (!info.m_preferred) delay += NONPREF_PEER_TX_DELAY; |
250 | | // The orphan wtxid is used, but resolution entails requesting the parents by txid. Sometimes |
251 | | // parent and child are announced and thus requested around the same time, and we happen to |
252 | | // receive child sooner. Waiting a few seconds may allow us to cancel the orphan resolution |
253 | | // request if the parent arrives in that time. |
254 | 675 | if (m_num_wtxid_peers > 0) delay += TXID_RELAY_DELAY; |
255 | 675 | const bool overloaded = !info.m_relay_permissions && m_txrequest.CountInFlight(nodeid) >= MAX_PEER_TX_REQUEST_IN_FLIGHT; |
256 | 675 | if (overloaded) delay += OVERLOADED_PEER_TX_DELAY; |
257 | | |
258 | | // Treat finding orphan resolution candidate as equivalent to the peer announcing all missing parents. |
259 | | // In the future, orphan resolution may include more explicit steps |
260 | 694 | for (const auto& parent_txid : unique_parents) { |
261 | 694 | m_txrequest.ReceivedInv(nodeid, parent_txid, info.m_preferred, now + delay); |
262 | 694 | } |
263 | 675 | LogDebug(BCLog::TXPACKAGES, "added peer=%d as a candidate for resolving orphan %s\n", nodeid, wtxid.ToString()); |
264 | 675 | return true; |
265 | 675 | } |
266 | | |
267 | | std::vector<GenTxid> TxDownloadManagerImpl::GetRequestsToSend(NodeId nodeid, std::chrono::microseconds current_time) |
268 | 338k | { |
269 | 338k | std::vector<GenTxid> requests; |
270 | 338k | std::vector<std::pair<NodeId, GenTxid>> expired; |
271 | 338k | auto requestable = m_txrequest.GetRequestable(nodeid, current_time, &expired); |
272 | 338k | for (const auto& [expired_nodeid, gtxid] : expired) { |
273 | 28 | LogDebug(BCLog::NET, "timeout of inflight %s %s from peer=%d\n", gtxid.IsWtxid() ? "wtx" : "tx", |
274 | 28 | gtxid.ToUint256().ToString(), expired_nodeid); |
275 | 28 | } |
276 | 338k | for (const GenTxid& gtxid : requestable) { |
277 | 23.0k | if (!AlreadyHaveTx(gtxid, /*include_reconsiderable=*/false)) { |
278 | 22.9k | LogDebug(BCLog::NET, "Requesting %s %s peer=%d\n", gtxid.IsWtxid() ? "wtx" : "tx", |
279 | 22.9k | gtxid.ToUint256().ToString(), nodeid); |
280 | 22.9k | requests.emplace_back(gtxid); |
281 | 22.9k | m_txrequest.RequestedTx(nodeid, gtxid.ToUint256(), current_time + GETDATA_TX_INTERVAL); |
282 | 22.9k | } else { |
283 | | // We have already seen this transaction, no need to download. This is just a belt-and-suspenders, as |
284 | | // this should already be called whenever a transaction becomes AlreadyHaveTx(). |
285 | 63 | m_txrequest.ForgetTxHash(gtxid.ToUint256()); |
286 | 63 | } |
287 | 23.0k | } |
288 | 338k | return requests; |
289 | 338k | } |
290 | | |
291 | | void TxDownloadManagerImpl::ReceivedNotFound(NodeId nodeid, const std::vector<GenTxid>& gtxids) |
292 | 8 | { |
293 | 8 | for (const auto& gtxid : gtxids) { |
294 | | // If we receive a NOTFOUND message for a tx we requested, mark the announcement for it as |
295 | | // completed in TxRequestTracker. |
296 | 8 | m_txrequest.ReceivedResponse(nodeid, gtxid.ToUint256()); |
297 | 8 | } |
298 | 8 | } |
299 | | |
300 | | std::optional<PackageToValidate> TxDownloadManagerImpl::Find1P1CPackage(const CTransactionRef& ptx, NodeId nodeid) |
301 | 52 | { |
302 | 52 | const auto& parent_wtxid{ptx->GetWitnessHash()}; |
303 | | |
304 | 52 | Assume(RecentRejectsReconsiderableFilter().contains(parent_wtxid.ToUint256())); |
305 | | |
306 | | // Only consider children from this peer. This helps prevent censorship attempts in which an attacker |
307 | | // sends lots of fake children for the parent, and we (unluckily) keep selecting the fake |
308 | | // children instead of the real one provided by the honest peer. Since we track all announcers |
309 | | // of an orphan, this does not exclude parent + orphan pairs that we happened to request from |
310 | | // different peers. |
311 | 52 | const auto cpfp_candidates_same_peer{m_orphanage->GetChildrenFromSamePeer(ptx, nodeid)}; |
312 | | |
313 | | // These children should be sorted from newest to oldest. In the (probably uncommon) case |
314 | | // of children that replace each other, this helps us accept the highest feerate (probably the |
315 | | // most recent) one efficiently. |
316 | 52 | for (const auto& child : cpfp_candidates_same_peer) { |
317 | 30 | Package maybe_cpfp_package{ptx, child}; |
318 | 30 | if (!RecentRejectsReconsiderableFilter().contains(GetPackageHash(maybe_cpfp_package)) && |
319 | 30 | !RecentRejectsFilter().contains(child->GetHash().ToUint256())) { |
320 | 30 | return PackageToValidate{ptx, child, nodeid, nodeid}; |
321 | 30 | } |
322 | 30 | } |
323 | 22 | return std::nullopt; |
324 | 52 | } |
325 | | |
326 | | void TxDownloadManagerImpl::MempoolAcceptedTx(const CTransactionRef& tx) |
327 | 12.0k | { |
328 | | // As this version of the transaction was acceptable, we can forget about any requests for it. |
329 | | // No-op if the tx is not in txrequest. |
330 | 12.0k | m_txrequest.ForgetTxHash(tx->GetHash().ToUint256()); |
331 | 12.0k | m_txrequest.ForgetTxHash(tx->GetWitnessHash().ToUint256()); |
332 | | |
333 | 12.0k | m_orphanage->AddChildrenToWorkSet(*tx, m_rng); |
334 | | // If it came from the orphanage, remove it. No-op if the tx is not in txorphanage. |
335 | 12.0k | m_orphanage->EraseTx(tx->GetWitnessHash()); |
336 | 12.0k | } |
337 | | |
338 | | std::vector<Txid> TxDownloadManagerImpl::GetUniqueParents(const CTransaction& tx) |
339 | 714 | { |
340 | 714 | std::vector<Txid> unique_parents; |
341 | 714 | unique_parents.reserve(tx.vin.size()); |
342 | 836 | for (const CTxIn& txin : tx.vin) { |
343 | | // We start with all parents, and then remove duplicates below. |
344 | 836 | unique_parents.push_back(txin.prevout.hash); |
345 | 836 | } |
346 | | |
347 | 714 | std::sort(unique_parents.begin(), unique_parents.end()); |
348 | 714 | unique_parents.erase(std::unique(unique_parents.begin(), unique_parents.end()), unique_parents.end()); |
349 | | |
350 | 714 | return unique_parents; |
351 | 714 | } |
352 | | |
353 | | node::RejectedTxTodo TxDownloadManagerImpl::MempoolRejectedTx(const CTransactionRef& ptx, const TxValidationState& state, NodeId nodeid, bool first_time_failure) |
354 | 960 | { |
355 | 960 | const CTransaction& tx{*ptx}; |
356 | | // Results returned to caller |
357 | | // Whether we should call AddToCompactExtraTransactions at the end |
358 | 960 | bool add_extra_compact_tx{first_time_failure}; |
359 | | // Hashes to pass to AddKnownTx later |
360 | 960 | std::vector<Txid> unique_parents; |
361 | | // Populated if failure is reconsiderable and eligible package is found. |
362 | 960 | std::optional<node::PackageToValidate> package_to_validate; |
363 | | |
364 | 960 | if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) { |
365 | | // Only process a new orphan if this is a first time failure, as otherwise it must be either |
366 | | // already in orphanage or from 1p1c processing. |
367 | 707 | if (first_time_failure && !RecentRejectsFilter().contains(ptx->GetWitnessHash().ToUint256())) { |
368 | 707 | bool fRejectedParents = false; // It may be the case that the orphans parents have all been rejected |
369 | | |
370 | | // Deduplicate parent txids, so that we don't have to loop over |
371 | | // the same parent txid more than once down below. |
372 | 707 | unique_parents = GetUniqueParents(tx); |
373 | | |
374 | | // Distinguish between parents in m_lazy_recent_rejects and m_lazy_recent_rejects_reconsiderable. |
375 | | // We can tolerate having up to 1 parent in m_lazy_recent_rejects_reconsiderable since we |
376 | | // submit 1p1c packages. However, fail immediately if any are in m_lazy_recent_rejects. |
377 | 707 | std::optional<Txid> rejected_parent_reconsiderable; |
378 | 805 | for (const Txid& parent_txid : unique_parents) { |
379 | 805 | if (RecentRejectsFilter().contains(parent_txid.ToUint256())) { |
380 | 36 | fRejectedParents = true; |
381 | 36 | break; |
382 | 769 | } else if (RecentRejectsReconsiderableFilter().contains(parent_txid.ToUint256()) && |
383 | 769 | !m_mempool.exists(parent_txid)) { |
384 | | // More than 1 parent in m_lazy_recent_rejects_reconsiderable: 1p1c will not be |
385 | | // sufficient to accept this package, so just give up here. |
386 | 16 | if (rejected_parent_reconsiderable.has_value()) { |
387 | 2 | fRejectedParents = true; |
388 | 2 | break; |
389 | 2 | } |
390 | 14 | rejected_parent_reconsiderable = parent_txid; |
391 | 14 | } |
392 | 805 | } |
393 | 707 | if (!fRejectedParents) { |
394 | | // Filter parents that we already have. |
395 | | // Exclude m_lazy_recent_rejects_reconsiderable: the missing parent may have been |
396 | | // previously rejected for being too low feerate. This orphan might CPFP it. |
397 | 732 | std::erase_if(unique_parents, [&](const auto& txid) { |
398 | 732 | return AlreadyHaveTx(txid, /*include_reconsiderable=*/false); |
399 | 732 | }); |
400 | 669 | const auto now{GetTime<std::chrono::microseconds>()}; |
401 | 669 | const auto& wtxid = ptx->GetWitnessHash(); |
402 | | // Potentially flip add_extra_compact_tx to false if tx is already in orphanage, which |
403 | | // means it was already added to vExtraTxnForCompact. |
404 | 669 | add_extra_compact_tx &= !m_orphanage->HaveTx(wtxid); |
405 | | |
406 | | // If there is no candidate for orphan resolution, AddTx will not be called. This means |
407 | | // that if a peer is overloading us with invs and orphans, they will eventually not be |
408 | | // able to add any more transactions to the orphanage. |
409 | | // |
410 | | // Search by txid and, if the tx has a witness, wtxid |
411 | 669 | std::vector<NodeId> orphan_resolution_candidates{nodeid}; |
412 | 669 | m_txrequest.GetCandidatePeers(ptx->GetHash().ToUint256(), orphan_resolution_candidates); |
413 | 669 | if (ptx->HasWitness()) m_txrequest.GetCandidatePeers(ptx->GetWitnessHash().ToUint256(), orphan_resolution_candidates); |
414 | | |
415 | 672 | for (const auto& nodeid : orphan_resolution_candidates) { |
416 | 672 | if (MaybeAddOrphanResolutionCandidate(unique_parents, ptx->GetWitnessHash(), nodeid, now)) { |
417 | 672 | m_orphanage->AddTx(ptx, nodeid); |
418 | 672 | } |
419 | 672 | } |
420 | | |
421 | | // Once added to the orphan pool, a tx is considered AlreadyHave, and we shouldn't request it anymore. |
422 | 669 | m_txrequest.ForgetTxHash(tx.GetHash().ToUint256()); |
423 | 669 | m_txrequest.ForgetTxHash(tx.GetWitnessHash().ToUint256()); |
424 | 669 | } else { |
425 | 38 | unique_parents.clear(); |
426 | 38 | LogDebug(BCLog::MEMPOOL, "not keeping orphan with rejected parents %s (wtxid=%s)\n", |
427 | 38 | tx.GetHash().ToString(), |
428 | 38 | tx.GetWitnessHash().ToString()); |
429 | | // We will continue to reject this tx since it has rejected |
430 | | // parents so avoid re-requesting it from other peers. |
431 | | // Here we add both the txid and the wtxid, as we know that |
432 | | // regardless of what witness is provided, we will not accept |
433 | | // this, so we don't need to allow for redownload of this txid |
434 | | // from any of our non-wtxidrelay peers. |
435 | 38 | RecentRejectsFilter().insert(tx.GetHash().ToUint256()); |
436 | 38 | RecentRejectsFilter().insert(tx.GetWitnessHash().ToUint256()); |
437 | 38 | m_txrequest.ForgetTxHash(tx.GetHash().ToUint256()); |
438 | 38 | m_txrequest.ForgetTxHash(tx.GetWitnessHash().ToUint256()); |
439 | 38 | } |
440 | 707 | } |
441 | 707 | } else if (state.GetResult() == TxValidationResult::TX_WITNESS_STRIPPED) { |
442 | 9 | add_extra_compact_tx = false; |
443 | 244 | } else { |
444 | | // We can add the wtxid of this transaction to our reject filter. |
445 | | // Do not add txids of witness transactions or witness-stripped |
446 | | // transactions to the filter, as they can have been malleated; |
447 | | // adding such txids to the reject filter would potentially |
448 | | // interfere with relay of valid transactions from peers that |
449 | | // do not support wtxid-based relay. See |
450 | | // https://github.com/bitcoin/bitcoin/issues/8279 for details. |
451 | | // We can remove this restriction (and always add wtxids to |
452 | | // the filter even for witness stripped transactions) once |
453 | | // wtxid-based relay is broadly deployed. |
454 | | // See also comments in https://github.com/bitcoin/bitcoin/pull/18044#discussion_r443419034 |
455 | | // for concerns around weakening security of unupgraded nodes |
456 | | // if we start doing this too early. |
457 | 244 | if (state.GetResult() == TxValidationResult::TX_RECONSIDERABLE) { |
458 | | // If the result is TX_RECONSIDERABLE, add it to m_lazy_recent_rejects_reconsiderable |
459 | | // because we should not download or submit this transaction by itself again, but may |
460 | | // submit it as part of a package later. |
461 | 44 | RecentRejectsReconsiderableFilter().insert(ptx->GetWitnessHash().ToUint256()); |
462 | | |
463 | 44 | if (first_time_failure) { |
464 | | // When a transaction fails for TX_RECONSIDERABLE, look for a matching child in the |
465 | | // orphanage, as it is possible that they succeed as a package. |
466 | 37 | LogDebug(BCLog::TXPACKAGES, "tx %s (wtxid=%s) failed but reconsiderable, looking for child in orphanage\n", |
467 | 37 | ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString()); |
468 | 37 | package_to_validate = Find1P1CPackage(ptx, nodeid); |
469 | 37 | } |
470 | 200 | } else { |
471 | 200 | RecentRejectsFilter().insert(ptx->GetWitnessHash().ToUint256()); |
472 | 200 | } |
473 | 244 | m_txrequest.ForgetTxHash(ptx->GetWitnessHash().ToUint256()); |
474 | | // If the transaction failed for TX_INPUTS_NOT_STANDARD, |
475 | | // then we know that the witness was irrelevant to the policy |
476 | | // failure, since this check depends only on the txid |
477 | | // (the scriptPubKey being spent is covered by the txid). |
478 | | // Add the txid to the reject filter to prevent repeated |
479 | | // processing of this transaction in the event that child |
480 | | // transactions are later received (resulting in |
481 | | // parent-fetching by txid via the orphan-handling logic). |
482 | | // We only add the txid if it differs from the wtxid, to avoid wasting entries in the |
483 | | // rolling bloom filter. |
484 | 244 | if (state.GetResult() == TxValidationResult::TX_INPUTS_NOT_STANDARD && ptx->HasWitness()) { |
485 | 3 | RecentRejectsFilter().insert(ptx->GetHash().ToUint256()); |
486 | 3 | m_txrequest.ForgetTxHash(ptx->GetHash().ToUint256()); |
487 | 3 | } |
488 | 244 | } |
489 | | |
490 | | // If the tx failed in ProcessOrphanTx, it should be removed from the orphanage unless the |
491 | | // tx was still missing inputs. If the tx was not in the orphanage, EraseTx does nothing and returns 0. |
492 | 960 | if (state.GetResult() != TxValidationResult::TX_MISSING_INPUTS && m_orphanage->EraseTx(ptx->GetWitnessHash())) { |
493 | 10 | LogDebug(BCLog::TXPACKAGES, " removed orphan tx %s (wtxid=%s)\n", ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString()); |
494 | 10 | } |
495 | | |
496 | 960 | return RejectedTxTodo{ |
497 | 960 | .m_should_add_extra_compact_tx = add_extra_compact_tx, |
498 | 960 | .m_unique_parents = std::move(unique_parents), |
499 | 960 | .m_package_to_validate = std::move(package_to_validate) |
500 | 960 | }; |
501 | 960 | } |
502 | | |
503 | | void TxDownloadManagerImpl::MempoolRejectedPackage(const Package& package) |
504 | 3 | { |
505 | 3 | RecentRejectsReconsiderableFilter().insert(GetPackageHash(package)); |
506 | 3 | } |
507 | | |
508 | | std::pair<bool, std::optional<PackageToValidate>> TxDownloadManagerImpl::ReceivedTx(NodeId nodeid, const CTransactionRef& ptx) |
509 | 16.4k | { |
510 | 16.4k | const Txid& txid = ptx->GetHash(); |
511 | 16.4k | const Wtxid& wtxid = ptx->GetWitnessHash(); |
512 | | |
513 | | // Mark that we have received a response |
514 | 16.4k | m_txrequest.ReceivedResponse(nodeid, txid.ToUint256()); |
515 | 16.4k | if (ptx->HasWitness()) m_txrequest.ReceivedResponse(nodeid, wtxid.ToUint256()); |
516 | | |
517 | | // First check if we should drop this tx. |
518 | | // We do the AlreadyHaveTx() check using wtxid, rather than txid - in the |
519 | | // absence of witness malleation, this is strictly better, because the |
520 | | // recent rejects filter may contain the wtxid but rarely contains |
521 | | // the txid of a segwit transaction that has been rejected. |
522 | | // In the presence of witness malleation, it's possible that by only |
523 | | // doing the check with wtxid, we could overlook a transaction which |
524 | | // was confirmed with a different witness, or exists in our mempool |
525 | | // with a different witness, but this has limited downside: |
526 | | // mempool validation does its own lookup of whether we have the txid |
527 | | // already; and an adversary can already relay us old transactions |
528 | | // (older than our recency filter) if trying to DoS us, without any need |
529 | | // for witness malleation. |
530 | 16.4k | if (AlreadyHaveTx(wtxid, /*include_reconsiderable=*/false)) { |
531 | | // If a tx is detected by m_lazy_recent_rejects it is ignored. Because we haven't |
532 | | // submitted the tx to our mempool, we won't have computed a DoS |
533 | | // score for it or determined exactly why we consider it invalid. |
534 | | // |
535 | | // This means we won't penalize any peer subsequently relaying a DoSy |
536 | | // tx (even if we penalized the first peer who gave it to us) because |
537 | | // we have to account for m_lazy_recent_rejects showing false positives. In |
538 | | // other words, we shouldn't penalize a peer if we aren't *sure* they |
539 | | // submitted a DoSy tx. |
540 | | // |
541 | | // Note that m_lazy_recent_rejects doesn't just record DoSy or invalid |
542 | | // transactions, but any tx not accepted by the mempool, which may be |
543 | | // due to node policy (vs. consensus). So we can't blanket penalize a |
544 | | // peer simply for relaying a tx that our m_lazy_recent_rejects has caught, |
545 | | // regardless of false positives. |
546 | 3.66k | return {false, std::nullopt}; |
547 | 12.7k | } else if (RecentRejectsReconsiderableFilter().contains(wtxid.ToUint256())) { |
548 | | // When a transaction is already in m_lazy_recent_rejects_reconsiderable, we shouldn't submit |
549 | | // it by itself again. However, look for a matching child in the orphanage, as it is |
550 | | // possible that they succeed as a package. |
551 | 15 | LogDebug(BCLog::TXPACKAGES, "found tx %s (wtxid=%s) in reconsiderable rejects, looking for child in orphanage\n", |
552 | 15 | txid.ToString(), wtxid.ToString()); |
553 | 15 | return {false, Find1P1CPackage(ptx, nodeid)}; |
554 | 15 | } |
555 | | |
556 | | |
557 | 12.7k | return {true, std::nullopt}; |
558 | 16.4k | } |
559 | | |
560 | | bool TxDownloadManagerImpl::HaveMoreWork(NodeId nodeid) |
561 | 138k | { |
562 | 138k | return m_orphanage->HaveTxToReconsider(nodeid); |
563 | 138k | } |
564 | | |
565 | | CTransactionRef TxDownloadManagerImpl::GetTxToReconsider(NodeId nodeid) |
566 | 342k | { |
567 | 342k | return m_orphanage->GetTxToReconsider(nodeid); |
568 | 342k | } |
569 | | |
570 | | void TxDownloadManagerImpl::CheckIsEmpty(NodeId nodeid) |
571 | 1.78k | { |
572 | 1.78k | assert(m_txrequest.Count(nodeid) == 0); |
573 | 1.78k | assert(m_orphanage->UsageByPeer(nodeid) == 0); |
574 | 1.78k | } |
575 | | void TxDownloadManagerImpl::CheckIsEmpty() |
576 | 917 | { |
577 | 917 | assert(m_orphanage->TotalOrphanUsage() == 0); |
578 | 917 | assert(m_orphanage->CountUniqueOrphans() == 0); |
579 | 917 | assert(m_txrequest.Size() == 0); |
580 | 917 | assert(m_num_wtxid_peers == 0); |
581 | 917 | } |
582 | | std::vector<TxOrphanage::OrphanInfo> TxDownloadManagerImpl::GetOrphanTransactions() const |
583 | 228 | { |
584 | 228 | return m_orphanage->GetOrphanTransactions(); |
585 | 228 | } |
586 | | } // namespace node |