Coverage Report

Created: 2025-04-09 20:14

/root/bitcoin/src/txorphanage.h
Line
Count
Source (jump to first uncovered line)
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_TXORPHANAGE_H
6
#define BITCOIN_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
/** Expiration time for orphan transactions */
19
static constexpr auto ORPHAN_TX_EXPIRE_TIME{20min};
20
/** Minimum time between orphan transactions expire time checks */
21
static constexpr auto ORPHAN_TX_EXPIRE_INTERVAL{5min};
22
23
/** A class to track orphan transactions (failed on TX_MISSING_INPUTS)
24
 * Since we cannot distinguish orphans from bad transactions with
25
 * non-existent inputs, we heavily limit the number of orphans
26
 * we keep and the duration we keep them for.
27
 * Not thread-safe. Requires external synchronization.
28
 */
29
class TxOrphanage {
30
public:
31
    /** Add a new orphan transaction */
32
    bool AddTx(const CTransactionRef& tx, NodeId peer);
33
34
    /** Add an additional announcer to an orphan if it exists. Otherwise, do nothing. */
35
    bool AddAnnouncer(const Wtxid& wtxid, NodeId peer);
36
37
    CTransactionRef GetTx(const Wtxid& wtxid) const;
38
39
    /** Check if we already have an orphan transaction (by wtxid only) */
40
    bool HaveTx(const Wtxid& wtxid) const;
41
42
    /** Check if a {tx, peer} exists in the orphanage.*/
43
    bool HaveTxFromPeer(const Wtxid& wtxid, NodeId peer) const;
44
45
    /** Extract a transaction from a peer's work set
46
     *  Returns nullptr if there are no transactions to work on.
47
     *  Otherwise returns the transaction reference, and removes
48
     *  it from the work set.
49
     */
50
    CTransactionRef GetTxToReconsider(NodeId peer);
51
52
    /** Erase an orphan by wtxid */
53
    int EraseTx(const Wtxid& wtxid);
54
55
    /** Maybe erase all orphans announced by a peer (eg, after that peer disconnects). If an orphan
56
     * has been announced by another peer, don't erase, just remove this peer from the list of announcers. */
57
    void EraseForPeer(NodeId peer);
58
59
    /** Erase all orphans included in or invalidated by a new block */
60
    void EraseForBlock(const CBlock& block);
61
62
    /** Limit the orphanage to the given maximum */
63
    void LimitOrphans(unsigned int max_orphans, FastRandomContext& rng);
64
65
    /** Add any orphans that list a particular tx as a parent into the from peer's work set */
66
    void AddChildrenToWorkSet(const CTransaction& tx, FastRandomContext& rng);
67
68
    /** Does this peer have any work to do? */
69
    bool HaveTxToReconsider(NodeId peer);
70
71
    /** Get all children that spend from this tx and were received from nodeid. Sorted from most
72
     * recent to least recent. */
73
    std::vector<CTransactionRef> GetChildrenFromSamePeer(const CTransactionRef& parent, NodeId nodeid) const;
74
75
    /** Return how many entries exist in the orphange */
76
    size_t Size() const
77
1.00k
    {
78
1.00k
        return m_orphans.size();
79
1.00k
    }
80
81
    /** Allows providing orphan information externally */
82
    struct OrphanTxBase {
83
        CTransactionRef tx;
84
        /** Peers added with AddTx or AddAnnouncer. */
85
        std::set<NodeId> announcers;
86
        NodeSeconds nTimeExpire;
87
88
        /** Get the weight of this transaction, an approximation of its memory usage. */
89
0
        unsigned int GetUsage() const {
90
0
            return GetTransactionWeight(*tx);
91
0
        }
92
    };
93
94
    std::vector<OrphanTxBase> GetOrphanTransactions() const;
95
96
    /** Get the total usage (weight) of all orphans. If an orphan has multiple announcers, its usage is
97
     * only counted once within this total. */
98
1.00k
    unsigned int TotalOrphanUsage() const { return m_total_orphan_usage; }
99
100
    /** Total usage (weight) of orphans for which this peer is an announcer. If an orphan has multiple
101
     * announcers, its weight will be accounted for in each PeerOrphanInfo, so the total of all
102
     * peers' UsageByPeer() may be larger than TotalOrphanBytes(). */
103
3.02k
    unsigned int UsageByPeer(NodeId peer) const {
104
3.02k
        auto peer_it = m_peer_orphanage_info.find(peer);
105
3.02k
        return peer_it == m_peer_orphanage_info.end() ? 0 : peer_it->second.m_total_usage;
106
3.02k
    }
107
108
    /** Check consistency between PeerOrphanInfo and m_orphans. Recalculate counters and ensure they
109
     * match what is cached. */
110
    void SanityCheck() const;
111
112
protected:
113
    struct OrphanTx : public OrphanTxBase {
114
        size_t list_pos;
115
    };
116
117
    /** Total usage (weight) of all entries in m_orphans. */
118
    unsigned int m_total_orphan_usage{0};
119
120
    /** Total number of <peer, tx> pairs. Can be larger than m_orphans.size() because multiple peers
121
     * may have announced the same orphan. */
122
    unsigned int m_total_announcements{0};
123
124
    /** Map from wtxid to orphan transaction record. Limited by
125
     *  -maxorphantx/DEFAULT_MAX_ORPHAN_TRANSACTIONS */
126
    std::map<Wtxid, OrphanTx> m_orphans;
127
128
    struct PeerOrphanInfo {
129
        /** List of transactions that should be reconsidered: added to in AddChildrenToWorkSet,
130
         * removed from one-by-one with each call to GetTxToReconsider. The wtxids may refer to
131
         * transactions that are no longer present in orphanage; these are lazily removed in
132
         * GetTxToReconsider. */
133
        std::set<Wtxid> m_work_set;
134
135
        /** Total weight of orphans for which this peer is an announcer.
136
         * If orphans are provided by different peers, its weight will be accounted for in each
137
         * PeerOrphanInfo, so the total of all peers' m_total_usage may be larger than
138
         * m_total_orphan_size. If a peer is removed as an announcer, even if the orphan still
139
         * remains in the orphanage, this number will be decremented. */
140
        unsigned int m_total_usage{0};
141
    };
142
    std::map<NodeId, PeerOrphanInfo> m_peer_orphanage_info;
143
144
    using OrphanMap = decltype(m_orphans);
145
146
    struct IteratorComparator
147
    {
148
        template<typename I>
149
        bool operator()(const I& a, const I& b) const
150
0
        {
151
0
            return a->first < b->first;
152
0
        }
153
    };
154
155
    /** Index from the parents' COutPoint into the m_orphans. Used
156
     *  to remove orphan transactions from the m_orphans */
157
    std::map<COutPoint, std::set<OrphanMap::iterator, IteratorComparator>> m_outpoint_to_orphan_it;
158
159
    /** Orphan transactions in vector for quick random eviction */
160
    std::vector<OrphanMap::iterator> m_orphan_list;
161
162
    /** Timestamp for the next scheduled sweep of expired orphans */
163
    NodeSeconds m_next_sweep{0s};
164
};
165
166
#endif // BITCOIN_TXORPHANAGE_H