/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 |