Branch data Line data Source code
1 : : // Copyright (c) 2024-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 : : #ifndef BITCOIN_NODE_TXDOWNLOADMAN_IMPL_H
5 : : #define BITCOIN_NODE_TXDOWNLOADMAN_IMPL_H
6 : :
7 : : #include <node/txdownloadman.h>
8 : :
9 : : #include <common/bloom.h>
10 : : #include <consensus/validation.h>
11 : : #include <kernel/chain.h>
12 : : #include <net.h>
13 : : #include <node/txorphanage.h>
14 : : #include <primitives/transaction.h>
15 : : #include <policy/packages.h>
16 : : #include <random.h>
17 : : #include <txrequest.h>
18 : :
19 : : class CTxMemPool;
20 : : namespace node {
21 : : class TxDownloadManagerImpl {
22 : : public:
23 : : const CTxMemPool& m_mempool;
24 : : FastRandomContext m_rng;
25 : :
26 : : /** Manages unvalidated tx data (orphan transactions for which we are downloading ancestors). */
27 : : std::unique_ptr<TxOrphanage> m_orphanage;
28 : : /** Tracks candidates for requesting and downloading transaction data. */
29 : : TxRequestTracker m_txrequest;
30 : :
31 : : /**
32 : : * Filter for transactions that were recently rejected by the mempool.
33 : : * These are not rerequested until the chain tip changes, at which point
34 : : * the entire filter is reset.
35 : : *
36 : : * Without this filter we'd be re-requesting txs from each of our peers,
37 : : * increasing bandwidth consumption considerably. For instance, with 100
38 : : * peers, half of which relay a tx we don't accept, that might be a 50x
39 : : * bandwidth increase. A flooding attacker attempting to roll-over the
40 : : * filter using minimum-sized, 60byte, transactions might manage to send
41 : : * 1000/sec if we have fast peers, so we pick 120,000 to give our peers a
42 : : * two minute window to send invs to us.
43 : : *
44 : : * Decreasing the false positive rate is fairly cheap, so we pick one in a
45 : : * million to make it highly unlikely for users to have issues with this
46 : : * filter.
47 : : *
48 : : * We typically only add wtxids to this filter. For non-segwit
49 : : * transactions, the txid == wtxid, so this only prevents us from
50 : : * re-downloading non-segwit transactions when communicating with
51 : : * non-wtxidrelay peers -- which is important for avoiding malleation
52 : : * attacks that could otherwise interfere with transaction relay from
53 : : * non-wtxidrelay peers. For communicating with wtxidrelay peers, having
54 : : * the reject filter store wtxids is exactly what we want to avoid
55 : : * redownload of a rejected transaction.
56 : : *
57 : : * In cases where we can tell that a segwit transaction will fail
58 : : * validation no matter the witness, we may add the txid of such
59 : : * transaction to the filter as well. This can be helpful when
60 : : * communicating with txid-relay peers or if we were to otherwise fetch a
61 : : * transaction via txid (eg in our orphan handling).
62 : : *
63 : : * Memory used: 1.3 MB
64 : : */
65 : : std::unique_ptr<CRollingBloomFilter> m_lazy_recent_rejects{nullptr};
66 : :
67 : 550677 : CRollingBloomFilter& RecentRejectsFilter()
68 : : {
69 [ + + ]: 550677 : if (!m_lazy_recent_rejects) {
70 : 3035 : m_lazy_recent_rejects = std::make_unique<CRollingBloomFilter>(120'000, 0.000'001);
71 : : }
72 : :
73 : 550677 : return *m_lazy_recent_rejects;
74 : : }
75 : :
76 : : /**
77 : : * Filter for:
78 : : * (1) wtxids of transactions that were recently rejected by the mempool but are
79 : : * eligible for reconsideration if submitted with other transactions.
80 : : * (2) packages (see GetPackageHash) we have already rejected before and should not retry.
81 : : *
82 : : * Similar to m_lazy_recent_rejects, this filter is used to save bandwidth when e.g. all of our peers
83 : : * have larger mempools and thus lower minimum feerates than us.
84 : : *
85 : : * When a transaction's error is TxValidationResult::TX_RECONSIDERABLE (in a package or by
86 : : * itself), add its wtxid to this filter. When a package fails for any reason, add the combined
87 : : * hash to this filter.
88 : : *
89 : : * Upon receiving an announcement for a transaction, if it exists in this filter, do not
90 : : * download the txdata. When considering packages, if it exists in this filter, drop it.
91 : : *
92 : : * Reset this filter when the chain tip changes.
93 : : *
94 : : * Parameters are picked to be the same as m_lazy_recent_rejects, with the same rationale.
95 : : */
96 : : std::unique_ptr<CRollingBloomFilter> m_lazy_recent_rejects_reconsiderable{nullptr};
97 : :
98 : 484889 : CRollingBloomFilter& RecentRejectsReconsiderableFilter()
99 : : {
100 [ + + ]: 484889 : if (!m_lazy_recent_rejects_reconsiderable) {
101 : 2995 : m_lazy_recent_rejects_reconsiderable = std::make_unique<CRollingBloomFilter>(120'000, 0.000'001);
102 : : }
103 : :
104 : 484889 : return *m_lazy_recent_rejects_reconsiderable;
105 : : }
106 : :
107 : : /*
108 : : * Filter for transactions that have been recently confirmed.
109 : : * We use this to avoid requesting transactions that have already been
110 : : * confirmed.
111 : : *
112 : : * Blocks don't typically have more than 4000 transactions, so this should
113 : : * be at least six blocks (~1 hr) worth of transactions that we can store,
114 : : * inserting both a txid and wtxid for every observed transaction.
115 : : * If the number of transactions appearing in a block goes up, or if we are
116 : : * seeing getdata requests more than an hour after initial announcement, we
117 : : * can increase this number.
118 : : * The false positive rate of 1/1M should come out to less than 1
119 : : * transaction per day that would be inadvertently ignored (which is the
120 : : * same probability that we have in the reject filter).
121 : : */
122 : : std::unique_ptr<CRollingBloomFilter> m_lazy_recent_confirmed_transactions{nullptr};
123 : :
124 : 169420 : CRollingBloomFilter& RecentConfirmedTransactionsFilter()
125 : : {
126 [ + + ]: 169420 : if (!m_lazy_recent_confirmed_transactions) {
127 : 3215 : m_lazy_recent_confirmed_transactions = std::make_unique<CRollingBloomFilter>(48'000, 0.000'001);
128 : : }
129 : :
130 : 169420 : return *m_lazy_recent_confirmed_transactions;
131 : : }
132 : :
133 : 13927 : TxDownloadManagerImpl(const TxDownloadOptions& options)
134 : 13927 : : m_mempool{options.m_mempool},
135 : 13927 : m_rng{options.m_deterministic_txrequest},
136 : 13927 : m_orphanage{MakeTxOrphanage()},
137 [ + - ]: 13927 : m_txrequest{options.m_deterministic_txrequest}
138 : 13927 : {}
139 : :
140 : : struct PeerInfo {
141 : : /** Information relevant to scheduling tx requests. */
142 : : const TxDownloadConnectionInfo m_connection_info;
143 : :
144 : 16112 : PeerInfo(const TxDownloadConnectionInfo& info) : m_connection_info{info} {}
145 : : };
146 : :
147 : : /** Information for all of the peers we may download transactions from. This is not necessarily
148 : : * all peers we are connected to (no block-relay-only and temporary connections). */
149 : : std::map<NodeId, PeerInfo> m_peer_info;
150 : :
151 : : /** Number of wtxid relay peers we have in m_peer_info. */
152 : : uint32_t m_num_wtxid_peers{0};
153 : :
154 : : void ActiveTipChange();
155 : : void BlockConnected(const std::shared_ptr<const CBlock>& pblock);
156 : : void BlockDisconnected();
157 : :
158 : : /** Check whether we already have this gtxid in:
159 : : * - mempool
160 : : * - orphanage
161 : : * - m_recent_rejects
162 : : * - m_recent_rejects_reconsiderable (if include_reconsiderable = true)
163 : : * - m_recent_confirmed_transactions
164 : : * */
165 : : bool AlreadyHaveTx(const GenTxid& gtxid, bool include_reconsiderable);
166 : :
167 : : void ConnectedPeer(NodeId nodeid, const TxDownloadConnectionInfo& info);
168 : : void DisconnectedPeer(NodeId nodeid);
169 : :
170 : : /** Consider adding this tx hash to txrequest. Should be called whenever a new inv has been received.
171 : : * Also called internally when a transaction is missing parents so that we can request them.
172 : : */
173 : : bool AddTxAnnouncement(NodeId peer, const GenTxid& gtxid, std::chrono::microseconds now);
174 : :
175 : : /** Get getdata requests to send. */
176 : : std::vector<GenTxid> GetRequestsToSend(NodeId nodeid, std::chrono::microseconds current_time);
177 : :
178 : : /** Marks a tx as ReceivedResponse in txrequest. */
179 : : void ReceivedNotFound(NodeId nodeid, const std::vector<GenTxid>& gtxids);
180 : :
181 : : /** Look for a child of this transaction in the orphanage to form a 1-parent-1-child package,
182 : : * skipping any combinations that have already been tried. Return the resulting package along with
183 : : * the senders of its respective transactions, or std::nullopt if no package is found. */
184 : : std::optional<PackageToValidate> Find1P1CPackage(const CTransactionRef& ptx, NodeId nodeid);
185 : :
186 : : void MempoolAcceptedTx(const CTransactionRef& tx);
187 : : RejectedTxTodo MempoolRejectedTx(const CTransactionRef& ptx, const TxValidationState& state, NodeId nodeid, bool first_time_failure);
188 : : void MempoolRejectedPackage(const Package& package);
189 : :
190 : : std::pair<bool, std::optional<PackageToValidate>> ReceivedTx(NodeId nodeid, const CTransactionRef& ptx);
191 : :
192 : : bool HaveMoreWork(NodeId nodeid);
193 : : CTransactionRef GetTxToReconsider(NodeId nodeid);
194 : :
195 : : void CheckIsEmpty();
196 : : void CheckIsEmpty(NodeId nodeid);
197 : :
198 : : std::vector<TxOrphanage::OrphanInfo> GetOrphanTransactions() const;
199 : :
200 : : protected:
201 : : /** Helper for getting deduplicated vector of Txids in vin. */
202 : : std::vector<Txid> GetUniqueParents(const CTransaction& tx);
203 : :
204 : : /** If this peer is an orphan resolution candidate for this transaction, treat the unique_parents as announced by
205 : : * this peer; add them as new invs to m_txrequest.
206 : : * @returns whether this transaction was a valid orphan resolution candidate.
207 : : * */
208 : : bool MaybeAddOrphanResolutionCandidate(const std::vector<Txid>& unique_parents, const Wtxid& wtxid, NodeId nodeid, std::chrono::microseconds now);
209 : : };
210 : : } // namespace node
211 : : #endif // BITCOIN_NODE_TXDOWNLOADMAN_IMPL_H
|