txdownloadman_impl.cpp raw

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