txdownloadman.h raw

   1  // Copyright (c) 2024 The Limenka 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  #ifndef LIMENKA_NODE_TXDOWNLOADMAN_H
   6  #define LIMENKA_NODE_TXDOWNLOADMAN_H
   7  
   8  #include <net.h>
   9  #include <policy/packages.h>
  10  #include <txorphanage.h>
  11  
  12  #include <cstdint>
  13  #include <memory>
  14  
  15  class CBlock;
  16  class CRollingBloomFilter;
  17  class CTxMemPool;
  18  class GenTxid;
  19  class TxRequestTracker;
  20  namespace node {
  21  class TxDownloadManagerImpl;
  22  
  23  /** Maximum number of in-flight transaction requests from a peer. It is not a hard limit, but the threshold at which
  24   *  point the OVERLOADED_PEER_TX_DELAY kicks in. */
  25  static constexpr int32_t MAX_PEER_TX_REQUEST_IN_FLIGHT = 100;
  26  /** Maximum number of transactions to consider for requesting, per peer. It provides a reasonable DoS limit to
  27   *  per-peer memory usage spent on announcements, while covering peers continuously sending INVs at the maximum
  28   *  rate (by our own policy, see INVENTORY_BROADCAST_PER_SECOND) for several minutes, while not receiving
  29   *  the actual transaction (from any peer) in response to requests for them. */
  30  static constexpr int32_t MAX_PEER_TX_ANNOUNCEMENTS = 5000;
  31  /** How long to delay requesting transactions via txids, if we have wtxid-relaying peers */
  32  static constexpr auto TXID_RELAY_DELAY{2s};
  33  /** How long to delay requesting transactions from non-preferred peers */
  34  static constexpr auto NONPREF_PEER_TX_DELAY{2s};
  35  /** How long to delay requesting transactions from overloaded peers (see MAX_PEER_TX_REQUEST_IN_FLIGHT). */
  36  static constexpr auto OVERLOADED_PEER_TX_DELAY{2s};
  37  /** How long to wait before downloading a transaction from an additional peer */
  38  static constexpr auto GETDATA_TX_INTERVAL{60s};
  39  struct TxDownloadOptions {
  40      /** Read-only reference to mempool. */
  41      const CTxMemPool& m_mempool;
  42      /** RNG provided by caller. */
  43      FastRandomContext& m_rng;
  44      /** Maximum number of transactions allowed in orphanage. */
  45      uint32_t m_max_orphan_txs;
  46      /** Instantiate TxRequestTracker as deterministic (used for tests). */
  47      bool m_deterministic_txrequest{false};
  48  };
  49  struct TxDownloadConnectionInfo {
  50      /** Whether this peer is preferred for transaction download. */
  51      const bool m_preferred;
  52      /** Whether this peer has Relay permissions. */
  53      const bool m_relay_permissions;
  54      /** Whether this peer supports wtxid relay. */
  55      const bool m_wtxid_relay;
  56  };
  57  struct PackageToValidate {
  58      Package m_txns;
  59      std::vector<NodeId> m_senders;
  60      /** Construct a 1-parent-1-child package. */
  61      explicit PackageToValidate(const CTransactionRef& parent,
  62                                 const CTransactionRef& child,
  63                                 NodeId parent_sender,
  64                                 NodeId child_sender) :
  65          m_txns{parent, child},
  66          m_senders{parent_sender, child_sender}
  67      {}
  68  
  69      // Move ctor
  70      PackageToValidate(PackageToValidate&& other) : m_txns{std::move(other.m_txns)}, m_senders{std::move(other.m_senders)} {}
  71      // Copy ctor
  72      PackageToValidate(const PackageToValidate& other) = default;
  73  
  74      // Move assignment
  75      PackageToValidate& operator=(PackageToValidate&& other) {
  76          this->m_txns = std::move(other.m_txns);
  77          this->m_senders = std::move(other.m_senders);
  78          return *this;
  79      }
  80  
  81      std::string ToString() const {
  82          Assume(m_txns.size() == 2);
  83          return strprintf("parent %s (wtxid=%s, sender=%d) + child %s (wtxid=%s, sender=%d)",
  84                           m_txns.front()->GetHash().ToString(),
  85                           m_txns.front()->GetWitnessHash().ToString(),
  86                           m_senders.front(),
  87                           m_txns.back()->GetHash().ToString(),
  88                           m_txns.back()->GetWitnessHash().ToString(),
  89                           m_senders.back());
  90      }
  91  };
  92  struct RejectedTxTodo
  93  {
  94      bool m_should_add_extra_compact_tx;
  95      std::vector<Txid> m_unique_parents;
  96      std::optional<PackageToValidate> m_package_to_validate;
  97  };
  98  
  99  
 100  /**
 101   * Class responsible for deciding what transactions to request and, once
 102   * downloaded, whether and how to validate them. It is also responsible for
 103   * deciding what transaction packages to validate and how to resolve orphan
 104   * transactions. Its data structures include TxRequestTracker for scheduling
 105   * requests, rolling bloom filters for remembering transactions that have
 106   * already been {accepted, rejected, confirmed}, an orphanage, and a registry of
 107   * each peer's transaction relay-related information.
 108   *
 109   * Caller needs to interact with TxDownloadManager:
 110   * - ValidationInterface callbacks.
 111   * - When a potential transaction relay peer connects or disconnects.
 112   * - When a transaction or package is accepted or rejected from mempool
 113   * - When a inv, notfound, or tx message is received
 114   * - To get instructions for which getdata messages to send
 115   *
 116   * This class is not thread-safe. Access must be synchronized using an
 117   * external mutex.
 118   */
 119  class TxDownloadManager {
 120      const std::unique_ptr<TxDownloadManagerImpl> m_impl;
 121  
 122  public:
 123      explicit TxDownloadManager(const TxDownloadOptions& options);
 124      ~TxDownloadManager();
 125  
 126      // Responses to chain events. TxDownloadManager is not an actual client of ValidationInterface, these are called through PeerManager.
 127      void ActiveTipChange();
 128      void BlockConnected(const std::shared_ptr<const CBlock>& pblock);
 129      void BlockDisconnected();
 130  
 131      /** Creates a new PeerInfo. Saves the connection info to calculate tx announcement delays later. */
 132      void ConnectedPeer(NodeId nodeid, const TxDownloadConnectionInfo& info);
 133  
 134      /** Deletes all txrequest announcements and orphans for a given peer. */
 135      void DisconnectedPeer(NodeId nodeid);
 136  
 137      /** Consider adding this tx hash to txrequest. Should be called whenever a new inv has been received.
 138       * Also called internally when a transaction is missing parents so that we can request them.
 139       * Returns true if this was a dropped inv (p2p_inv=true and we already have the tx), false otherwise. */
 140      bool AddTxAnnouncement(NodeId peer, const GenTxid& gtxid, std::chrono::microseconds now);
 141  
 142      /** Get getdata requests to send. */
 143      std::vector<GenTxid> GetRequestsToSend(NodeId nodeid, std::chrono::microseconds current_time);
 144  
 145      /** Should be called when a notfound for a tx has been received. */
 146      void ReceivedNotFound(NodeId nodeid, const std::vector<uint256>& txhashes);
 147  
 148      /** Respond to successful transaction submission to mempool */
 149      void MempoolAcceptedTx(const CTransactionRef& tx);
 150  
 151      /** Respond to transaction rejected from mempool */
 152      RejectedTxTodo MempoolRejectedTx(const CTransactionRef& ptx, const TxValidationState& state, NodeId nodeid, bool first_time_failure);
 153  
 154      /** Respond to package rejected from mempool */
 155      void MempoolRejectedPackage(const Package& package);
 156  
 157      /** Marks a tx as ReceivedResponse in txrequest and checks whether AlreadyHaveTx.
 158       * Return a bool indicating whether this tx should be validated. If false, optionally, a
 159       * PackageToValidate. */
 160      std::pair<bool, std::optional<PackageToValidate>> ReceivedTx(NodeId nodeid, const CTransactionRef& ptx);
 161  
 162      /** Whether there are any orphans to reconsider for this peer. */
 163      bool HaveMoreWork(NodeId nodeid) const;
 164  
 165      /** Returns next orphan tx to consider, or nullptr if none exist. */
 166      CTransactionRef GetTxToReconsider(NodeId nodeid);
 167  
 168      /** Check that all data structures are empty. */
 169      void CheckIsEmpty() const;
 170  
 171      /** Check that all data structures that track per-peer information have nothing for this peer. */
 172      void CheckIsEmpty(NodeId nodeid) const;
 173  
 174      /** Wrapper for TxOrphanage::GetOrphanTransactions */
 175      std::vector<TxOrphanage::OrphanTxBase> GetOrphanTransactions() const;
 176  
 177      void SetMaxOrphanTxs(uint32_t max_orphan_txs);
 178  };
 179  } // namespace node
 180  #endif // LIMENKA_NODE_TXDOWNLOADMAN_H
 181