Bitcoin Core 28.99.0
P2P Digital Currency
txdownloadman_impl.cpp
Go to the documentation of this file.
1// Copyright (c) 2024
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 <logging.h>
11#include <txmempool.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, bool p2p_inv)
43{
44 return m_impl->AddTxAnnouncement(peer, gtxid, now, p2p_inv);
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<uint256>& txhashes)
51{
52 m_impl->ReceivedNotFound(nodeid, txhashes);
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::OrphanTxBase> 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 RecentConfirmedTransactionsFilter().insert(ptx->GetHash().ToUint256());
104 if (ptx->HasWitness()) {
105 RecentConfirmedTransactionsFilter().insert(ptx->GetWitnessHash().ToUint256());
106 }
107 m_txrequest.ForgetTxHash(ptx->GetHash());
108 m_txrequest.ForgetTxHash(ptx->GetWitnessHash());
109 }
110}
111
113{
114 // To avoid relay problems with transactions that were previously
115 // confirmed, clear our filter of recently confirmed transactions whenever
116 // there's a reorg.
117 // This means that in a 1-block reorg (where 1 block is disconnected and
118 // then another block reconnected), our filter will drop to having only one
119 // block's worth of transactions in it, but that should be fine, since
120 // presumably the most common case of relaying a confirmed transaction
121 // should be just after a new block containing it is found.
123}
124
125bool TxDownloadManagerImpl::AlreadyHaveTx(const GenTxid& gtxid, bool include_reconsiderable)
126{
127 const uint256& hash = gtxid.GetHash();
128
129 if (gtxid.IsWtxid()) {
130 // Normal query by wtxid.
131 if (m_orphanage.HaveTx(Wtxid::FromUint256(hash))) return true;
132 } else {
133 // Never query by txid: it is possible that the transaction in the orphanage has the same
134 // txid but a different witness, which would give us a false positive result. If we decided
135 // not to request the transaction based on this result, an attacker could prevent us from
136 // downloading a transaction by intentionally creating a malleated version of it. While
137 // only one (or none!) of these transactions can ultimately be confirmed, we have no way of
138 // discerning which one that is, so the orphanage can store multiple transactions with the
139 // same txid.
140 //
141 // While we won't query by txid, we can try to "guess" what the wtxid is based on the txid.
142 // A non-segwit transaction's txid == wtxid. Query this txid "casted" to a wtxid. This will
143 // help us find non-segwit transactions, saving bandwidth, and should have no false positives.
144 if (m_orphanage.HaveTx(Wtxid::FromUint256(hash))) return true;
145 }
146
147 if (include_reconsiderable && RecentRejectsReconsiderableFilter().contains(hash)) return true;
148
149 if (RecentConfirmedTransactionsFilter().contains(hash)) return true;
150
151 return RecentRejectsFilter().contains(hash) || m_opts.m_mempool.exists(gtxid);
152}
153
155{
156 // If already connected (shouldn't happen in practice), exit early.
157 if (m_peer_info.contains(nodeid)) return;
158
159 m_peer_info.try_emplace(nodeid, info);
160 if (info.m_wtxid_relay) m_num_wtxid_peers += 1;
161}
162
164{
167
168 if (auto it = m_peer_info.find(nodeid); it != m_peer_info.end()) {
169 if (it->second.m_connection_info.m_wtxid_relay) m_num_wtxid_peers -= 1;
170 m_peer_info.erase(it);
171 }
172
173}
174
175bool TxDownloadManagerImpl::AddTxAnnouncement(NodeId peer, const GenTxid& gtxid, std::chrono::microseconds now, bool p2p_inv)
176{
177 // If this is an inv received from a peer and we already have it, we can drop it.
178 // If this is a request for the parent of an orphan, we don't drop transactions that we already have. In particular,
179 // we *do* want to request parents that are in m_lazy_recent_rejects_reconsiderable, since they can be CPFP'd.
180 if (p2p_inv && AlreadyHaveTx(gtxid, /*include_reconsiderable=*/true)) return true;
181
182 auto it = m_peer_info.find(peer);
183 if (it == m_peer_info.end()) return false;
184 const auto& info = it->second.m_connection_info;
185 if (!info.m_relay_permissions && m_txrequest.Count(peer) >= MAX_PEER_TX_ANNOUNCEMENTS) {
186 // Too many queued announcements for this peer
187 return false;
188 }
189 // Decide the TxRequestTracker parameters for this announcement:
190 // - "preferred": if fPreferredDownload is set (= outbound, or NetPermissionFlags::NoBan permission)
191 // - "reqtime": current time plus delays for:
192 // - NONPREF_PEER_TX_DELAY for announcements from non-preferred connections
193 // - TXID_RELAY_DELAY for txid announcements while wtxid peers are available
194 // - OVERLOADED_PEER_TX_DELAY for announcements from peers which have at least
195 // MAX_PEER_TX_REQUEST_IN_FLIGHT requests in flight (and don't have NetPermissionFlags::Relay).
196 auto delay{0us};
197 if (!info.m_preferred) delay += NONPREF_PEER_TX_DELAY;
198 if (!gtxid.IsWtxid() && m_num_wtxid_peers > 0) delay += TXID_RELAY_DELAY;
199 const bool overloaded = !info.m_relay_permissions && m_txrequest.CountInFlight(peer) >= MAX_PEER_TX_REQUEST_IN_FLIGHT;
200 if (overloaded) delay += OVERLOADED_PEER_TX_DELAY;
201
202 m_txrequest.ReceivedInv(peer, gtxid, info.m_preferred, now + delay);
203
204 return false;
205}
206
207std::vector<GenTxid> TxDownloadManagerImpl::GetRequestsToSend(NodeId nodeid, std::chrono::microseconds current_time)
208{
209 std::vector<GenTxid> requests;
210 std::vector<std::pair<NodeId, GenTxid>> expired;
211 auto requestable = m_txrequest.GetRequestable(nodeid, current_time, &expired);
212 for (const auto& entry : expired) {
213 LogDebug(BCLog::NET, "timeout of inflight %s %s from peer=%d\n", entry.second.IsWtxid() ? "wtx" : "tx",
214 entry.second.GetHash().ToString(), entry.first);
215 }
216 for (const GenTxid& gtxid : requestable) {
217 if (!AlreadyHaveTx(gtxid, /*include_reconsiderable=*/false)) {
218 LogDebug(BCLog::NET, "Requesting %s %s peer=%d\n", gtxid.IsWtxid() ? "wtx" : "tx",
219 gtxid.GetHash().ToString(), nodeid);
220 requests.emplace_back(gtxid);
221 m_txrequest.RequestedTx(nodeid, gtxid.GetHash(), current_time + GETDATA_TX_INTERVAL);
222 } else {
223 // We have already seen this transaction, no need to download. This is just a belt-and-suspenders, as
224 // this should already be called whenever a transaction becomes AlreadyHaveTx().
225 m_txrequest.ForgetTxHash(gtxid.GetHash());
226 }
227 }
228 return requests;
229}
230
231void TxDownloadManagerImpl::ReceivedNotFound(NodeId nodeid, const std::vector<uint256>& txhashes)
232{
233 for (const auto& txhash : txhashes) {
234 // If we receive a NOTFOUND message for a tx we requested, mark the announcement for it as
235 // completed in TxRequestTracker.
236 m_txrequest.ReceivedResponse(nodeid, txhash);
237 }
238}
239
240std::optional<PackageToValidate> TxDownloadManagerImpl::Find1P1CPackage(const CTransactionRef& ptx, NodeId nodeid)
241{
242 const auto& parent_wtxid{ptx->GetWitnessHash()};
243
244 Assume(RecentRejectsReconsiderableFilter().contains(parent_wtxid.ToUint256()));
245
246 // Prefer children from this peer. This helps prevent censorship attempts in which an attacker
247 // sends lots of fake children for the parent, and we (unluckily) keep selecting the fake
248 // children instead of the real one provided by the honest peer.
249 const auto cpfp_candidates_same_peer{m_orphanage.GetChildrenFromSamePeer(ptx, nodeid)};
250
251 // These children should be sorted from newest to oldest. In the (probably uncommon) case
252 // of children that replace each other, this helps us accept the highest feerate (probably the
253 // most recent) one efficiently.
254 for (const auto& child : cpfp_candidates_same_peer) {
255 Package maybe_cpfp_package{ptx, child};
256 if (!RecentRejectsReconsiderableFilter().contains(GetPackageHash(maybe_cpfp_package)) &&
257 !RecentRejectsFilter().contains(child->GetHash().ToUint256())) {
258 return PackageToValidate{ptx, child, nodeid, nodeid};
259 }
260 }
261
262 // If no suitable candidate from the same peer is found, also try children that were provided by
263 // a different peer. This is useful because sometimes multiple peers announce both transactions
264 // to us, and we happen to download them from different peers (we wouldn't have known that these
265 // 2 transactions are related). We still want to find 1p1c packages then.
266 //
267 // If we start tracking all announcers of orphans, we can restrict this logic to parent + child
268 // pairs in which both were provided by the same peer, i.e. delete this step.
269 const auto cpfp_candidates_different_peer{m_orphanage.GetChildrenFromDifferentPeer(ptx, nodeid)};
270
271 // Find the first 1p1c that hasn't already been rejected. We randomize the order to not
272 // create a bias that attackers can use to delay package acceptance.
273 //
274 // Create a random permutation of the indices.
275 std::vector<size_t> tx_indices(cpfp_candidates_different_peer.size());
276 std::iota(tx_indices.begin(), tx_indices.end(), 0);
277 std::shuffle(tx_indices.begin(), tx_indices.end(), m_opts.m_rng);
278
279 for (const auto index : tx_indices) {
280 // If we already tried a package and failed for any reason, the combined hash was
281 // cached in m_lazy_recent_rejects_reconsiderable.
282 const auto [child_tx, child_sender] = cpfp_candidates_different_peer.at(index);
283 Package maybe_cpfp_package{ptx, child_tx};
284 if (!RecentRejectsReconsiderableFilter().contains(GetPackageHash(maybe_cpfp_package)) &&
285 !RecentRejectsFilter().contains(child_tx->GetHash().ToUint256())) {
286 return PackageToValidate{ptx, child_tx, nodeid, child_sender};
287 }
288 }
289 return std::nullopt;
290}
291
293{
294 // As this version of the transaction was acceptable, we can forget about any requests for it.
295 // No-op if the tx is not in txrequest.
296 m_txrequest.ForgetTxHash(tx->GetHash());
297 m_txrequest.ForgetTxHash(tx->GetWitnessHash());
298
300 // If it came from the orphanage, remove it. No-op if the tx is not in txorphanage.
301 m_orphanage.EraseTx(tx->GetWitnessHash());
302}
303
305{
306 const CTransaction& tx{*ptx};
307 // Results returned to caller
308 // Whether we should call AddToCompactExtraTransactions at the end
309 bool add_extra_compact_tx{first_time_failure};
310 // Hashes to pass to AddKnownTx later
311 std::vector<uint256> unique_parents;
312 // Populated if failure is reconsiderable and eligible package is found.
313 std::optional<node::PackageToValidate> package_to_validate;
314
316 // Only process a new orphan if this is a first time failure, as otherwise it must be either
317 // already in orphanage or from 1p1c processing.
318 if (first_time_failure && !RecentRejectsFilter().contains(ptx->GetWitnessHash().ToUint256())) {
319 bool fRejectedParents = false; // It may be the case that the orphans parents have all been rejected
320
321 // Deduplicate parent txids, so that we don't have to loop over
322 // the same parent txid more than once down below.
323 unique_parents.reserve(tx.vin.size());
324 for (const CTxIn& txin : tx.vin) {
325 // We start with all parents, and then remove duplicates below.
326 unique_parents.push_back(txin.prevout.hash);
327 }
328 std::sort(unique_parents.begin(), unique_parents.end());
329 unique_parents.erase(std::unique(unique_parents.begin(), unique_parents.end()), unique_parents.end());
330
331 // Distinguish between parents in m_lazy_recent_rejects and m_lazy_recent_rejects_reconsiderable.
332 // We can tolerate having up to 1 parent in m_lazy_recent_rejects_reconsiderable since we
333 // submit 1p1c packages. However, fail immediately if any are in m_lazy_recent_rejects.
334 std::optional<uint256> rejected_parent_reconsiderable;
335 for (const uint256& parent_txid : unique_parents) {
336 if (RecentRejectsFilter().contains(parent_txid)) {
337 fRejectedParents = true;
338 break;
339 } else if (RecentRejectsReconsiderableFilter().contains(parent_txid) &&
340 !m_opts.m_mempool.exists(GenTxid::Txid(parent_txid))) {
341 // More than 1 parent in m_lazy_recent_rejects_reconsiderable: 1p1c will not be
342 // sufficient to accept this package, so just give up here.
343 if (rejected_parent_reconsiderable.has_value()) {
344 fRejectedParents = true;
345 break;
346 }
347 rejected_parent_reconsiderable = parent_txid;
348 }
349 }
350 if (!fRejectedParents) {
351 const auto current_time{GetTime<std::chrono::microseconds>()};
352
353 for (const uint256& parent_txid : unique_parents) {
354 // Here, we only have the txid (and not wtxid) of the
355 // inputs, so we only request in txid mode, even for
356 // wtxidrelay peers.
357 // Eventually we should replace this with an improved
358 // protocol for getting all unconfirmed parents.
359 const auto gtxid{GenTxid::Txid(parent_txid)};
360 // Exclude m_lazy_recent_rejects_reconsiderable: the missing parent may have been
361 // previously rejected for being too low feerate. This orphan might CPFP it.
362 if (!AlreadyHaveTx(gtxid, /*include_reconsiderable=*/false)) {
363 AddTxAnnouncement(nodeid, gtxid, current_time, /*p2p_inv=*/false);
364 }
365 }
366
367 // Potentially flip add_extra_compact_tx to false if AddTx returns false because the tx was already there
368 add_extra_compact_tx &= m_orphanage.AddTx(ptx, nodeid);
369
370 // Once added to the orphan pool, a tx is considered AlreadyHave, and we shouldn't request it anymore.
371 m_txrequest.ForgetTxHash(tx.GetHash());
372 m_txrequest.ForgetTxHash(tx.GetWitnessHash());
373
374 // DoS prevention: do not allow m_orphanage to grow unbounded (see CVE-2012-3789)
376 } else {
377 unique_parents.clear();
378 LogDebug(BCLog::MEMPOOL, "not keeping orphan with rejected parents %s (wtxid=%s)\n",
379 tx.GetHash().ToString(),
380 tx.GetWitnessHash().ToString());
381 // We will continue to reject this tx since it has rejected
382 // parents so avoid re-requesting it from other peers.
383 // Here we add both the txid and the wtxid, as we know that
384 // regardless of what witness is provided, we will not accept
385 // this, so we don't need to allow for redownload of this txid
386 // from any of our non-wtxidrelay peers.
387 RecentRejectsFilter().insert(tx.GetHash().ToUint256());
388 RecentRejectsFilter().insert(tx.GetWitnessHash().ToUint256());
389 m_txrequest.ForgetTxHash(tx.GetHash());
390 m_txrequest.ForgetTxHash(tx.GetWitnessHash());
391 }
392 }
394 add_extra_compact_tx = false;
395 } else {
396 // We can add the wtxid of this transaction to our reject filter.
397 // Do not add txids of witness transactions or witness-stripped
398 // transactions to the filter, as they can have been malleated;
399 // adding such txids to the reject filter would potentially
400 // interfere with relay of valid transactions from peers that
401 // do not support wtxid-based relay. See
402 // https://github.com/bitcoin/bitcoin/issues/8279 for details.
403 // We can remove this restriction (and always add wtxids to
404 // the filter even for witness stripped transactions) once
405 // wtxid-based relay is broadly deployed.
406 // See also comments in https://github.com/bitcoin/bitcoin/pull/18044#discussion_r443419034
407 // for concerns around weakening security of unupgraded nodes
408 // if we start doing this too early.
410 // If the result is TX_RECONSIDERABLE, add it to m_lazy_recent_rejects_reconsiderable
411 // because we should not download or submit this transaction by itself again, but may
412 // submit it as part of a package later.
413 RecentRejectsReconsiderableFilter().insert(ptx->GetWitnessHash().ToUint256());
414
415 if (first_time_failure) {
416 // When a transaction fails for TX_RECONSIDERABLE, look for a matching child in the
417 // orphanage, as it is possible that they succeed as a package.
418 LogDebug(BCLog::TXPACKAGES, "tx %s (wtxid=%s) failed but reconsiderable, looking for child in orphanage\n",
419 ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString());
420 package_to_validate = Find1P1CPackage(ptx, nodeid);
421 }
422 } else {
423 RecentRejectsFilter().insert(ptx->GetWitnessHash().ToUint256());
424 }
425 m_txrequest.ForgetTxHash(ptx->GetWitnessHash());
426 // If the transaction failed for TX_INPUTS_NOT_STANDARD,
427 // then we know that the witness was irrelevant to the policy
428 // failure, since this check depends only on the txid
429 // (the scriptPubKey being spent is covered by the txid).
430 // Add the txid to the reject filter to prevent repeated
431 // processing of this transaction in the event that child
432 // transactions are later received (resulting in
433 // parent-fetching by txid via the orphan-handling logic).
434 // We only add the txid if it differs from the wtxid, to avoid wasting entries in the
435 // rolling bloom filter.
436 if (state.GetResult() == TxValidationResult::TX_INPUTS_NOT_STANDARD && ptx->HasWitness()) {
437 RecentRejectsFilter().insert(ptx->GetHash().ToUint256());
438 m_txrequest.ForgetTxHash(ptx->GetHash());
439 }
440 }
441
442 // If the tx failed in ProcessOrphanTx, it should be removed from the orphanage unless the
443 // tx was still missing inputs. If the tx was not in the orphanage, EraseTx does nothing and returns 0.
444 if (state.GetResult() != TxValidationResult::TX_MISSING_INPUTS && m_orphanage.EraseTx(ptx->GetWitnessHash()) > 0) {
445 LogDebug(BCLog::TXPACKAGES, " removed orphan tx %s (wtxid=%s)\n", ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString());
446 }
447
448 return RejectedTxTodo{
449 .m_should_add_extra_compact_tx = add_extra_compact_tx,
450 .m_unique_parents = std::move(unique_parents),
451 .m_package_to_validate = std::move(package_to_validate)
452 };
453}
454
456{
458}
459
460std::pair<bool, std::optional<PackageToValidate>> TxDownloadManagerImpl::ReceivedTx(NodeId nodeid, const CTransactionRef& ptx)
461{
462 const uint256& txid = ptx->GetHash();
463 const uint256& wtxid = ptx->GetWitnessHash();
464
465 // Mark that we have received a response
466 m_txrequest.ReceivedResponse(nodeid, txid);
467 if (ptx->HasWitness()) m_txrequest.ReceivedResponse(nodeid, wtxid);
468
469 // First check if we should drop this tx.
470 // We do the AlreadyHaveTx() check using wtxid, rather than txid - in the
471 // absence of witness malleation, this is strictly better, because the
472 // recent rejects filter may contain the wtxid but rarely contains
473 // the txid of a segwit transaction that has been rejected.
474 // In the presence of witness malleation, it's possible that by only
475 // doing the check with wtxid, we could overlook a transaction which
476 // was confirmed with a different witness, or exists in our mempool
477 // with a different witness, but this has limited downside:
478 // mempool validation does its own lookup of whether we have the txid
479 // already; and an adversary can already relay us old transactions
480 // (older than our recency filter) if trying to DoS us, without any need
481 // for witness malleation.
482 if (AlreadyHaveTx(GenTxid::Wtxid(wtxid), /*include_reconsiderable=*/false)) {
483 // If a tx is detected by m_lazy_recent_rejects it is ignored. Because we haven't
484 // submitted the tx to our mempool, we won't have computed a DoS
485 // score for it or determined exactly why we consider it invalid.
486 //
487 // This means we won't penalize any peer subsequently relaying a DoSy
488 // tx (even if we penalized the first peer who gave it to us) because
489 // we have to account for m_lazy_recent_rejects showing false positives. In
490 // other words, we shouldn't penalize a peer if we aren't *sure* they
491 // submitted a DoSy tx.
492 //
493 // Note that m_lazy_recent_rejects doesn't just record DoSy or invalid
494 // transactions, but any tx not accepted by the mempool, which may be
495 // due to node policy (vs. consensus). So we can't blanket penalize a
496 // peer simply for relaying a tx that our m_lazy_recent_rejects has caught,
497 // regardless of false positives.
498 return {false, std::nullopt};
499 } else if (RecentRejectsReconsiderableFilter().contains(wtxid)) {
500 // When a transaction is already in m_lazy_recent_rejects_reconsiderable, we shouldn't submit
501 // it by itself again. However, look for a matching child in the orphanage, as it is
502 // possible that they succeed as a package.
503 LogDebug(BCLog::TXPACKAGES, "found tx %s (wtxid=%s) in reconsiderable rejects, looking for child in orphanage\n",
504 txid.ToString(), wtxid.ToString());
505 return {false, Find1P1CPackage(ptx, nodeid)};
506 }
507
508
509 return {true, std::nullopt};
510}
511
513{
514 return m_orphanage.HaveTxToReconsider(nodeid);
515}
516
518{
519 return m_orphanage.GetTxToReconsider(nodeid);
520}
521
523{
524 assert(m_txrequest.Count(nodeid) == 0);
525}
527{
528 assert(m_orphanage.Size() == 0);
529 assert(m_txrequest.Size() == 0);
531}
532std::vector<TxOrphanage::OrphanTxBase> TxDownloadManagerImpl::GetOrphanTransactions() const
533{
535}
536} // namespace node
#define Assume(val)
Assume is the identity function.
Definition: check.h:97
Txid hash
Definition: transaction.h:31
bool contains(Span< const unsigned char > vKey) const
Definition: bloom.cpp:226
void insert(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:296
An input of a transaction.
Definition: transaction.h:67
COutPoint prevout
Definition: transaction.h:69
bool exists(const GenTxid &gtxid) const
Definition: txmempool.h:647
A generic txid reference (txid or wtxid).
Definition: transaction.h:428
bool IsWtxid() const
Definition: transaction.h:436
static GenTxid Wtxid(const uint256 &hash)
Definition: transaction.h:435
const uint256 & GetHash() const LIFETIMEBOUND
Definition: transaction.h:437
static GenTxid Txid(const uint256 &hash)
Definition: transaction.h:434
bool AddTx(const CTransactionRef &tx, NodeId peer)
Add a new orphan transaction.
Definition: txorphanage.cpp:15
void EraseForPeer(NodeId peer)
Erase all orphans announced by a peer (eg, after that peer disconnects)
Definition: txorphanage.cpp:83
void AddChildrenToWorkSet(const CTransaction &tx)
Add any orphans that list a particular tx as a parent into the from peer's work set.
std::vector< OrphanTxBase > GetOrphanTransactions() const
void LimitOrphans(unsigned int max_orphans, FastRandomContext &rng)
Limit the orphanage to the given maximum.
int EraseTx(const Wtxid &wtxid)
Erase an orphan by wtxid.
Definition: txorphanage.cpp:48
void EraseForBlock(const CBlock &block)
Erase all orphans included in or invalidated by a new block.
std::vector< std::pair< CTransactionRef, NodeId > > GetChildrenFromDifferentPeer(const CTransactionRef &parent, NodeId nodeid) const
Get all children that spend from this tx but were not received from nodeid.
size_t Size() const
Return how many entries exist in the orphange.
Definition: txorphanage.h:70
std::vector< CTransactionRef > GetChildrenFromSamePeer(const CTransactionRef &parent, NodeId nodeid) const
Get all children that spend from this tx and were received from nodeid.
bool HaveTx(const Wtxid &wtxid) const
Check if we already have an orphan transaction (by wtxid only)
bool HaveTxToReconsider(NodeId peer)
Does this peer have any work to do?
CTransactionRef GetTxToReconsider(NodeId peer)
Extract a transaction from a peer's work set Returns nullptr if there are no transactions to work on.
void ReceivedInv(NodeId peer, const GenTxid &gtxid, bool preferred, std::chrono::microseconds reqtime)
Adds a new CANDIDATE announcement.
Definition: txrequest.cpp:731
size_t CountInFlight(NodeId peer) const
Count how many REQUESTED announcements a peer has.
Definition: txrequest.cpp:720
void DisconnectedPeer(NodeId peer)
Deletes all announcements for a given peer.
Definition: txrequest.cpp:719
void ReceivedResponse(NodeId peer, const uint256 &txhash)
Converts a CANDIDATE or REQUESTED announcement to a COMPLETED one.
Definition: txrequest.cpp:742
void RequestedTx(NodeId peer, const uint256 &txhash, std::chrono::microseconds expiry)
Marks a transaction as requested, with a specified expiry.
Definition: txrequest.cpp:737
size_t Count(NodeId peer) const
Count how many announcements a peer has (REQUESTED, CANDIDATE, and COMPLETED combined).
Definition: txrequest.cpp:722
size_t Size() const
Count how many announcements are being tracked in total across all peers and transaction hashes.
Definition: txrequest.cpp:723
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:747
void ForgetTxHash(const uint256 &txhash)
Deletes all announcements for a given txhash (both txid and wtxid ones).
Definition: txrequest.cpp:718
Result GetResult() const
Definition: validation.h:109
std::string ToString() const
Definition: uint256.cpp:47
std::vector< TxOrphanage::OrphanTxBase > GetOrphanTransactions() const
Wrapper for TxOrphanage::GetOrphanTransactions.
const std::unique_ptr< TxDownloadManagerImpl > m_impl
std::vector< GenTxid > GetRequestsToSend(NodeId nodeid, std::chrono::microseconds current_time)
Get getdata requests to send.
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, bool p2p_inv)
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)
void ReceivedNotFound(NodeId nodeid, const std::vector< uint256 > &txhashes)
Should be called when a notfound for a tx has been received.
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,...
CRollingBloomFilter & RecentConfirmedTransactionsFilter()
bool AddTxAnnouncement(NodeId peer, const GenTxid &gtxid, std::chrono::microseconds now, bool p2p_inv)
Consider adding this tx hash to txrequest.
void ReceivedNotFound(NodeId nodeid, const std::vector< uint256 > &txhashes)
Marks a tx as ReceivedResponse in txrequest.
void DisconnectedPeer(NodeId nodeid)
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)
std::vector< TxOrphanage::OrphanTxBase > GetOrphanTransactions() const
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.
TxOrphanage m_orphanage
Manages unvalidated tx data (orphan transactions for which we are downloading ancestors).
std::vector< GenTxid > GetRequestsToSend(NodeId nodeid, std::chrono::microseconds current_time)
Get getdata requests to send.
void BlockConnected(const std::shared_ptr< const CBlock > &pblock)
CTransactionRef GetTxToReconsider(NodeId nodeid)
CRollingBloomFilter & RecentRejectsFilter()
void MempoolRejectedPackage(const Package &package)
static transaction_identifier FromUint256(const uint256 &id)
256-bit opaque blob.
Definition: uint256.h:190
@ 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: logging.h:280
@ TXPACKAGES
Definition: logging.h:73
@ MEMPOOL
Definition: logging.h:45
@ NET
Definition: logging.h:43
Definition: messages.h:20
static constexpr auto GETDATA_TX_INTERVAL
How long to wait before downloading a transaction from an additional peer.
Definition: txdownloadman.h:38
static constexpr int32_t MAX_PEER_TX_ANNOUNCEMENTS
Maximum number of transactions to consider for requesting, per peer.
Definition: txdownloadman.h:30
static constexpr int32_t MAX_PEER_TX_REQUEST_IN_FLIGHT
Maximum number of in-flight transaction requests from a peer.
Definition: txdownloadman.h:25
static constexpr auto TXID_RELAY_DELAY
How long to delay requesting transactions via txids, if we have wtxid-relaying peers.
Definition: txdownloadman.h:32
static 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
static 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:97
uint256 GetPackageHash(const std::vector< CTransactionRef > &transactions)
Get the hash of these transactions' wtxids, concatenated in lexicographical order (treating the wtxid...
Definition: packages.cpp:151
std::vector< CTransactionRef > Package
A package is an ordered list of transactions.
Definition: packages.h:50
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:423
bool m_should_add_extra_compact_tx
Definition: txdownloadman.h:94
const bool m_wtxid_relay
Whether this peer supports wtxid relay.
Definition: txdownloadman.h:55
FastRandomContext & m_rng
RNG provided by caller.
Definition: txdownloadman.h:43
const uint32_t m_max_orphan_txs
Maximum number of transactions allowed in orphanage.
Definition: txdownloadman.h:45
const CTxMemPool & m_mempool
Read-only reference to mempool.
Definition: txdownloadman.h:41
assert(!tx.IsCoinBase())