LCOV - code coverage report
Current view: top level - src/node - txorphanage.h Coverage Total Hit
Test: total_coverage.info Lines: 100.0 % 5 5
Test Date: 2025-08-01 05:08:13 Functions: - 0 0
Branches: 50.0 % 4 2

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2021-2022 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   [ +  -  +  - ]:        1226 : class TxOrphanage {
      39                 :             : public:
      40                 :             :     using Usage = int64_t;
      41                 :             :     using Count = unsigned int;
      42                 :             : 
      43                 :             :     /** Allows providing orphan information externally */
      44                 :             :     struct OrphanTxBase {
      45                 :             :         CTransactionRef tx;
      46                 :             :         /** Peers added with AddTx or AddAnnouncer. */
      47                 :             :         std::set<NodeId> announcers;
      48                 :             : 
      49                 :             :         // Constructor with moved announcers
      50                 :     1798379 :         OrphanTxBase(CTransactionRef tx, std::set<NodeId>&& announcers) :
      51                 :     1798379 :             tx(std::move(tx)),
      52                 :     1798379 :             announcers(std::move(announcers))
      53                 :             :         {}
      54                 :             :     };
      55                 :             : 
      56                 :        1226 :     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                 :             :     /** Limit the orphanage to MaxGlobalLatencyScore and MaxGlobalUsage. */
      92                 :             :     virtual void LimitOrphans() = 0;
      93                 :             : 
      94                 :             :     /** Add any orphans that list a particular tx as a parent into the from peer's work set */
      95                 :             :     virtual std::vector<std::pair<Wtxid, NodeId>> AddChildrenToWorkSet(const CTransaction& tx, FastRandomContext& rng) = 0;
      96                 :             : 
      97                 :             :     /** Does this peer have any work to do? */
      98                 :             :     virtual bool HaveTxToReconsider(NodeId peer) = 0;
      99                 :             : 
     100                 :             :     /** Get all children that spend from this tx and were received from nodeid. Sorted from most
     101                 :             :      * recent to least recent. */
     102                 :             :     virtual std::vector<CTransactionRef> GetChildrenFromSamePeer(const CTransactionRef& parent, NodeId nodeid) const = 0;
     103                 :             : 
     104                 :             :     /** Return how many entries exist in the orphange */
     105                 :             :     virtual size_t Size() const = 0;
     106                 :             : 
     107                 :             :     /** Get all orphan transactions */
     108                 :             :     virtual std::vector<OrphanTxBase> GetOrphanTransactions() const = 0;
     109                 :             : 
     110                 :             :     /** Get the total usage (weight) of all orphans. If an orphan has multiple announcers, its usage is
     111                 :             :      * only counted once within this total. */
     112                 :             :     virtual Usage TotalOrphanUsage() const = 0;
     113                 :             : 
     114                 :             :     /** Total usage (weight) of orphans for which this peer is an announcer. If an orphan has multiple
     115                 :             :      * announcers, its weight will be accounted for in each PeerOrphanInfo, so the total of all
     116                 :             :      * peers' UsageByPeer() may be larger than TotalOrphanUsage(). Similarly, UsageByPeer() may be far higher than
     117                 :             :      * ReservedPeerUsage(), particularly if many peers have provided the same orphans. */
     118                 :             :     virtual Usage UsageByPeer(NodeId peer) const = 0;
     119                 :             : 
     120                 :             :     /** Check consistency between PeerOrphanInfo and m_orphans. Recalculate counters and ensure they
     121                 :             :      * match what is cached. */
     122                 :             :     virtual void SanityCheck() const = 0;
     123                 :             : 
     124                 :             :     /** Number of announcements, i.e. total size of m_orphans. Ones for the same wtxid are not de-duplicated.
     125                 :             :      * Not the same as TotalLatencyScore(). */
     126                 :             :     virtual Count CountAnnouncements() const = 0;
     127                 :             : 
     128                 :             :     /** Number of unique orphans (by wtxid). */
     129                 :             :     virtual Count CountUniqueOrphans() const = 0;
     130                 :             : 
     131                 :             :     /** Number of orphans stored from this peer. */
     132                 :             :     virtual Count AnnouncementsFromPeer(NodeId peer) const = 0;
     133                 :             : 
     134                 :             :     /** Latency score of transactions announced by this peer. */
     135                 :             :     virtual Count LatencyScoreFromPeer(NodeId peer) const = 0;
     136                 :             : 
     137                 :             :     /** Get the maximum global latency score allowed */
     138                 :             :     virtual Count MaxGlobalLatencyScore() const = 0;
     139                 :             : 
     140                 :             :     /** Get the total latency score of all orphans */
     141                 :             :     virtual Count TotalLatencyScore() const = 0;
     142                 :             : 
     143                 :             :     /** Get the reserved usage per peer */
     144                 :             :     virtual Usage ReservedPeerUsage() const = 0;
     145                 :             : 
     146                 :             :     /** Get the maximum latency score allowed per peer */
     147                 :             :     virtual Count MaxPeerLatencyScore() const = 0;
     148                 :             : 
     149                 :             :     /** Get the maximum global usage allowed */
     150                 :             :     virtual Usage MaxGlobalUsage() const = 0;
     151                 :             : };
     152                 :             : 
     153                 :             : /** Create a new TxOrphanage instance */
     154                 :             : std::unique_ptr<TxOrphanage> MakeTxOrphanage() noexcept;
     155                 :             : std::unique_ptr<TxOrphanage> MakeTxOrphanage(TxOrphanage::Count max_global_ann, TxOrphanage::Usage reserved_peer_usage) noexcept;
     156                 :             : } // namespace node
     157                 :             : #endif // BITCOIN_NODE_TXORPHANAGE_H
        

Generated by: LCOV version 2.0-1