Coverage Report

Created: 2025-09-19 18:21

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