Coverage Report

Created: 2026-07-14 18:13

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