Coverage Report

Created: 2026-05-30 09:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/tmp/bitcoin/src/node/mini_miner.h
Line
Count
Source
1
// Copyright (c) 2022-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
#ifndef BITCOIN_NODE_MINI_MINER_H
6
#define BITCOIN_NODE_MINI_MINER_H
7
8
#include <attributes.h>
9
#include <consensus/amount.h>
10
#include <primitives/transaction.h>
11
12
#include <cstdint>
13
#include <map>
14
#include <optional>
15
#include <set>
16
#include <vector>
17
18
class CFeeRate;
19
class CTxMemPool;
20
21
namespace node {
22
23
// Container for tracking updates to ancestor feerate as we include ancestors in the "block"
24
class MiniMinerMempoolEntry
25
{
26
    const CTransactionRef tx;
27
    const int64_t vsize_individual;
28
    int64_t vsize_with_ancestors;
29
    const CAmount fee_individual;
30
    CAmount fee_with_ancestors;
31
32
// This class must be constructed while holding mempool.cs. After construction, the object's
33
// methods can be called without holding that lock.
34
35
public:
36
    explicit MiniMinerMempoolEntry(const CTransactionRef& tx_in,
37
                                   int64_t vsize_self,
38
                                   int64_t vsize_ancestor,
39
                                   CAmount fee_self,
40
                                   CAmount fee_ancestor):
41
68.1k
        tx{tx_in},
42
68.1k
        vsize_individual{vsize_self},
43
68.1k
        vsize_with_ancestors{vsize_ancestor},
44
68.1k
        fee_individual{fee_self},
45
68.1k
        fee_with_ancestors{fee_ancestor}
46
68.1k
    { }
47
48
38.7M
    CAmount GetModifiedFee() const { return fee_individual; }
49
38.7M
    CAmount GetModFeesWithAncestors() const { return fee_with_ancestors; }
50
42.2M
    int64_t GetTxSize() const { return vsize_individual; }
51
42.2M
    int64_t GetSizeWithAncestors() const { return vsize_with_ancestors; }
52
68.0k
    const CTransaction& GetTx() const LIFETIMEBOUND { return *tx; }
53
99.6k
    void UpdateAncestorState(int64_t vsize_change, CAmount fee_change) {
54
99.6k
        vsize_with_ancestors += vsize_change;
55
99.6k
        fee_with_ancestors += fee_change;
56
99.6k
    }
57
};
58
59
// Comparator needed for std::set<MockEntryMap::iterator>
60
struct IteratorComparator
61
{
62
    template<typename I>
63
    bool operator()(const I& a, const I& b) const
64
7.58k
    {
65
7.58k
        return a->first < b->first;
66
7.58k
    }
67
};
68
69
/** A minimal version of BlockAssembler, using the same ancestor set scoring algorithm. Allows us to
70
 * run this algorithm on a limited set of transactions (e.g. subset of mempool or transactions that
71
 * are not yet in mempool) instead of the entire mempool, ignoring consensus rules.
72
 * Callers may use this to:
73
 * - Calculate the "bump fee" needed to spend an unconfirmed UTXO at a given feerate
74
 * - "Linearize" a list of transactions to see the order in which they would be selected for
75
 *   inclusion in a block
76
 */
77
class MiniMiner
78
{
79
    // When true, a caller may use CalculateBumpFees(). Becomes false if we failed to retrieve
80
    // mempool entries (i.e. cluster size too large) or bump fees have already been calculated.
81
    bool m_ready_to_calculate{true};
82
83
    // Set once per lifetime, fill in during initialization.
84
    // txids of to-be-replaced transactions
85
    std::set<Txid> m_to_be_replaced;
86
87
    // If multiple argument outpoints correspond to the same transaction, cache them together in
88
    // a single entry indexed by txid. Then we can just work with txids since all outpoints from
89
    // the same tx will have the same bumpfee. Excludes non-mempool transactions.
90
    std::map<Txid, std::vector<COutPoint>> m_requested_outpoints_by_txid;
91
92
    // Txid to a number representing the order in which this transaction was included (smaller
93
    // number = included earlier).  Transactions included in an ancestor set together have the same
94
    // sequence number.
95
    std::map<Txid, uint32_t> m_inclusion_order;
96
    // What we're trying to calculate. Outpoint to the fee needed to bring the transaction to the target feerate.
97
    std::map<COutPoint, CAmount> m_bump_fees;
98
99
    // The constructed block template
100
    std::set<Txid> m_in_block;
101
102
    // Information on the current status of the block
103
    CAmount m_total_fees{0};
104
    int32_t m_total_vsize{0};
105
106
    /** Main data structure holding the entries, can be indexed by txid */
107
    std::map<Txid, MiniMinerMempoolEntry> m_entries_by_txid;
108
    using MockEntryMap = decltype(m_entries_by_txid);
109
110
    /** Vector of entries, can be sorted by ancestor feerate. */
111
    std::vector<MockEntryMap::iterator> m_entries;
112
113
    /** Map of txid to its descendants. Should be inclusive. */
114
    std::map<Txid, std::vector<MockEntryMap::iterator>> m_descendant_set_by_txid;
115
116
    /** Consider this ancestor package "mined" so remove all these entries from our data structures. */
117
    void DeleteAncestorPackage(const std::set<MockEntryMap::iterator, IteratorComparator>& ancestors);
118
119
    /** Perform some checks. */
120
    void SanityCheck() const;
121
122
public:
123
    /** Returns true if CalculateBumpFees may be called, false if not. */
124
115
    bool IsReadyToCalculate() const { return m_ready_to_calculate; }
125
126
    /** Build a block template until the target feerate is hit. If target_feerate is not given,
127
     * builds a block template until all transactions have been selected. */
128
    void BuildMockTemplate(std::optional<CFeeRate> target_feerate);
129
130
    /** Returns set of txids in the block template if one has been constructed. */
131
2
    std::set<Txid> GetMockTemplateTxids() const { return m_in_block; }
132
133
    /** Constructor that takes a list of outpoints that may or may not belong to transactions in the
134
     * mempool. Copies out information about the relevant transactions in the mempool into
135
     * MiniMinerMempoolEntrys.
136
    */
137
    MiniMiner(const CTxMemPool& mempool, const std::vector<COutPoint>& outpoints);
138
139
    /** Constructor in which the MiniMinerMempoolEntry entries have been constructed manually.
140
     * It is assumed that all entries are unique and their values are correct, otherwise results
141
     * computed by MiniMiner may be incorrect. Callers should check IsReadyToCalculate() after
142
     * construction.
143
     * @param[in] descendant_caches A map from each transaction to the set of txids of this
144
     *                              transaction's descendant set, including itself. Each tx in
145
     *                              manual_entries must have a corresponding entry in this map, and
146
     *                              all of the txids in a descendant set must correspond to a tx in
147
     *                              manual_entries.
148
     */
149
    MiniMiner(const std::vector<MiniMinerMempoolEntry>& manual_entries,
150
              const std::map<Txid, std::set<Txid>>& descendant_caches);
151
152
    /** Construct a new block template and, for each outpoint corresponding to a transaction that
153
     * did not make it into the block, calculate the cost of bumping those transactions (and their
154
     * ancestors) to the minimum feerate. Returns a map from outpoint to bump fee, or an empty map
155
     * if they cannot be calculated. */
156
    std::map<COutPoint, CAmount> CalculateBumpFees(const CFeeRate& target_feerate);
157
158
    /** Construct a new block template and, calculate the cost of bumping all transactions that did
159
     * not make it into the block to the target feerate. Returns the total bump fee, or std::nullopt
160
     * if it cannot be calculated. */
161
    std::optional<CAmount> CalculateTotalBumpFees(const CFeeRate& target_feerate);
162
163
    /** Construct a new block template with all of the transactions and calculate the order in which
164
     * they are selected. Returns the sequence number (lower = selected earlier) with which each
165
     * transaction was selected, indexed by txid, or an empty map if it cannot be calculated.
166
     */
167
    std::map<Txid, uint32_t> Linearize();
168
};
169
} // namespace node
170
171
#endif // BITCOIN_NODE_MINI_MINER_H