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