Coverage Report

Created: 2026-09-14 20:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/tmp/bitcoin/src/node/txdownloadman_impl.h
Line
Count
Source
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
    CRollingBloomFilter& RecentRejectsFilter()
68
141k
    {
69
141k
        if (!m_lazy_recent_rejects) {
70
653
            m_lazy_recent_rejects = std::make_unique<CRollingBloomFilter>(120'000, 0.000'001);
71
653
        }
72
73
141k
        return *m_lazy_recent_rejects;
74
141k
    }
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
    CRollingBloomFilter& RecentRejectsReconsiderableFilter()
99
115k
    {
100
115k
        if (!m_lazy_recent_rejects_reconsiderable) {
101
649
            m_lazy_recent_rejects_reconsiderable = std::make_unique<CRollingBloomFilter>(120'000, 0.000'001);
102
649
        }
103
104
115k
        return *m_lazy_recent_rejects_reconsiderable;
105
115k
    }
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
    CRollingBloomFilter& RecentConfirmedTransactionsFilter()
125
297k
    {
126
297k
        if (!m_lazy_recent_confirmed_transactions) {
127
650
            m_lazy_recent_confirmed_transactions = std::make_unique<CRollingBloomFilter>(48'000, 0.000'001);
128
650
        }
129
130
297k
        return *m_lazy_recent_confirmed_transactions;
131
297k
    }
132
133
    TxDownloadManagerImpl(const TxDownloadOptions& options)
134
1.32k
        : m_mempool{options.m_mempool},
135
1.32k
          m_rng{options.m_deterministic_txrequest},
136
1.32k
          m_orphanage{MakeTxOrphanage()},
137
1.32k
          m_txrequest{options.m_deterministic_txrequest}
138
1.32k
    {}
139
140
    struct PeerInfo {
141
        /** Information relevant to scheduling tx requests. */
142
        const TxDownloadConnectionInfo m_connection_info;
143
144
1.68k
        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