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.cpp
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
5
#include <node/txdownloadman_impl.h>
6
#include <node/txdownloadman.h>
7
8
#include <chain.h>
9
#include <consensus/validation.h>
10
#include <txmempool.h>
11
#include <util/log.h>
12
#include <validation.h>
13
#include <validationinterface.h>
14
15
namespace node {
16
// TxDownloadManager wrappers
17
TxDownloadManager::TxDownloadManager(const TxDownloadOptions& options) :
18
1.26k
    m_impl{std::make_unique<TxDownloadManagerImpl>(options)}
19
1.26k
{}
20
1.26k
TxDownloadManager::~TxDownloadManager() = default;
21
22
void TxDownloadManager::ActiveTipChange()
23
74.7k
{
24
74.7k
    m_impl->ActiveTipChange();
25
74.7k
}
26
void TxDownloadManager::BlockConnected(const std::shared_ptr<const CBlock>& pblock)
27
79.2k
{
28
79.2k
    m_impl->BlockConnected(pblock);
29
79.2k
}
30
void TxDownloadManager::BlockDisconnected()
31
9.54k
{
32
9.54k
    m_impl->BlockDisconnected();
33
9.54k
}
34
void TxDownloadManager::ConnectedPeer(NodeId nodeid, const TxDownloadConnectionInfo& info)
35
1.61k
{
36
1.61k
    m_impl->ConnectedPeer(nodeid, info);
37
1.61k
}
38
void TxDownloadManager::DisconnectedPeer(NodeId nodeid)
39
1.78k
{
40
1.78k
    m_impl->DisconnectedPeer(nodeid);
41
1.78k
}
42
bool TxDownloadManager::AddTxAnnouncement(NodeId peer, const GenTxid& gtxid, std::chrono::microseconds now)
43
27.3k
{
44
27.3k
    return m_impl->AddTxAnnouncement(peer, gtxid, now);
45
27.3k
}
46
std::vector<GenTxid> TxDownloadManager::GetRequestsToSend(NodeId nodeid, std::chrono::microseconds current_time)
47
338k
{
48
338k
    return m_impl->GetRequestsToSend(nodeid, current_time);
49
338k
}
50
void TxDownloadManager::ReceivedNotFound(NodeId nodeid, const std::vector<GenTxid>& gtxids)
51
8
{
52
8
    m_impl->ReceivedNotFound(nodeid, gtxids);
53
8
}
54
void TxDownloadManager::MempoolAcceptedTx(const CTransactionRef& tx)
55
12.0k
{
56
12.0k
    m_impl->MempoolAcceptedTx(tx);
57
12.0k
}
58
RejectedTxTodo TxDownloadManager::MempoolRejectedTx(const CTransactionRef& ptx, const TxValidationState& state, NodeId nodeid, bool first_time_failure)
59
843
{
60
843
    return m_impl->MempoolRejectedTx(ptx, state, nodeid, first_time_failure);
61
843
}
62
void TxDownloadManager::MempoolRejectedPackage(const Package& package)
63
3
{
64
3
    m_impl->MempoolRejectedPackage(package);
65
3
}
66
std::pair<bool, std::optional<PackageToValidate>> TxDownloadManager::ReceivedTx(NodeId nodeid, const CTransactionRef& ptx)
67
16.4k
{
68
16.4k
    return m_impl->ReceivedTx(nodeid, ptx);
69
16.4k
}
70
bool TxDownloadManager::HaveMoreWork(NodeId nodeid) const
71
138k
{
72
138k
    return m_impl->HaveMoreWork(nodeid);
73
138k
}
74
CTransactionRef TxDownloadManager::GetTxToReconsider(NodeId nodeid)
75
342k
{
76
342k
    return m_impl->GetTxToReconsider(nodeid);
77
342k
}
78
void TxDownloadManager::CheckIsEmpty() const
79
917
{
80
917
    m_impl->CheckIsEmpty();
81
917
}
82
void TxDownloadManager::CheckIsEmpty(NodeId nodeid) const
83
1.78k
{
84
1.78k
    m_impl->CheckIsEmpty(nodeid);
85
1.78k
}
86
std::vector<TxOrphanage::OrphanInfo> TxDownloadManager::GetOrphanTransactions() const
87
228
{
88
228
    return m_impl->GetOrphanTransactions();
89
228
}
90
91
// TxDownloadManagerImpl
92
void TxDownloadManagerImpl::ActiveTipChange()
93
74.7k
{
94
74.7k
    RecentRejectsFilter().reset();
95
74.7k
    RecentRejectsReconsiderableFilter().reset();
96
74.7k
}
97
98
void TxDownloadManagerImpl::BlockConnected(const std::shared_ptr<const CBlock>& pblock)
99
79.2k
{
100
79.2k
    m_orphanage->EraseForBlock(*pblock);
101
102
125k
    for (const auto& ptx : pblock->vtx) {
103
        // Reconsider potential child transactions.
104
125k
        m_orphanage->AddChildrenToWorkSet(*ptx, m_rng);
105
106
125k
        RecentConfirmedTransactionsFilter().insert(ptx->GetHash().ToUint256());
107
125k
        if (ptx->HasWitness()) {
108
97.3k
            RecentConfirmedTransactionsFilter().insert(ptx->GetWitnessHash().ToUint256());
109
97.3k
        }
110
125k
        m_txrequest.ForgetTxHash(ptx->GetHash().ToUint256());
111
125k
        m_txrequest.ForgetTxHash(ptx->GetWitnessHash().ToUint256());
112
125k
    }
113
79.2k
}
114
115
void TxDownloadManagerImpl::BlockDisconnected()
116
9.54k
{
117
    // To avoid relay problems with transactions that were previously
118
    // confirmed, clear our filter of recently confirmed transactions whenever
119
    // there's a reorg.
120
    // This means that in a 1-block reorg (where 1 block is disconnected and
121
    // then another block reconnected), our filter will drop to having only one
122
    // block's worth of transactions in it, but that should be fine, since
123
    // presumably the most common case of relaying a confirmed transaction
124
    // should be just after a new block containing it is found.
125
9.54k
    RecentConfirmedTransactionsFilter().reset();
126
9.54k
}
127
128
bool TxDownloadManagerImpl::AlreadyHaveTx(const GenTxid& gtxid, bool include_reconsiderable)
129
67.6k
{
130
67.6k
    const uint256& hash = gtxid.ToUint256();
131
132
    // Never query by txid: it is possible that the transaction in the orphanage has the same
133
    // txid but a different witness, which would give us a false positive result. If we decided
134
    // not to request the transaction based on this result, an attacker could prevent us from
135
    // downloading a transaction by intentionally creating a malleated version of it.  While
136
    // only one (or none!) of these transactions can ultimately be confirmed, we have no way of
137
    // discerning which one that is, so the orphanage can store multiple transactions with the
138
    // same txid.
139
    //
140
    // While we won't query by txid, we can try to "guess" what the wtxid is based on the txid.
141
    // A non-segwit transaction's txid == wtxid. Query this txhash "casted" to a wtxid. This will
142
    // help us find non-segwit transactions, saving bandwidth, and should have no false positives.
143
67.6k
    if (m_orphanage->HaveTx(Wtxid::FromUint256(hash))) return true;
144
145
64.6k
    if (include_reconsiderable && RecentRejectsReconsiderableFilter().contains(hash)) return true;
146
147
64.6k
    if (RecentConfirmedTransactionsFilter().contains(hash)) return true;
148
149
64.5k
    return RecentRejectsFilter().contains(hash) || std::visit([&](const auto& id) { return m_mempool.exists(id); }, gtxid);
txdownloadman_impl.cpp:_ZZN4node21TxDownloadManagerImpl13AlreadyHaveTxERK7GenTxidbENK3$_0clI22transaction_identifierILb0EEEEDaRKT_
Line
Count
Source
149
975
    return RecentRejectsFilter().contains(hash) || std::visit([&](const auto& id) { return m_mempool.exists(id); }, gtxid);
txdownloadman_impl.cpp:_ZZN4node21TxDownloadManagerImpl13AlreadyHaveTxERK7GenTxidbENK3$_0clI22transaction_identifierILb1EEEEDaRKT_
Line
Count
Source
149
63.4k
    return RecentRejectsFilter().contains(hash) || std::visit([&](const auto& id) { return m_mempool.exists(id); }, gtxid);
150
64.6k
}
151
152
void TxDownloadManagerImpl::ConnectedPeer(NodeId nodeid, const TxDownloadConnectionInfo& info)
153
1.68k
{
154
    // If already connected (shouldn't happen in practice), exit early.
155
1.68k
    if (m_peer_info.contains(nodeid)) return;
156
157
1.68k
    m_peer_info.try_emplace(nodeid, info);
158
1.68k
    if (info.m_wtxid_relay) m_num_wtxid_peers += 1;
159
1.68k
}
160
161
void TxDownloadManagerImpl::DisconnectedPeer(NodeId nodeid)
162
1.78k
{
163
1.78k
    m_orphanage->EraseForPeer(nodeid);
164
1.78k
    m_txrequest.DisconnectedPeer(nodeid);
165
166
1.78k
    if (auto it = m_peer_info.find(nodeid); it != m_peer_info.end()) {
167
1.61k
        if (it->second.m_connection_info.m_wtxid_relay) m_num_wtxid_peers -= 1;
168
1.61k
        m_peer_info.erase(it);
169
1.61k
    }
170
171
1.78k
}
172
173
bool TxDownloadManagerImpl::AddTxAnnouncement(NodeId peer, const GenTxid& gtxid, std::chrono::microseconds now)
174
27.4k
{
175
    // If this is an orphan we are trying to resolve, consider this peer as a orphan resolution candidate instead.
176
    // - is wtxid matching something in orphanage
177
    // - exists in orphanage
178
    // - peer can be an orphan resolution candidate
179
27.4k
    if (const auto* wtxid = std::get_if<Wtxid>(&gtxid)) {
180
27.3k
        if (auto orphan_tx{m_orphanage->GetTx(*wtxid)}) {
181
7
            auto unique_parents{GetUniqueParents(*orphan_tx)};
182
8
            std::erase_if(unique_parents, [&](const auto& txid) {
183
8
                return AlreadyHaveTx(txid, /*include_reconsiderable=*/false);
184
8
            });
185
186
            // The missing parents may have all been rejected or accepted since the orphan was added to the orphanage.
187
            // Do not delete from the orphanage, as it may be queued for processing.
188
7
            if (unique_parents.empty()) {
189
0
                return true;
190
0
            }
191
192
7
            if (MaybeAddOrphanResolutionCandidate(unique_parents, *wtxid, peer, now)) {
193
3
                m_orphanage->AddAnnouncer(orphan_tx->GetWitnessHash(), peer);
194
3
            }
195
196
            // Return even if the peer isn't an orphan resolution candidate. This would be caught by AlreadyHaveTx.
197
7
            return true;
198
7
        }
199
27.3k
    }
200
201
    // If this is an inv received from a peer and we already have it, we can drop it.
202
27.4k
    if (AlreadyHaveTx(gtxid, /*include_reconsiderable=*/true)) return true;
203
204
23.6k
    auto it = m_peer_info.find(peer);
205
23.6k
    if (it == m_peer_info.end()) return false;
206
23.6k
    const auto& info = it->second.m_connection_info;
207
23.6k
    if (!info.m_relay_permissions && m_txrequest.Count(peer) >= MAX_PEER_TX_ANNOUNCEMENTS) {
208
        // Too many queued announcements for this peer
209
1
        return false;
210
1
    }
211
    // Decide the TxRequestTracker parameters for this announcement:
212
    // - "preferred": if fPreferredDownload is set (= outbound, or NetPermissionFlags::NoBan permission)
213
    // - "reqtime": current time plus delays for:
214
    //   - NONPREF_PEER_TX_DELAY for announcements from non-preferred connections
215
    //   - TXID_RELAY_DELAY for txid announcements while wtxid peers are available
216
    //   - OVERLOADED_PEER_TX_DELAY for announcements from peers which have at least
217
    //     MAX_PEER_TX_REQUEST_IN_FLIGHT requests in flight (and don't have NetPermissionFlags::Relay).
218
23.6k
    auto delay{0us};
219
23.6k
    if (!info.m_preferred) delay += NONPREF_PEER_TX_DELAY;
220
23.6k
    if (!gtxid.IsWtxid() && m_num_wtxid_peers > 0) delay += TXID_RELAY_DELAY;
221
23.6k
    const bool overloaded = !info.m_relay_permissions && m_txrequest.CountInFlight(peer) >= MAX_PEER_TX_REQUEST_IN_FLIGHT;
222
23.6k
    if (overloaded) delay += OVERLOADED_PEER_TX_DELAY;
223
224
23.6k
    m_txrequest.ReceivedInv(peer, gtxid, info.m_preferred, now + delay);
225
226
23.6k
    return false;
227
23.6k
}
228
229
bool TxDownloadManagerImpl::MaybeAddOrphanResolutionCandidate(const std::vector<Txid>& unique_parents, const Wtxid& wtxid, NodeId nodeid, std::chrono::microseconds now)
230
679
{
231
679
    auto it_peer = m_peer_info.find(nodeid);
232
679
    if (it_peer == m_peer_info.end()) return false;
233
679
    if (m_orphanage->HaveTxFromPeer(wtxid, nodeid)) return false;
234
235
675
    const auto& peer_entry = m_peer_info.at(nodeid);
236
675
    const auto& info = peer_entry.m_connection_info;
237
238
    // TODO: add delays and limits based on the amount of orphan resolution we are already doing
239
    // with this peer, how much they are using the orphanage, etc.
240
675
    if (!info.m_relay_permissions) {
241
        // This mirrors the delaying and dropping behavior in AddTxAnnouncement in order to preserve
242
        // existing behavior: drop if we are tracking too many invs for this peer already. Each
243
        // orphan resolution involves at least 1 transaction request which may or may not be
244
        // currently tracked in m_txrequest, so we include that in the count.
245
675
        if (m_txrequest.Count(nodeid) + unique_parents.size() > MAX_PEER_TX_ANNOUNCEMENTS) return false;
246
675
    }
247
248
675
    std::chrono::seconds delay{0s};
249
675
    if (!info.m_preferred) delay += NONPREF_PEER_TX_DELAY;
250
    // The orphan wtxid is used, but resolution entails requesting the parents by txid. Sometimes
251
    // parent and child are announced and thus requested around the same time, and we happen to
252
    // receive child sooner. Waiting a few seconds may allow us to cancel the orphan resolution
253
    // request if the parent arrives in that time.
254
675
    if (m_num_wtxid_peers > 0) delay += TXID_RELAY_DELAY;
255
675
    const bool overloaded = !info.m_relay_permissions && m_txrequest.CountInFlight(nodeid) >= MAX_PEER_TX_REQUEST_IN_FLIGHT;
256
675
    if (overloaded) delay += OVERLOADED_PEER_TX_DELAY;
257
258
    // Treat finding orphan resolution candidate as equivalent to the peer announcing all missing parents.
259
    // In the future, orphan resolution may include more explicit steps
260
694
    for (const auto& parent_txid : unique_parents) {
261
694
        m_txrequest.ReceivedInv(nodeid, parent_txid, info.m_preferred, now + delay);
262
694
    }
263
675
    LogDebug(BCLog::TXPACKAGES, "added peer=%d as a candidate for resolving orphan %s\n", nodeid, wtxid.ToString());
264
675
    return true;
265
675
}
266
267
std::vector<GenTxid> TxDownloadManagerImpl::GetRequestsToSend(NodeId nodeid, std::chrono::microseconds current_time)
268
338k
{
269
338k
    std::vector<GenTxid> requests;
270
338k
    std::vector<std::pair<NodeId, GenTxid>> expired;
271
338k
    auto requestable = m_txrequest.GetRequestable(nodeid, current_time, &expired);
272
338k
    for (const auto& [expired_nodeid, gtxid] : expired) {
273
28
        LogDebug(BCLog::NET, "timeout of inflight %s %s from peer=%d\n", gtxid.IsWtxid() ? "wtx" : "tx",
274
28
                 gtxid.ToUint256().ToString(), expired_nodeid);
275
28
    }
276
338k
    for (const GenTxid& gtxid : requestable) {
277
23.0k
        if (!AlreadyHaveTx(gtxid, /*include_reconsiderable=*/false)) {
278
22.9k
            LogDebug(BCLog::NET, "Requesting %s %s peer=%d\n", gtxid.IsWtxid() ? "wtx" : "tx",
279
22.9k
                     gtxid.ToUint256().ToString(), nodeid);
280
22.9k
            requests.emplace_back(gtxid);
281
22.9k
            m_txrequest.RequestedTx(nodeid, gtxid.ToUint256(), current_time + GETDATA_TX_INTERVAL);
282
22.9k
        } else {
283
            // We have already seen this transaction, no need to download. This is just a belt-and-suspenders, as
284
            // this should already be called whenever a transaction becomes AlreadyHaveTx().
285
63
            m_txrequest.ForgetTxHash(gtxid.ToUint256());
286
63
        }
287
23.0k
    }
288
338k
    return requests;
289
338k
}
290
291
void TxDownloadManagerImpl::ReceivedNotFound(NodeId nodeid, const std::vector<GenTxid>& gtxids)
292
8
{
293
8
    for (const auto& gtxid : gtxids) {
294
        // If we receive a NOTFOUND message for a tx we requested, mark the announcement for it as
295
        // completed in TxRequestTracker.
296
8
        m_txrequest.ReceivedResponse(nodeid, gtxid.ToUint256());
297
8
    }
298
8
}
299
300
std::optional<PackageToValidate> TxDownloadManagerImpl::Find1P1CPackage(const CTransactionRef& ptx, NodeId nodeid)
301
52
{
302
52
    const auto& parent_wtxid{ptx->GetWitnessHash()};
303
304
52
    Assume(RecentRejectsReconsiderableFilter().contains(parent_wtxid.ToUint256()));
305
306
    // Only consider children from this peer. This helps prevent censorship attempts in which an attacker
307
    // sends lots of fake children for the parent, and we (unluckily) keep selecting the fake
308
    // children instead of the real one provided by the honest peer. Since we track all announcers
309
    // of an orphan, this does not exclude parent + orphan pairs that we happened to request from
310
    // different peers.
311
52
    const auto cpfp_candidates_same_peer{m_orphanage->GetChildrenFromSamePeer(ptx, nodeid)};
312
313
    // These children should be sorted from newest to oldest. In the (probably uncommon) case
314
    // of children that replace each other, this helps us accept the highest feerate (probably the
315
    // most recent) one efficiently.
316
52
    for (const auto& child : cpfp_candidates_same_peer) {
317
30
        Package maybe_cpfp_package{ptx, child};
318
30
        if (!RecentRejectsReconsiderableFilter().contains(GetPackageHash(maybe_cpfp_package)) &&
319
30
            !RecentRejectsFilter().contains(child->GetHash().ToUint256())) {
320
30
            return PackageToValidate{ptx, child, nodeid, nodeid};
321
30
        }
322
30
    }
323
22
    return std::nullopt;
324
52
}
325
326
void TxDownloadManagerImpl::MempoolAcceptedTx(const CTransactionRef& tx)
327
12.0k
{
328
    // As this version of the transaction was acceptable, we can forget about any requests for it.
329
    // No-op if the tx is not in txrequest.
330
12.0k
    m_txrequest.ForgetTxHash(tx->GetHash().ToUint256());
331
12.0k
    m_txrequest.ForgetTxHash(tx->GetWitnessHash().ToUint256());
332
333
12.0k
    m_orphanage->AddChildrenToWorkSet(*tx, m_rng);
334
    // If it came from the orphanage, remove it. No-op if the tx is not in txorphanage.
335
12.0k
    m_orphanage->EraseTx(tx->GetWitnessHash());
336
12.0k
}
337
338
std::vector<Txid> TxDownloadManagerImpl::GetUniqueParents(const CTransaction& tx)
339
714
{
340
714
    std::vector<Txid> unique_parents;
341
714
    unique_parents.reserve(tx.vin.size());
342
836
    for (const CTxIn& txin : tx.vin) {
343
        // We start with all parents, and then remove duplicates below.
344
836
        unique_parents.push_back(txin.prevout.hash);
345
836
    }
346
347
714
    std::sort(unique_parents.begin(), unique_parents.end());
348
714
    unique_parents.erase(std::unique(unique_parents.begin(), unique_parents.end()), unique_parents.end());
349
350
714
    return unique_parents;
351
714
}
352
353
node::RejectedTxTodo TxDownloadManagerImpl::MempoolRejectedTx(const CTransactionRef& ptx, const TxValidationState& state, NodeId nodeid, bool first_time_failure)
354
960
{
355
960
    const CTransaction& tx{*ptx};
356
    // Results returned to caller
357
    // Whether we should call AddToCompactExtraTransactions at the end
358
960
    bool add_extra_compact_tx{first_time_failure};
359
    // Hashes to pass to AddKnownTx later
360
960
    std::vector<Txid> unique_parents;
361
    // Populated if failure is reconsiderable and eligible package is found.
362
960
    std::optional<node::PackageToValidate> package_to_validate;
363
364
960
    if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
365
        // Only process a new orphan if this is a first time failure, as otherwise it must be either
366
        // already in orphanage or from 1p1c processing.
367
707
        if (first_time_failure && !RecentRejectsFilter().contains(ptx->GetWitnessHash().ToUint256())) {
368
707
            bool fRejectedParents = false; // It may be the case that the orphans parents have all been rejected
369
370
            // Deduplicate parent txids, so that we don't have to loop over
371
            // the same parent txid more than once down below.
372
707
            unique_parents = GetUniqueParents(tx);
373
374
            // Distinguish between parents in m_lazy_recent_rejects and m_lazy_recent_rejects_reconsiderable.
375
            // We can tolerate having up to 1 parent in m_lazy_recent_rejects_reconsiderable since we
376
            // submit 1p1c packages. However, fail immediately if any are in m_lazy_recent_rejects.
377
707
            std::optional<Txid> rejected_parent_reconsiderable;
378
805
            for (const Txid& parent_txid : unique_parents) {
379
805
                if (RecentRejectsFilter().contains(parent_txid.ToUint256())) {
380
36
                    fRejectedParents = true;
381
36
                    break;
382
769
                } else if (RecentRejectsReconsiderableFilter().contains(parent_txid.ToUint256()) &&
383
769
                           !m_mempool.exists(parent_txid)) {
384
                    // More than 1 parent in m_lazy_recent_rejects_reconsiderable: 1p1c will not be
385
                    // sufficient to accept this package, so just give up here.
386
16
                    if (rejected_parent_reconsiderable.has_value()) {
387
2
                        fRejectedParents = true;
388
2
                        break;
389
2
                    }
390
14
                    rejected_parent_reconsiderable = parent_txid;
391
14
                }
392
805
            }
393
707
            if (!fRejectedParents) {
394
                // Filter parents that we already have.
395
                // Exclude m_lazy_recent_rejects_reconsiderable: the missing parent may have been
396
                // previously rejected for being too low feerate. This orphan might CPFP it.
397
732
                std::erase_if(unique_parents, [&](const auto& txid) {
398
732
                    return AlreadyHaveTx(txid, /*include_reconsiderable=*/false);
399
732
                });
400
669
                const auto now{GetTime<std::chrono::microseconds>()};
401
669
                const auto& wtxid = ptx->GetWitnessHash();
402
                // Potentially flip add_extra_compact_tx to false if tx is already in orphanage, which
403
                // means it was already added to vExtraTxnForCompact.
404
669
                add_extra_compact_tx &= !m_orphanage->HaveTx(wtxid);
405
406
                // If there is no candidate for orphan resolution, AddTx will not be called. This means
407
                // that if a peer is overloading us with invs and orphans, they will eventually not be
408
                // able to add any more transactions to the orphanage.
409
                //
410
                // Search by txid and, if the tx has a witness, wtxid
411
669
                std::vector<NodeId> orphan_resolution_candidates{nodeid};
412
669
                m_txrequest.GetCandidatePeers(ptx->GetHash().ToUint256(), orphan_resolution_candidates);
413
669
                if (ptx->HasWitness()) m_txrequest.GetCandidatePeers(ptx->GetWitnessHash().ToUint256(), orphan_resolution_candidates);
414
415
672
                for (const auto& nodeid : orphan_resolution_candidates) {
416
672
                    if (MaybeAddOrphanResolutionCandidate(unique_parents, ptx->GetWitnessHash(), nodeid, now)) {
417
672
                        m_orphanage->AddTx(ptx, nodeid);
418
672
                    }
419
672
                }
420
421
                // Once added to the orphan pool, a tx is considered AlreadyHave, and we shouldn't request it anymore.
422
669
                m_txrequest.ForgetTxHash(tx.GetHash().ToUint256());
423
669
                m_txrequest.ForgetTxHash(tx.GetWitnessHash().ToUint256());
424
669
            } else {
425
38
                unique_parents.clear();
426
38
                LogDebug(BCLog::MEMPOOL, "not keeping orphan with rejected parents %s (wtxid=%s)\n",
427
38
                         tx.GetHash().ToString(),
428
38
                         tx.GetWitnessHash().ToString());
429
                // We will continue to reject this tx since it has rejected
430
                // parents so avoid re-requesting it from other peers.
431
                // Here we add both the txid and the wtxid, as we know that
432
                // regardless of what witness is provided, we will not accept
433
                // this, so we don't need to allow for redownload of this txid
434
                // from any of our non-wtxidrelay peers.
435
38
                RecentRejectsFilter().insert(tx.GetHash().ToUint256());
436
38
                RecentRejectsFilter().insert(tx.GetWitnessHash().ToUint256());
437
38
                m_txrequest.ForgetTxHash(tx.GetHash().ToUint256());
438
38
                m_txrequest.ForgetTxHash(tx.GetWitnessHash().ToUint256());
439
38
            }
440
707
        }
441
707
    } else if (state.GetResult() == TxValidationResult::TX_WITNESS_STRIPPED) {
442
9
        add_extra_compact_tx = false;
443
244
    } else {
444
        // We can add the wtxid of this transaction to our reject filter.
445
        // Do not add txids of witness transactions or witness-stripped
446
        // transactions to the filter, as they can have been malleated;
447
        // adding such txids to the reject filter would potentially
448
        // interfere with relay of valid transactions from peers that
449
        // do not support wtxid-based relay. See
450
        // https://github.com/bitcoin/bitcoin/issues/8279 for details.
451
        // We can remove this restriction (and always add wtxids to
452
        // the filter even for witness stripped transactions) once
453
        // wtxid-based relay is broadly deployed.
454
        // See also comments in https://github.com/bitcoin/bitcoin/pull/18044#discussion_r443419034
455
        // for concerns around weakening security of unupgraded nodes
456
        // if we start doing this too early.
457
244
        if (state.GetResult() == TxValidationResult::TX_RECONSIDERABLE) {
458
            // If the result is TX_RECONSIDERABLE, add it to m_lazy_recent_rejects_reconsiderable
459
            // because we should not download or submit this transaction by itself again, but may
460
            // submit it as part of a package later.
461
44
            RecentRejectsReconsiderableFilter().insert(ptx->GetWitnessHash().ToUint256());
462
463
44
            if (first_time_failure) {
464
                // When a transaction fails for TX_RECONSIDERABLE, look for a matching child in the
465
                // orphanage, as it is possible that they succeed as a package.
466
37
                LogDebug(BCLog::TXPACKAGES, "tx %s (wtxid=%s) failed but reconsiderable, looking for child in orphanage\n",
467
37
                         ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString());
468
37
                package_to_validate = Find1P1CPackage(ptx, nodeid);
469
37
            }
470
200
        } else {
471
200
            RecentRejectsFilter().insert(ptx->GetWitnessHash().ToUint256());
472
200
        }
473
244
        m_txrequest.ForgetTxHash(ptx->GetWitnessHash().ToUint256());
474
        // If the transaction failed for TX_INPUTS_NOT_STANDARD,
475
        // then we know that the witness was irrelevant to the policy
476
        // failure, since this check depends only on the txid
477
        // (the scriptPubKey being spent is covered by the txid).
478
        // Add the txid to the reject filter to prevent repeated
479
        // processing of this transaction in the event that child
480
        // transactions are later received (resulting in
481
        // parent-fetching by txid via the orphan-handling logic).
482
        // We only add the txid if it differs from the wtxid, to avoid wasting entries in the
483
        // rolling bloom filter.
484
244
        if (state.GetResult() == TxValidationResult::TX_INPUTS_NOT_STANDARD && ptx->HasWitness()) {
485
3
            RecentRejectsFilter().insert(ptx->GetHash().ToUint256());
486
3
            m_txrequest.ForgetTxHash(ptx->GetHash().ToUint256());
487
3
        }
488
244
    }
489
490
    // If the tx failed in ProcessOrphanTx, it should be removed from the orphanage unless the
491
    // tx was still missing inputs. If the tx was not in the orphanage, EraseTx does nothing and returns 0.
492
960
    if (state.GetResult() != TxValidationResult::TX_MISSING_INPUTS && m_orphanage->EraseTx(ptx->GetWitnessHash())) {
493
10
        LogDebug(BCLog::TXPACKAGES, "   removed orphan tx %s (wtxid=%s)\n", ptx->GetHash().ToString(), ptx->GetWitnessHash().ToString());
494
10
    }
495
496
960
    return RejectedTxTodo{
497
960
        .m_should_add_extra_compact_tx = add_extra_compact_tx,
498
960
        .m_unique_parents = std::move(unique_parents),
499
960
        .m_package_to_validate = std::move(package_to_validate)
500
960
    };
501
960
}
502
503
void TxDownloadManagerImpl::MempoolRejectedPackage(const Package& package)
504
3
{
505
3
    RecentRejectsReconsiderableFilter().insert(GetPackageHash(package));
506
3
}
507
508
std::pair<bool, std::optional<PackageToValidate>> TxDownloadManagerImpl::ReceivedTx(NodeId nodeid, const CTransactionRef& ptx)
509
16.4k
{
510
16.4k
    const Txid& txid = ptx->GetHash();
511
16.4k
    const Wtxid& wtxid = ptx->GetWitnessHash();
512
513
    // Mark that we have received a response
514
16.4k
    m_txrequest.ReceivedResponse(nodeid, txid.ToUint256());
515
16.4k
    if (ptx->HasWitness()) m_txrequest.ReceivedResponse(nodeid, wtxid.ToUint256());
516
517
    // First check if we should drop this tx.
518
    // We do the AlreadyHaveTx() check using wtxid, rather than txid - in the
519
    // absence of witness malleation, this is strictly better, because the
520
    // recent rejects filter may contain the wtxid but rarely contains
521
    // the txid of a segwit transaction that has been rejected.
522
    // In the presence of witness malleation, it's possible that by only
523
    // doing the check with wtxid, we could overlook a transaction which
524
    // was confirmed with a different witness, or exists in our mempool
525
    // with a different witness, but this has limited downside:
526
    // mempool validation does its own lookup of whether we have the txid
527
    // already; and an adversary can already relay us old transactions
528
    // (older than our recency filter) if trying to DoS us, without any need
529
    // for witness malleation.
530
16.4k
    if (AlreadyHaveTx(wtxid, /*include_reconsiderable=*/false)) {
531
        // If a tx is detected by m_lazy_recent_rejects it is ignored. Because we haven't
532
        // submitted the tx to our mempool, we won't have computed a DoS
533
        // score for it or determined exactly why we consider it invalid.
534
        //
535
        // This means we won't penalize any peer subsequently relaying a DoSy
536
        // tx (even if we penalized the first peer who gave it to us) because
537
        // we have to account for m_lazy_recent_rejects showing false positives. In
538
        // other words, we shouldn't penalize a peer if we aren't *sure* they
539
        // submitted a DoSy tx.
540
        //
541
        // Note that m_lazy_recent_rejects doesn't just record DoSy or invalid
542
        // transactions, but any tx not accepted by the mempool, which may be
543
        // due to node policy (vs. consensus). So we can't blanket penalize a
544
        // peer simply for relaying a tx that our m_lazy_recent_rejects has caught,
545
        // regardless of false positives.
546
3.66k
        return {false, std::nullopt};
547
12.7k
    } else if (RecentRejectsReconsiderableFilter().contains(wtxid.ToUint256())) {
548
        // When a transaction is already in m_lazy_recent_rejects_reconsiderable, we shouldn't submit
549
        // it by itself again. However, look for a matching child in the orphanage, as it is
550
        // possible that they succeed as a package.
551
15
        LogDebug(BCLog::TXPACKAGES, "found tx %s (wtxid=%s) in reconsiderable rejects, looking for child in orphanage\n",
552
15
                 txid.ToString(), wtxid.ToString());
553
15
        return {false, Find1P1CPackage(ptx, nodeid)};
554
15
    }
555
556
557
12.7k
    return {true, std::nullopt};
558
16.4k
}
559
560
bool TxDownloadManagerImpl::HaveMoreWork(NodeId nodeid)
561
138k
{
562
138k
    return m_orphanage->HaveTxToReconsider(nodeid);
563
138k
}
564
565
CTransactionRef TxDownloadManagerImpl::GetTxToReconsider(NodeId nodeid)
566
342k
{
567
342k
    return m_orphanage->GetTxToReconsider(nodeid);
568
342k
}
569
570
void TxDownloadManagerImpl::CheckIsEmpty(NodeId nodeid)
571
1.78k
{
572
1.78k
    assert(m_txrequest.Count(nodeid) == 0);
573
1.78k
    assert(m_orphanage->UsageByPeer(nodeid) == 0);
574
1.78k
}
575
void TxDownloadManagerImpl::CheckIsEmpty()
576
917
{
577
917
    assert(m_orphanage->TotalOrphanUsage() == 0);
578
917
    assert(m_orphanage->CountUniqueOrphans() == 0);
579
917
    assert(m_txrequest.Size() == 0);
580
917
    assert(m_num_wtxid_peers == 0);
581
917
}
582
std::vector<TxOrphanage::OrphanInfo> TxDownloadManagerImpl::GetOrphanTransactions() const
583
228
{
584
228
    return m_orphanage->GetOrphanTransactions();
585
228
}
586
} // namespace node