txorphanage.h raw

   1  // Copyright (c) 2021-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  #ifndef BITCOIN_NODE_TXORPHANAGE_H
   6  #define BITCOIN_NODE_TXORPHANAGE_H
   7  
   8  #include <consensus/validation.h>
   9  #include <net.h>
  10  #include <primitives/block.h>
  11  #include <primitives/transaction.h>
  12  #include <sync.h>
  13  #include <util/time.h>
  14  
  15  #include <map>
  16  #include <set>
  17  
  18  namespace node {
  19  /** Default value for TxOrphanage::m_reserved_usage_per_peer. Helps limit the total amount of memory used by the orphanage. */
  20  static constexpr int64_t DEFAULT_RESERVED_ORPHAN_WEIGHT_PER_PEER{404'000};
  21  /** Default value for TxOrphanage::m_max_global_latency_score. Helps limit the maximum latency for operations like
  22   * EraseForBlock and LimitOrphans. */
  23  static constexpr unsigned int DEFAULT_MAX_ORPHANAGE_LATENCY_SCORE{3000};
  24  
  25  /** A class to track orphan transactions (failed on TX_MISSING_INPUTS)
  26   * Since we cannot distinguish orphans from bad transactions with non-existent inputs, we heavily limit the amount of
  27   * announcements (unique (NodeId, wtxid) pairs), the number of inputs, and size of the orphans stored (both individual
  28   * and summed). We also try to prevent adversaries from churning this data structure: once global limits are reached, we
  29   * continuously evict the oldest announcement (sorting non-reconsiderable orphans before reconsiderable ones) from the
  30   * most resource-intensive peer until we are back within limits.
  31   * - Peers can exceed their individual limits (e.g. because they are very useful transaction relay peers) as long as the
  32   *   global limits are not exceeded.
  33   * - As long as the orphan has 1 announcer, it remains in the orphanage.
  34   * - No peer can trigger the eviction of another peer's orphans.
  35   * - Peers' orphans are effectively protected from eviction as long as they don't exceed their limits.
  36   * Not thread-safe. Requires external synchronization.
  37   */
  38  class TxOrphanage {
  39  public:
  40      using Usage = int64_t;
  41      using Count = unsigned int;
  42  
  43      /** Allows providing orphan information externally */
  44      struct OrphanInfo {
  45          CTransactionRef tx;
  46          /** Peers added with AddTx or AddAnnouncer. */
  47          std::set<NodeId> announcers;
  48  
  49          // Constructor with moved announcers
  50          OrphanInfo(CTransactionRef tx, std::set<NodeId>&& announcers) :
  51              tx(std::move(tx)),
  52              announcers(std::move(announcers))
  53          {}
  54      };
  55  
  56      virtual ~TxOrphanage() = default;
  57  
  58      /** Add a new orphan transaction */
  59      virtual bool AddTx(const CTransactionRef& tx, NodeId peer) = 0;
  60  
  61      /** Add an additional announcer to an orphan if it exists. Otherwise, do nothing. */
  62      virtual bool AddAnnouncer(const Wtxid& wtxid, NodeId peer) = 0;
  63  
  64      /** Get a transaction by its witness txid */
  65      virtual CTransactionRef GetTx(const Wtxid& wtxid) const = 0;
  66  
  67      /** Check if we already have an orphan transaction (by wtxid only) */
  68      virtual bool HaveTx(const Wtxid& wtxid) const = 0;
  69  
  70      /** Check if a {tx, peer} exists in the orphanage.*/
  71      virtual bool HaveTxFromPeer(const Wtxid& wtxid, NodeId peer) const = 0;
  72  
  73      /** Extract a transaction from a peer's work set, and flip it back to non-reconsiderable.
  74       *  Returns nullptr if there are no transactions to work on.
  75       *  Otherwise returns the transaction reference, and removes
  76       *  it from the work set.
  77       */
  78      virtual CTransactionRef GetTxToReconsider(NodeId peer) = 0;
  79  
  80      /** Erase an orphan by wtxid, including all announcements if there are multiple.
  81       * Returns true if an orphan was erased, false if no tx with this wtxid exists. */
  82      virtual bool EraseTx(const Wtxid& wtxid) = 0;
  83  
  84      /** Maybe erase all orphans announced by a peer (eg, after that peer disconnects). If an orphan
  85       * has been announced by another peer, don't erase, just remove this peer from the list of announcers. */
  86      virtual void EraseForPeer(NodeId peer) = 0;
  87  
  88      /** Erase all orphans included in or invalidated by a new block */
  89      virtual void EraseForBlock(const CBlock& block) = 0;
  90  
  91      /** Add any orphans that list a particular tx as a parent into the from peer's work set */
  92      virtual std::vector<std::pair<Wtxid, NodeId>> AddChildrenToWorkSet(const CTransaction& tx, FastRandomContext& rng) = 0;
  93  
  94      /** Does this peer have any work to do? */
  95      virtual bool HaveTxToReconsider(NodeId peer) = 0;
  96  
  97      /** Get all children that spend from this tx and were received from nodeid. Sorted
  98       * reconsiderable before non-reconsiderable, then from most recent to least recent. */
  99      virtual std::vector<CTransactionRef> GetChildrenFromSamePeer(const CTransactionRef& parent, NodeId nodeid) const = 0;
 100  
 101      /** Get all orphan transactions */
 102      virtual std::vector<OrphanInfo> GetOrphanTransactions() const = 0;
 103  
 104      /** Get the total usage (weight) of all orphans. If an orphan has multiple announcers, its usage is
 105       * only counted once within this total. */
 106      virtual Usage TotalOrphanUsage() const = 0;
 107  
 108      /** Total usage (weight) of orphans for which this peer is an announcer. If an orphan has multiple
 109       * announcers, its weight will be accounted for in each PeerOrphanInfo, so the total of all
 110       * peers' UsageByPeer() may be larger than TotalOrphanUsage(). Similarly, UsageByPeer() may be far higher than
 111       * ReservedPeerUsage(), particularly if many peers have provided the same orphans. */
 112      virtual Usage UsageByPeer(NodeId peer) const = 0;
 113  
 114      /** Check consistency between PeerOrphanInfo and m_orphans. Recalculate counters and ensure they
 115       * match what is cached. */
 116      virtual void SanityCheck() const = 0;
 117  
 118      /** Number of announcements, i.e. total size of m_orphans. Ones for the same wtxid are not de-duplicated.
 119       * Not the same as TotalLatencyScore(). */
 120      virtual Count CountAnnouncements() const = 0;
 121  
 122      /** Number of unique orphans (by wtxid). */
 123      virtual Count CountUniqueOrphans() const = 0;
 124  
 125      /** Number of orphans stored from this peer. */
 126      virtual Count AnnouncementsFromPeer(NodeId peer) const = 0;
 127  
 128      /** Latency score of transactions announced by this peer. */
 129      virtual Count LatencyScoreFromPeer(NodeId peer) const = 0;
 130  
 131      /** Get the maximum global latency score allowed */
 132      virtual Count MaxGlobalLatencyScore() const = 0;
 133  
 134      /** Get the total latency score of all orphans */
 135      virtual Count TotalLatencyScore() const = 0;
 136  
 137      /** Get the reserved usage per peer */
 138      virtual Usage ReservedPeerUsage() const = 0;
 139  
 140      /** Get the maximum latency score allowed per peer */
 141      virtual Count MaxPeerLatencyScore() const = 0;
 142  
 143      /** Get the maximum global usage allowed */
 144      virtual Usage MaxGlobalUsage() const = 0;
 145  };
 146  
 147  /** Create a new TxOrphanage instance */
 148  std::unique_ptr<TxOrphanage> MakeTxOrphanage() noexcept;
 149  std::unique_ptr<TxOrphanage> MakeTxOrphanage(TxOrphanage::Count max_global_latency_score, TxOrphanage::Usage reserved_peer_usage) noexcept;
 150  } // namespace node
 151  #endif // BITCOIN_NODE_TXORPHANAGE_H
 152