/root/bitcoin/src/node/txorphanage.h
| Line | Count | Source | 
| 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 |  | 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 | 0 |             tx(std::move(tx)), | 
| 52 | 0 |             announcers(std::move(announcers)) | 
| 53 | 0 |         {} | 
| 54 |  |     }; | 
| 55 |  |  | 
| 56 | 619 |     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 |