Bitcoin Core 31.99.0
P2P Digital Currency
txdownloadman_impl.cpp
Go to the documentation of this file.
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
7
8#include <chain.h>
10#include <txmempool.h>
11#include <util/log.h>
12#include <validation.h>
13#include <validationinterface.h>
14
15namespace node {
16// TxDownloadManager wrappers
18 m_impl{std::make_unique<TxDownloadManagerImpl>(options)}
19{}
21
23{
24 m_impl->ActiveTipChange();
25}
26void TxDownloadManager::BlockConnected(const std::shared_ptr<const CBlock>& pblock)
27{
28 m_impl->BlockConnected(pblock);
29}
31{
32 m_impl->BlockDisconnected();
33}
35{
36 m_impl->ConnectedPeer(nodeid, info);
37}
39{
40 m_impl->DisconnectedPeer(nodeid);
41}
42bool TxDownloadManager::AddTxAnnouncement(NodeId peer, const GenTxid& gtxid, std::chrono::microseconds now)
43{
44 return m_impl->AddTxAnnouncement(peer, gtxid, now);
45}
46std::vector<GenTxid> TxDownloadManager::GetRequestsToSend(NodeId nodeid, std::chrono::microseconds current_time)
47{
48 return m_impl->GetRequestsToSend(nodeid, current_time);
49}
50void TxDownloadManager::ReceivedNotFound(NodeId nodeid, const std::vector<GenTxid>& gtxids)
51{
52 m_impl->ReceivedNotFound(nodeid, gtxids);
53}
55{
56 m_impl->MempoolAcceptedTx(tx);
57}
58RejectedTxTodo TxDownloadManager::MempoolRejectedTx(const CTransactionRef& ptx, const TxValidationState& state, NodeId nodeid, bool first_time_failure)
59{
60 return m_impl->MempoolRejectedTx(ptx, state, nodeid, first_time_failure);
61}
63{
64 m_impl->MempoolRejectedPackage(package);
65}
66std::pair<bool, std::optional<PackageToValidate>> TxDownloadManager::ReceivedTx(NodeId nodeid, const CTransactionRef& ptx)
67{
68 return m_impl->ReceivedTx(nodeid, ptx);
69}
71{
72 return m_impl->HaveMoreWork(nodeid);
73}
75{
76 return m_impl->GetTxToReconsider(nodeid);
77}
79{
80 m_impl->CheckIsEmpty();
81}
83{
84 m_impl->CheckIsEmpty(nodeid);
85}
86std::vector<TxOrphanage::OrphanInfo> TxDownloadManager::GetOrphanTransactions() const
87{
88 return m_impl->GetOrphanTransactions();
89}
90
91// TxDownloadManagerImpl
93{
96}
97
98void TxDownloadManagerImpl::BlockConnected(const std::shared_ptr<const CBlock>& pblock)
99{
100 m_orphanage->EraseForBlock(*pblock);
101
102 for (const auto& ptx : pblock->vtx) {
103 // Reconsider potential child transactions.
104 m_orphanage->AddChildrenToWorkSet(*ptx, m_rng);
105
106 RecentConfirmedTransactionsFilter().insert(ptx->GetHash().ToUint256());
107 if (ptx->HasWitness()) {
108 RecentConfirmedTransactionsFilter().insert(ptx->GetWitnessHash().ToUint256());
109 }
110 m_txrequest.ForgetTxHash(ptx->GetHash().ToUint256());
111 m_txrequest.ForgetTxHash(ptx->GetWitnessHash().ToUint256());
112 }
113}
114
116{
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.
126}
127
128bool TxDownloadManagerImpl::AlreadyHaveTx(const GenTxid& gtxid, bool include_reconsiderable)
129{
130 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 if (m_orphanage->HaveTx(Wtxid::FromUint256(hash))) return true;
144
145 if (include_reconsiderable && RecentRejectsReconsiderableFilter().contains(hash)) return true;
146
147 if (RecentConfirmedTransactionsFilter().contains(hash)) return true;
148
149 return RecentRejectsFilter().contains(hash) || std::visit([&](const auto& id) { return m_mempool.exists(id); }, gtxid);
150}
151
153{
154 // If already connected (shouldn't happen in practice), exit early.
155 if (m_peer_info.contains(nodeid)) return;
156
157 m_peer_info.try_emplace(nodeid, info);
158 if (info.m_wtxid_relay) m_num_wtxid_peers += 1;
159}
160
162{
163 m_orphanage->EraseForPeer(nodeid);
165
166 if (auto it = m_peer_info.find(nodeid); it != m_peer_info.end()) {
167 if (it->second.m_connection_info.m_wtxid_relay) m_num_wtxid_peers -= 1;
168 m_peer_info.erase(it);
169 }
170
171}
172
173bool TxDownloadManagerImpl::AddTxAnnouncement(NodeId peer, const GenTxid& gtxid, std::chrono::microseconds now)
174{
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 if (const auto* wtxid = std::get_if<Wtxid>(&gtxid)) {
180 if (auto orphan_tx{m_orphanage->GetTx(*wtxid)}) {
181 auto unique_parents{GetUniqueParents(*orphan_tx)};
182 std::erase_if(unique_parents, [&](const auto& txid) {
183 return AlreadyHaveTx(txid, /*include_reconsiderable=*/false);
184 });
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 if (unique_parents.empty()) {
189 return true;
190 }
191
192 if (MaybeAddOrphanResolutionCandidate(unique_parents, *wtxid, peer, now)) {
193 m_orphanage->AddAnnouncer(orphan_tx->GetWitnessHash(), peer);
194 }
195
196 // Return even if the peer isn't an orphan resolution candidate. This would be caught by AlreadyHaveTx.
197 return true;
198 }
199 }
200
201 // If this is an inv received from a peer and we already have it, we can drop it.
202 if (AlreadyHaveTx(gtxid, /*include_reconsiderable=*/true)) return true;
203
204 auto it = m_peer_info.find(peer);
205 if (it == m_peer_info.end()) return false;
206 const auto& info = it->second.m_connection_info;
207 if (!info.m_relay_permissions && m_txrequest.Count(peer) >= MAX_PEER_TX_ANNOUNCEMENTS) {
208 // Too many queued announcements for this peer
209 return false;
210 }
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 auto delay{0us};
219 if (!info.m_preferred) delay += NONPREF_PEER_TX_DELAY;
220 if (!gtxid.IsWtxid() && m_num_wtxid_peers > 0) delay += TXID_RELAY_DELAY;
221 const bool overloaded = !info.m_relay_permissions && m_txrequest.CountInFlight(peer) >= MAX_PEER_TX_REQUEST_IN_FLIGHT;
222 if (overloaded) delay += OVERLOADED_PEER_TX_DELAY;
223
224 m_txrequest.ReceivedInv(peer, gtxid, info.m_preferred, now + delay);
225
226 return false;
227}
228
229bool TxDownloadManagerImpl::MaybeAddOrphanResolutionCandidate(const std::vector<Txid>& unique_parents, const Wtxid& wtxid, NodeId nodeid, std::chrono::microseconds now)
230{
231 auto it_peer = m_peer_info.find(nodeid);
232 if (it_peer == m_peer_info.end()) return false;
233 if (m_orphanage->HaveTxFromPeer(wtxid, nodeid)) return false;
234
235 const auto& peer_entry = m_peer_info.at(nodeid);
236 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 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 if (m_txrequest.Count(nodeid) + unique_parents.size() > MAX_PEER_TX_ANNOUNCEMENTS) return false;
246 }
247
248 std::chrono::seconds delay{0s};
249 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 if (m_num_wtxid_peers > 0) delay += TXID_RELAY_DELAY;
255 const bool overloaded = !info.m_relay_permissions && m_txrequest.CountInFlight(nodeid) >= MAX_PEER_TX_REQUEST_IN_FLIGHT;
256 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 for (const auto& parent_txid : unique_parents) {
261 m_txrequest.ReceivedInv(nodeid, parent_txid, info.m_preferred, now + delay);
262 }
263 LogDebug(BCLog::TXPACKAGES, "added peer=%d as a candidate for resolving orphan %s\n", nodeid, wtxid.ToString());
264 return true;
265}
266
267std::vector<GenTxid> TxDownloadManagerImpl::GetRequestsToSend(NodeId nodeid, std::chrono::microseconds current_time)
268{
269 std::vector<GenTxid> requests;
270 std::vector<std::pair<NodeId, GenTxid>> expired;
271 auto requestable = m_txrequest.GetRequestable(nodeid, current_time, &expired);
272 for (const auto& [expired_nodeid, gtxid] : expired) {
273 LogDebug(BCLog::NET, "timeout of inflight %s %s from peer=%d\n", gtxid.IsWtxid() ? "wtx" : "tx",
274 gtxid.ToUint256().ToString(), expired_nodeid);
275 }
276 for (const GenTxid& gtxid : requestable) {
277 if (!AlreadyHaveTx(gtxid, /*include_reconsiderable=*/false)) {
278 LogDebug(BCLog::NET, "Requesting %s %s peer=%d\n", gtxid.IsWtxid() ? "wtx" : "tx",
279 gtxid.ToUint256().ToString(), nodeid);
280 requests.emplace_back(gtxid);
281 m_txrequest.RequestedTx(nodeid, gtxid.ToUint256(), current_time + GETDATA_TX_INTERVAL);
282 } 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 m_txrequest.ForgetTxHash(gtxid.ToUint256());
286 }
287 }
288 return requests;
289}
290
291void TxDownloadManagerImpl::ReceivedNotFound(NodeId nodeid, const std::vector<GenTxid>& gtxids)
292{
293 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 m_txrequest.ReceivedResponse(nodeid, gtxid.ToUint256());
297 }
298}
299
300std::optional<PackageToValidate> TxDownloadManagerImpl::Find1P1CPackage(const CTransactionRef& ptx, NodeId nodeid)
301{
302 const auto& parent_wtxid{ptx->GetWitnessHash()};
303
304 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 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 for (const auto& child : cpfp_candidates_same_peer) {
317 Package maybe_cpfp_package{ptx, child};
318 if (!RecentRejectsReconsiderableFilter().contains(GetPackageHash(maybe_cpfp_package)) &&
319 !RecentRejectsFilter().contains(child->GetHash().ToUint256())) {
320 return PackageToValidate{ptx, child, nodeid, nodeid};
321 }
322 }
323 return std::nullopt;
324}
325
327{
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 m_txrequest.ForgetTxHash(tx->GetHash().ToUint256());
331 m_txrequest.ForgetTxHash(tx->GetWitnessHash().ToUint256());
332
333 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 m_orphanage->EraseTx(tx->GetWitnessHash());
336}
337
339{
340 std::vector<Txid> unique_parents;
341 unique_parents.reserve(tx.vin.size());
342 for (const CTxIn& txin : tx.vin) {
343 // We start with all parents, and then remove duplicates below.
344 unique_parents.push_back(txin.prevout.hash);
345 }
346
347 std::sort(unique_parents.begin(), unique_parents.end());
348 unique_parents.erase(std::unique(unique_parents.begin(), unique_parents.end()), unique_parents.end());
349
350 return unique_parents;
351}
352
354{
355 const CTransaction& tx{*ptx};
356 // Results returned to caller
357 // Whether we should call AddToCompactExtraTransactions at the end
358 bool add_extra_compact_tx{first_time_failure};
359 // Hashes to pass to AddKnownTx later
360 std::vector<Txid> unique_parents;
361 // Populated if failure is reconsiderable and eligible package is found.
362 std::optional<node::PackageToValidate> package_to_validate;
363
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 if (first_time_failure && !RecentRejectsFilter().contains(ptx->GetWitnessHash().ToUint256())) {
368 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 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 std::optional<Txid> rejected_parent_reconsiderable;
378 for (const Txid& parent_txid : unique_parents) {
379 if (RecentRejectsFilter().contains(parent_txid.ToUint256())) {
380 fRejectedParents = true;
381 break;
382 } else if (RecentRejectsReconsiderableFilter().contains(parent_txid.ToUint256()) &&
383 !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 if (rejected_parent_reconsiderable.has_value()) {
387 fRejectedParents = true;
388 break;
389 }
390 rejected_parent_reconsiderable = parent_txid;
391 }
392 }
393 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 std::erase_if(unique_parents, [&](const auto& txid) {
398 return AlreadyHaveTx(txid, /*include_reconsiderable=*/false);
399 });
400 const auto now{GetTime<std::chrono::microseconds>()};
401 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 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 std::vector<NodeId> orphan_resolution_candidates{nodeid};
412 m_txrequest.GetCandidatePeers(ptx->GetHash().ToUint256(), orphan_resolution_candidates);
413 if (ptx->HasWitness()) m_txrequest.GetCandidatePeers(ptx->GetWitnessHash().ToUint256(), orphan_resolution_candidates);
414
415 for (const auto& nodeid : orphan_resolution_candidates) {
416 if (MaybeAddOrphanResolutionCandidate(unique_parents, ptx->GetWitnessHash(), nodeid, now)) {
417 m_orphanage->AddTx(ptx, nodeid);
418 }
419 }
420
421 // Once added to the orphan pool, a tx is considered AlreadyHave, and we shouldn't request it anymore.
422 m_txrequest.ForgetTxHash(tx.GetHash().ToUint256());
423 m_txrequest.ForgetTxHash(tx.GetWitnessHash().ToUint256());
424 } else {
425 unique_parents.clear();
426 LogDebug(BCLog::MEMPOOL, "not keeping orphan with rejected parents %s (wtxid=%s)\n",
427 tx.GetHash().ToString(),
428 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 RecentRejectsFilter().insert(tx.GetHash().ToUint256());
436 RecentRejectsFilter().insert(tx.GetWitnessHash().ToUint256());
437 m_txrequest.ForgetTxHash(tx.GetHash().ToUint256());
438 m_txrequest.ForgetTxHash(tx.GetWitnessHash().ToUint256());
439 }
440 }
442 add_extra_compact_tx = false;
443 } 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.
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 RecentRejectsReconsiderableFilter().insert(ptx->GetWitnessHash().ToUint256());
462
463 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 LogDebug(BCLog::TXPACKAGES, "tx %s (wtxid=%s) failed but reconsiderable, looking for child in orphanage\n",
467 ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString());
468 package_to_validate = Find1P1CPackage(ptx, nodeid);
469 }
470 } else {
471 RecentRejectsFilter().insert(ptx->GetWitnessHash().ToUint256());
472 }
473 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 if (state.GetResult() == TxValidationResult::TX_INPUTS_NOT_STANDARD && ptx->HasWitness()) {
485 RecentRejectsFilter().insert(ptx->GetHash().ToUint256());
486 m_txrequest.ForgetTxHash(ptx->GetHash().ToUint256());
487 }
488 }
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 if (state.GetResult() != TxValidationResult::TX_MISSING_INPUTS && m_orphanage->EraseTx(ptx->GetWitnessHash())) {
493 LogDebug(BCLog::TXPACKAGES, " removed orphan tx %s (wtxid=%s)\n", ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString());
494 }
495
496 return RejectedTxTodo{
497 .m_should_add_extra_compact_tx = add_extra_compact_tx,
498 .m_unique_parents = std::move(unique_parents),
499 .m_package_to_validate = std::move(package_to_validate)
500 };
501}
502
504{
506}
507
508std::pair<bool, std::optional<PackageToValidate>> TxDownloadManagerImpl::ReceivedTx(NodeId nodeid, const CTransactionRef& ptx)
509{
510 const Txid& txid = ptx->GetHash();
511 const Wtxid& wtxid = ptx->GetWitnessHash();
512
513 // Mark that we have received a response
514 m_txrequest.ReceivedResponse(nodeid, txid.ToUint256());
515 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 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 return {false, std::nullopt};
547 } 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 LogDebug(BCLog::TXPACKAGES, "found tx %s (wtxid=%s) in reconsiderable rejects, looking for child in orphanage\n",
552 txid.ToString(), wtxid.ToString());
553 return {false, Find1P1CPackage(ptx, nodeid)};
554 }
555
556
557 return {true, std::nullopt};
558}
559
561{
562 return m_orphanage->HaveTxToReconsider(nodeid);
563}
564
566{
567 return m_orphanage->GetTxToReconsider(nodeid);
568}
569
571{
572 assert(m_txrequest.Count(nodeid) == 0);
573 assert(m_orphanage->UsageByPeer(nodeid) == 0);
574}
576{
577 assert(m_orphanage->TotalOrphanUsage() == 0);
578 assert(m_orphanage->CountUniqueOrphans() == 0);
579 assert(m_txrequest.Size() == 0);
581}
582std::vector<TxOrphanage::OrphanInfo> TxDownloadManagerImpl::GetOrphanTransactions() const
583{
584 return m_orphanage->GetOrphanTransactions();
585}
586} // namespace node
#define Assume(val)
Assume is the identity function.
Definition: check.h:128
Txid hash
Definition: transaction.h:31
bool contains(std::span< const unsigned char > vKey) const
Definition: bloom.cpp:226
void insert(std::span< const unsigned char > vKey)
Definition: bloom.cpp:195
The basic transaction that is broadcasted on the network and contained in blocks.
Definition: transaction.h:281
const std::vector< CTxIn > vin
Definition: transaction.h:291
An input of a transaction.
Definition: transaction.h:62
COutPoint prevout
Definition: transaction.h:64
bool exists(const Txid &txid) const
Definition: txmempool.h:513
bool IsWtxid() const
const uint256 & ToUint256() const LIFETIMEBOUND
void ReceivedInv(NodeId peer, const GenTxid &gtxid, bool preferred, std::chrono::microseconds reqtime)
Adds a new CANDIDATE announcement.
Definition: txrequest.cpp:730
size_t CountInFlight(NodeId peer) const
Count how many REQUESTED announcements a peer has.
Definition: txrequest.cpp:718
void GetCandidatePeers(const uint256 &txhash, std::vector< NodeId > &result_peers) const
For some txhash (txid or wtxid), finds all peers with non-COMPLETED announcements and appends them to...
Definition: txrequest.cpp:722
void DisconnectedPeer(NodeId peer)
Deletes all announcements for a given peer.
Definition: txrequest.cpp:717
void ReceivedResponse(NodeId peer, const uint256 &txhash)
Converts a CANDIDATE or REQUESTED announcement to a COMPLETED one.
Definition: txrequest.cpp:741
void RequestedTx(NodeId peer, const uint256 &txhash, std::chrono::microseconds expiry)
Marks a transaction as requested, with a specified expiry.
Definition: txrequest.cpp:736
size_t Count(NodeId peer) const
Count how many announcements a peer has (REQUESTED, CANDIDATE, and COMPLETED combined).
Definition: txrequest.cpp:720
size_t Size() const
Count how many announcements are being tracked in total across all peers and transaction hashes.
Definition: txrequest.cpp:721
std::vector< GenTxid > GetRequestable(NodeId peer, std::chrono::microseconds now, std::vector< std::pair< NodeId, GenTxid > > *expired=nullptr)
Find the txids to request now from peer.
Definition: txrequest.cpp:746
void ForgetTxHash(const uint256 &txhash)
Deletes all announcements for a given txhash (both txid and wtxid ones).
Definition: txrequest.cpp:716
Result GetResult() const
Definition: validation.h:116
const std::unique_ptr< TxDownloadManagerImpl > m_impl
std::vector< GenTxid > GetRequestsToSend(NodeId nodeid, std::chrono::microseconds current_time)
Get getdata requests to send.
void ReceivedNotFound(NodeId nodeid, const std::vector< GenTxid > &gtxids)
Should be called when a notfound for a tx has been received.
std::vector< TxOrphanage::OrphanInfo > GetOrphanTransactions() const
Wrapper for TxOrphanage::GetOrphanTransactions.
std::pair< bool, std::optional< PackageToValidate > > ReceivedTx(NodeId nodeid, const CTransactionRef &ptx)
Marks a tx as ReceivedResponse in txrequest and checks whether AlreadyHaveTx.
bool AddTxAnnouncement(NodeId peer, const GenTxid &gtxid, std::chrono::microseconds now)
Consider adding this tx hash to txrequest.
void BlockConnected(const std::shared_ptr< const CBlock > &pblock)
CTransactionRef GetTxToReconsider(NodeId nodeid)
Returns next orphan tx to consider, or nullptr if none exist.
void CheckIsEmpty() const
Check that all data structures are empty.
void MempoolAcceptedTx(const CTransactionRef &tx)
Respond to successful transaction submission to mempool.
void ConnectedPeer(NodeId nodeid, const TxDownloadConnectionInfo &info)
Creates a new PeerInfo.
void MempoolRejectedPackage(const Package &package)
Respond to package rejected from mempool.
void DisconnectedPeer(NodeId nodeid)
Deletes all txrequest announcements and orphans for a given peer.
RejectedTxTodo MempoolRejectedTx(const CTransactionRef &ptx, const TxValidationState &state, NodeId nodeid, bool first_time_failure)
Respond to transaction rejected from mempool.
TxDownloadManager(const TxDownloadOptions &options)
bool HaveMoreWork(NodeId nodeid) const
Whether there are any orphans to reconsider for this peer.
std::optional< PackageToValidate > Find1P1CPackage(const CTransactionRef &ptx, NodeId nodeid)
Look for a child of this transaction in the orphanage to form a 1-parent-1-child package,...
bool AddTxAnnouncement(NodeId peer, const GenTxid &gtxid, std::chrono::microseconds now)
Consider adding this tx hash to txrequest.
CRollingBloomFilter & RecentConfirmedTransactionsFilter()
std::unique_ptr< TxOrphanage > m_orphanage
Manages unvalidated tx data (orphan transactions for which we are downloading ancestors).
void DisconnectedPeer(NodeId nodeid)
bool MaybeAddOrphanResolutionCandidate(const std::vector< Txid > &unique_parents, const Wtxid &wtxid, NodeId nodeid, std::chrono::microseconds now)
If this peer is an orphan resolution candidate for this transaction, treat the unique_parents as anno...
void ReceivedNotFound(NodeId nodeid, const std::vector< GenTxid > &gtxids)
Marks a tx as ReceivedResponse in txrequest.
TxRequestTracker m_txrequest
Tracks candidates for requesting and downloading transaction data.
std::pair< bool, std::optional< PackageToValidate > > ReceivedTx(NodeId nodeid, const CTransactionRef &ptx)
void MempoolAcceptedTx(const CTransactionRef &tx)
CRollingBloomFilter & RecentRejectsReconsiderableFilter()
RejectedTxTodo MempoolRejectedTx(const CTransactionRef &ptx, const TxValidationState &state, NodeId nodeid, bool first_time_failure)
uint32_t m_num_wtxid_peers
Number of wtxid relay peers we have in m_peer_info.
void ConnectedPeer(NodeId nodeid, const TxDownloadConnectionInfo &info)
bool AlreadyHaveTx(const GenTxid &gtxid, bool include_reconsiderable)
Check whether we already have this gtxid in:
std::map< NodeId, PeerInfo > m_peer_info
Information for all of the peers we may download transactions from.
std::vector< TxOrphanage::OrphanInfo > GetOrphanTransactions() const
std::vector< GenTxid > GetRequestsToSend(NodeId nodeid, std::chrono::microseconds current_time)
Get getdata requests to send.
std::vector< Txid > GetUniqueParents(const CTransaction &tx)
Helper for getting deduplicated vector of Txids in vin.
void BlockConnected(const std::shared_ptr< const CBlock > &pblock)
CTransactionRef GetTxToReconsider(NodeId nodeid)
CRollingBloomFilter & RecentRejectsFilter()
void MempoolRejectedPackage(const Package &package)
std::string ToString() const
const uint256 & ToUint256() const LIFETIMEBOUND
static transaction_identifier FromUint256(const uint256 &id)
256-bit opaque blob.
Definition: uint256.h:196
@ TX_MISSING_INPUTS
transaction was missing some of its inputs
@ TX_INPUTS_NOT_STANDARD
inputs (covered by txid) failed policy rules
@ TX_WITNESS_STRIPPED
Transaction is missing a witness.
@ TX_RECONSIDERABLE
fails some policy, but might be acceptable if submitted in a (different) package
#define LogDebug(category,...)
Definition: log.h:143
@ TXPACKAGES
Definition: categories.h:45
@ MEMPOOL
Definition: categories.h:18
@ NET
Definition: categories.h:16
Definition: messages.h:21
constexpr auto GETDATA_TX_INTERVAL
How long to wait before downloading a transaction from an additional peer.
Definition: txdownloadman.h:38
constexpr int32_t MAX_PEER_TX_ANNOUNCEMENTS
Maximum number of transactions to consider for requesting, per peer.
Definition: txdownloadman.h:30
constexpr int32_t MAX_PEER_TX_REQUEST_IN_FLIGHT
Maximum number of in-flight transaction requests from a peer.
Definition: txdownloadman.h:25
constexpr auto TXID_RELAY_DELAY
How long to delay requesting transactions via txids, if we have wtxid-relaying peers.
Definition: txdownloadman.h:32
constexpr auto OVERLOADED_PEER_TX_DELAY
How long to delay requesting transactions from overloaded peers (see MAX_PEER_TX_REQUEST_IN_FLIGHT).
Definition: txdownloadman.h:36
constexpr auto NONPREF_PEER_TX_DELAY
How long to delay requesting transactions from non-preferred peers.
Definition: txdownloadman.h:34
int64_t NodeId
Definition: net.h:105
uint256 GetPackageHash(const std::vector< CTransactionRef > &transactions)
Get the hash of the concatenated wtxids of transactions, with wtxids treated as a little-endian numbe...
Definition: packages.cpp:151
std::vector< CTransactionRef > Package
A package is an ordered list of transactions.
Definition: packages.h:45
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:403
bool m_should_add_extra_compact_tx
Definition: txdownloadman.h:90
const bool m_wtxid_relay
Whether this peer supports wtxid relay.
Definition: txdownloadman.h:51
assert(!tx.IsCoinBase())