fuzz coverage

Coverage Report

Created: 2025-09-17 22:41

/Users/eugenesiegel/btc/bitcoin/src/rpc/mempool.cpp
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) 2010 Satoshi Nakamoto
2
// Copyright (c) 2009-2022 The Bitcoin Core developers
3
// Distributed under the MIT software license, see the accompanying
4
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6
#include <rpc/blockchain.h>
7
8
#include <node/mempool_persist.h>
9
10
#include <chainparams.h>
11
#include <consensus/validation.h>
12
#include <core_io.h>
13
#include <kernel/mempool_entry.h>
14
#include <net_processing.h>
15
#include <node/mempool_persist_args.h>
16
#include <node/types.h>
17
#include <policy/rbf.h>
18
#include <policy/settings.h>
19
#include <primitives/transaction.h>
20
#include <rpc/server.h>
21
#include <rpc/server_util.h>
22
#include <rpc/util.h>
23
#include <txmempool.h>
24
#include <univalue.h>
25
#include <util/fs.h>
26
#include <util/moneystr.h>
27
#include <util/strencodings.h>
28
#include <util/time.h>
29
#include <util/vector.h>
30
31
#include <utility>
32
33
using node::DumpMempool;
34
35
using node::DEFAULT_MAX_BURN_AMOUNT;
36
using node::DEFAULT_MAX_RAW_TX_FEE_RATE;
37
using node::MempoolPath;
38
using node::NodeContext;
39
using node::TransactionError;
40
using util::ToString;
41
42
static RPCHelpMan sendrawtransaction()
43
0
{
44
0
    return RPCHelpMan{
45
0
        "sendrawtransaction",
46
0
        "Submit a raw transaction (serialized, hex-encoded) to local node and network.\n"
47
0
        "\nThe transaction will be sent unconditionally to all peers, so using sendrawtransaction\n"
48
0
        "for manual rebroadcast may degrade privacy by leaking the transaction's origin, as\n"
49
0
        "nodes will normally not rebroadcast non-wallet transactions already in their mempool.\n"
50
0
        "\nA specific exception, RPC_TRANSACTION_ALREADY_IN_UTXO_SET, may throw if the transaction cannot be added to the mempool.\n"
51
0
        "\nRelated RPCs: createrawtransaction, signrawtransactionwithkey\n",
52
0
        {
53
0
            {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"},
54
0
            {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())},
55
0
             "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT +
56
0
                 "/kvB.\nFee rates larger than 1BTC/kvB are rejected.\nSet to 0 to accept any fee rate."},
57
0
            {"maxburnamount", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_BURN_AMOUNT)},
58
0
             "Reject transactions with provably unspendable outputs (e.g. 'datacarrier' outputs that use the OP_RETURN opcode) greater than the specified value, expressed in " + CURRENCY_UNIT + ".\n"
59
0
             "If burning funds through unspendable outputs is desired, increase this value.\n"
60
0
             "This check is based on heuristics and does not guarantee spendability of outputs.\n"},
61
0
        },
62
0
        RPCResult{
63
0
            RPCResult::Type::STR_HEX, "", "The transaction hash in hex"
64
0
        },
65
0
        RPCExamples{
66
0
            "\nCreate a transaction\n"
67
0
            + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") +
68
0
            "Sign the transaction, and get back the hex\n"
69
0
            + HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") +
70
0
            "\nSend the transaction (signed hex)\n"
71
0
            + HelpExampleCli("sendrawtransaction", "\"signedhex\"") +
72
0
            "\nAs a JSON-RPC call\n"
73
0
            + HelpExampleRpc("sendrawtransaction", "\"signedhex\"")
74
0
                },
75
0
        [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
76
0
        {
77
0
            const CAmount max_burn_amount = request.params[2].isNull() ? 0 : AmountFromValue(request.params[2]);
78
79
0
            CMutableTransaction mtx;
80
0
            if (!DecodeHexTx(mtx, request.params[0].get_str())) {
81
0
                throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input.");
82
0
            }
83
84
0
            for (const auto& out : mtx.vout) {
85
0
                if((out.scriptPubKey.IsUnspendable() || !out.scriptPubKey.HasValidOps()) && out.nValue > max_burn_amount) {
86
0
                    throw JSONRPCTransactionError(TransactionError::MAX_BURN_EXCEEDED);
87
0
                }
88
0
            }
89
90
0
            CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
91
92
0
            const CFeeRate max_raw_tx_fee_rate{ParseFeeRate(self.Arg<UniValue>("maxfeerate"))};
93
94
0
            int64_t virtual_size = GetVirtualTransactionSize(*tx);
95
0
            CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size);
96
97
0
            std::string err_string;
98
0
            AssertLockNotHeld(cs_main);
Line
Count
Source
142
0
#define AssertLockNotHeld(cs) AssertLockNotHeldInline(#cs, __FILE__, __LINE__, &cs)
99
0
            NodeContext& node = EnsureAnyNodeContext(request.context);
100
0
            const TransactionError err = BroadcastTransaction(node, tx, err_string, max_raw_tx_fee, /*relay=*/true, /*wait_callback=*/true);
101
0
            if (TransactionError::OK != err) {
102
0
                throw JSONRPCTransactionError(err, err_string);
103
0
            }
104
105
0
            return tx->GetHash().GetHex();
106
0
        },
107
0
    };
108
0
}
109
110
static RPCHelpMan testmempoolaccept()
111
0
{
112
0
    return RPCHelpMan{
113
0
        "testmempoolaccept",
114
0
        "Returns result of mempool acceptance tests indicating if raw transaction(s) (serialized, hex-encoded) would be accepted by mempool.\n"
115
0
        "\nIf multiple transactions are passed in, parents must come before children and package policies apply: the transactions cannot conflict with any mempool transactions or each other.\n"
116
0
        "\nIf one transaction fails, other transactions may not be fully validated (the 'allowed' key will be blank).\n"
117
0
        "\nThe maximum number of transactions allowed is " + ToString(MAX_PACKAGE_COUNT) + ".\n"
118
0
        "\nThis checks if transactions violate the consensus or policy rules.\n"
119
0
        "\nSee sendrawtransaction call.\n",
120
0
        {
121
0
            {"rawtxs", RPCArg::Type::ARR, RPCArg::Optional::NO, "An array of hex strings of raw transactions.",
122
0
                {
123
0
                    {"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
124
0
                },
125
0
            },
126
0
            {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())},
127
0
             "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT +
128
0
                 "/kvB.\nFee rates larger than 1BTC/kvB are rejected.\nSet to 0 to accept any fee rate."},
129
0
        },
130
0
        RPCResult{
131
0
            RPCResult::Type::ARR, "", "The result of the mempool acceptance test for each raw transaction in the input array.\n"
132
0
                                      "Returns results for each transaction in the same order they were passed in.\n"
133
0
                                      "Transactions that cannot be fully validated due to failures in other transactions will not contain an 'allowed' result.\n",
134
0
            {
135
0
                {RPCResult::Type::OBJ, "", "",
136
0
                {
137
0
                    {RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
138
0
                    {RPCResult::Type::STR_HEX, "wtxid", "The transaction witness hash in hex"},
139
0
                    {RPCResult::Type::STR, "package-error", /*optional=*/true, "Package validation error, if any (only possible if rawtxs had more than 1 transaction)."},
140
0
                    {RPCResult::Type::BOOL, "allowed", /*optional=*/true, "Whether this tx would be accepted to the mempool and pass client-specified maxfeerate. "
141
0
                                                       "If not present, the tx was not fully validated due to a failure in another tx in the list."},
142
0
                    {RPCResult::Type::NUM, "vsize", /*optional=*/true, "Virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted (only present when 'allowed' is true)"},
143
0
                    {RPCResult::Type::OBJ, "fees", /*optional=*/true, "Transaction fees (only present if 'allowed' is true)",
144
0
                    {
145
0
                        {RPCResult::Type::STR_AMOUNT, "base", "transaction fee in " + CURRENCY_UNIT},
146
0
                        {RPCResult::Type::STR_AMOUNT, "effective-feerate", /*optional=*/false, "the effective feerate in " + CURRENCY_UNIT + " per KvB. May differ from the base feerate if, for example, there are modified fees from prioritisetransaction or a package feerate was used."},
147
0
                        {RPCResult::Type::ARR, "effective-includes", /*optional=*/false, "transactions whose fees and vsizes are included in effective-feerate.",
148
0
                            {RPCResult{RPCResult::Type::STR_HEX, "", "transaction wtxid in hex"},
149
0
                        }},
150
0
                    }},
151
0
                    {RPCResult::Type::STR, "reject-reason", /*optional=*/true, "Rejection reason (only present when 'allowed' is false)"},
152
0
                    {RPCResult::Type::STR, "reject-details", /*optional=*/true, "Rejection details (only present when 'allowed' is false and rejection details exist)"},
153
0
                }},
154
0
            }
155
0
        },
156
0
        RPCExamples{
157
0
            "\nCreate a transaction\n"
158
0
            + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") +
159
0
            "Sign the transaction, and get back the hex\n"
160
0
            + HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") +
161
0
            "\nTest acceptance of the transaction (signed hex)\n"
162
0
            + HelpExampleCli("testmempoolaccept", R"('["signedhex"]')") +
163
0
            "\nAs a JSON-RPC call\n"
164
0
            + HelpExampleRpc("testmempoolaccept", "[\"signedhex\"]")
165
0
                },
166
0
        [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
167
0
        {
168
0
            const UniValue raw_transactions = request.params[0].get_array();
169
0
            if (raw_transactions.size() < 1 || raw_transactions.size() > MAX_PACKAGE_COUNT) {
170
0
                throw JSONRPCError(RPC_INVALID_PARAMETER,
171
0
                                   "Array must contain between 1 and " + ToString(MAX_PACKAGE_COUNT) + " transactions.");
172
0
            }
173
174
0
            const CFeeRate max_raw_tx_fee_rate{ParseFeeRate(self.Arg<UniValue>("maxfeerate"))};
175
176
0
            std::vector<CTransactionRef> txns;
177
0
            txns.reserve(raw_transactions.size());
178
0
            for (const auto& rawtx : raw_transactions.getValues()) {
179
0
                CMutableTransaction mtx;
180
0
                if (!DecodeHexTx(mtx, rawtx.get_str())) {
181
0
                    throw JSONRPCError(RPC_DESERIALIZATION_ERROR,
182
0
                                       "TX decode failed: " + rawtx.get_str() + " Make sure the tx has at least one input.");
183
0
                }
184
0
                txns.emplace_back(MakeTransactionRef(std::move(mtx)));
185
0
            }
186
187
0
            NodeContext& node = EnsureAnyNodeContext(request.context);
188
0
            CTxMemPool& mempool = EnsureMemPool(node);
189
0
            ChainstateManager& chainman = EnsureChainman(node);
190
0
            Chainstate& chainstate = chainman.ActiveChainstate();
191
0
            const PackageMempoolAcceptResult package_result = [&] {
192
0
                LOCK(::cs_main);
Line
Count
Source
259
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
193
0
                if (txns.size() > 1) return ProcessNewPackage(chainstate, mempool, txns, /*test_accept=*/true, /*client_maxfeerate=*/{});
194
0
                return PackageMempoolAcceptResult(txns[0]->GetWitnessHash(),
195
0
                                                  chainman.ProcessTransaction(txns[0], /*test_accept=*/true));
196
0
            }();
197
198
0
            UniValue rpc_result(UniValue::VARR);
199
            // We will check transaction fees while we iterate through txns in order. If any transaction fee
200
            // exceeds maxfeerate, we will leave the rest of the validation results blank, because it
201
            // doesn't make sense to return a validation result for a transaction if its ancestor(s) would
202
            // not be submitted.
203
0
            bool exit_early{false};
204
0
            for (const auto& tx : txns) {
205
0
                UniValue result_inner(UniValue::VOBJ);
206
0
                result_inner.pushKV("txid", tx->GetHash().GetHex());
207
0
                result_inner.pushKV("wtxid", tx->GetWitnessHash().GetHex());
208
0
                if (package_result.m_state.GetResult() == PackageValidationResult::PCKG_POLICY) {
209
0
                    result_inner.pushKV("package-error", package_result.m_state.ToString());
210
0
                }
211
0
                auto it = package_result.m_tx_results.find(tx->GetWitnessHash());
212
0
                if (exit_early || it == package_result.m_tx_results.end()) {
213
                    // Validation unfinished. Just return the txid and wtxid.
214
0
                    rpc_result.push_back(std::move(result_inner));
215
0
                    continue;
216
0
                }
217
0
                const auto& tx_result = it->second;
218
                // Package testmempoolaccept doesn't allow transactions to already be in the mempool.
219
0
                CHECK_NONFATAL(tx_result.m_result_type != MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
Line
Count
Source
103
0
    inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition)
220
0
                if (tx_result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
221
0
                    const CAmount fee = tx_result.m_base_fees.value();
222
                    // Check that fee does not exceed maximum fee
223
0
                    const int64_t virtual_size = tx_result.m_vsize.value();
224
0
                    const CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size);
225
0
                    if (max_raw_tx_fee && fee > max_raw_tx_fee) {
226
0
                        result_inner.pushKV("allowed", false);
227
0
                        result_inner.pushKV("reject-reason", "max-fee-exceeded");
228
0
                        exit_early = true;
229
0
                    } else {
230
                        // Only return the fee and vsize if the transaction would pass ATMP.
231
                        // These can be used to calculate the feerate.
232
0
                        result_inner.pushKV("allowed", true);
233
0
                        result_inner.pushKV("vsize", virtual_size);
234
0
                        UniValue fees(UniValue::VOBJ);
235
0
                        fees.pushKV("base", ValueFromAmount(fee));
236
0
                        fees.pushKV("effective-feerate", ValueFromAmount(tx_result.m_effective_feerate.value().GetFeePerK()));
237
0
                        UniValue effective_includes_res(UniValue::VARR);
238
0
                        for (const auto& wtxid : tx_result.m_wtxids_fee_calculations.value()) {
239
0
                            effective_includes_res.push_back(wtxid.ToString());
240
0
                        }
241
0
                        fees.pushKV("effective-includes", std::move(effective_includes_res));
242
0
                        result_inner.pushKV("fees", std::move(fees));
243
0
                    }
244
0
                } else {
245
0
                    result_inner.pushKV("allowed", false);
246
0
                    const TxValidationState state = tx_result.m_state;
247
0
                    if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
248
0
                        result_inner.pushKV("reject-reason", "missing-inputs");
249
0
                    } else {
250
0
                        result_inner.pushKV("reject-reason", state.GetRejectReason());
251
0
                        result_inner.pushKV("reject-details", state.ToString());
252
0
                    }
253
0
                }
254
0
                rpc_result.push_back(std::move(result_inner));
255
0
            }
256
0
            return rpc_result;
257
0
        },
258
0
    };
259
0
}
260
261
static std::vector<RPCResult> MempoolEntryDescription()
262
0
{
263
0
    return {
264
0
        RPCResult{RPCResult::Type::NUM, "vsize", "virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted."},
265
0
        RPCResult{RPCResult::Type::NUM, "weight", "transaction weight as defined in BIP 141."},
266
0
        RPCResult{RPCResult::Type::NUM_TIME, "time", "local time transaction entered pool in seconds since 1 Jan 1970 GMT"},
267
0
        RPCResult{RPCResult::Type::NUM, "height", "block height when transaction entered pool"},
268
0
        RPCResult{RPCResult::Type::NUM, "descendantcount", "number of in-mempool descendant transactions (including this one)"},
269
0
        RPCResult{RPCResult::Type::NUM, "descendantsize", "virtual transaction size of in-mempool descendants (including this one)"},
270
0
        RPCResult{RPCResult::Type::NUM, "ancestorcount", "number of in-mempool ancestor transactions (including this one)"},
271
0
        RPCResult{RPCResult::Type::NUM, "ancestorsize", "virtual transaction size of in-mempool ancestors (including this one)"},
272
0
        RPCResult{RPCResult::Type::STR_HEX, "wtxid", "hash of serialized transaction, including witness data"},
273
0
        RPCResult{RPCResult::Type::OBJ, "fees", "",
274
0
            {
275
0
                RPCResult{RPCResult::Type::STR_AMOUNT, "base", "transaction fee, denominated in " + CURRENCY_UNIT},
276
0
                RPCResult{RPCResult::Type::STR_AMOUNT, "modified", "transaction fee with fee deltas used for mining priority, denominated in " + CURRENCY_UNIT},
277
0
                RPCResult{RPCResult::Type::STR_AMOUNT, "ancestor", "transaction fees of in-mempool ancestors (including this one) with fee deltas used for mining priority, denominated in " + CURRENCY_UNIT},
278
0
                RPCResult{RPCResult::Type::STR_AMOUNT, "descendant", "transaction fees of in-mempool descendants (including this one) with fee deltas used for mining priority, denominated in " + CURRENCY_UNIT},
279
0
            }},
280
0
        RPCResult{RPCResult::Type::ARR, "depends", "unconfirmed transactions used as inputs for this transaction",
281
0
            {RPCResult{RPCResult::Type::STR_HEX, "transactionid", "parent transaction id"}}},
282
0
        RPCResult{RPCResult::Type::ARR, "spentby", "unconfirmed transactions spending outputs from this transaction",
283
0
            {RPCResult{RPCResult::Type::STR_HEX, "transactionid", "child transaction id"}}},
284
0
        RPCResult{RPCResult::Type::BOOL, "bip125-replaceable", "Whether this transaction signals BIP125 replaceability or has an unconfirmed ancestor signaling BIP125 replaceability. (DEPRECATED)\n"},
285
0
        RPCResult{RPCResult::Type::BOOL, "unbroadcast", "Whether this transaction is currently unbroadcast (initial broadcast not yet acknowledged by any peers)"},
286
0
    };
287
0
}
288
289
static void entryToJSON(const CTxMemPool& pool, UniValue& info, const CTxMemPoolEntry& e) EXCLUSIVE_LOCKS_REQUIRED(pool.cs)
290
0
{
291
0
    AssertLockHeld(pool.cs);
Line
Count
Source
137
0
#define AssertLockHeld(cs) AssertLockHeldInternal(#cs, __FILE__, __LINE__, &cs)
292
293
0
    info.pushKV("vsize", (int)e.GetTxSize());
294
0
    info.pushKV("weight", (int)e.GetTxWeight());
295
0
    info.pushKV("time", count_seconds(e.GetTime()));
296
0
    info.pushKV("height", (int)e.GetHeight());
297
0
    info.pushKV("descendantcount", e.GetCountWithDescendants());
298
0
    info.pushKV("descendantsize", e.GetSizeWithDescendants());
299
0
    info.pushKV("ancestorcount", e.GetCountWithAncestors());
300
0
    info.pushKV("ancestorsize", e.GetSizeWithAncestors());
301
0
    info.pushKV("wtxid", e.GetTx().GetWitnessHash().ToString());
302
303
0
    UniValue fees(UniValue::VOBJ);
304
0
    fees.pushKV("base", ValueFromAmount(e.GetFee()));
305
0
    fees.pushKV("modified", ValueFromAmount(e.GetModifiedFee()));
306
0
    fees.pushKV("ancestor", ValueFromAmount(e.GetModFeesWithAncestors()));
307
0
    fees.pushKV("descendant", ValueFromAmount(e.GetModFeesWithDescendants()));
308
0
    info.pushKV("fees", std::move(fees));
309
310
0
    const CTransaction& tx = e.GetTx();
311
0
    std::set<std::string> setDepends;
312
0
    for (const CTxIn& txin : tx.vin)
313
0
    {
314
0
        if (pool.exists(txin.prevout.hash))
315
0
            setDepends.insert(txin.prevout.hash.ToString());
316
0
    }
317
318
0
    UniValue depends(UniValue::VARR);
319
0
    for (const std::string& dep : setDepends)
320
0
    {
321
0
        depends.push_back(dep);
322
0
    }
323
324
0
    info.pushKV("depends", std::move(depends));
325
326
0
    UniValue spent(UniValue::VARR);
327
0
    for (const CTxMemPoolEntry& child : e.GetMemPoolChildrenConst()) {
328
0
        spent.push_back(child.GetTx().GetHash().ToString());
329
0
    }
330
331
0
    info.pushKV("spentby", std::move(spent));
332
333
    // Add opt-in RBF status
334
0
    bool rbfStatus = false;
335
0
    RBFTransactionState rbfState = IsRBFOptIn(tx, pool);
336
0
    if (rbfState == RBFTransactionState::UNKNOWN) {
337
0
        throw JSONRPCError(RPC_MISC_ERROR, "Transaction is not in mempool");
338
0
    } else if (rbfState == RBFTransactionState::REPLACEABLE_BIP125) {
339
0
        rbfStatus = true;
340
0
    }
341
342
0
    info.pushKV("bip125-replaceable", rbfStatus);
343
0
    info.pushKV("unbroadcast", pool.IsUnbroadcastTx(tx.GetHash()));
344
0
}
345
346
UniValue MempoolToJSON(const CTxMemPool& pool, bool verbose, bool include_mempool_sequence)
347
0
{
348
0
    if (verbose) {
349
0
        if (include_mempool_sequence) {
350
0
            throw JSONRPCError(RPC_INVALID_PARAMETER, "Verbose results cannot contain mempool sequence values.");
351
0
        }
352
0
        LOCK(pool.cs);
Line
Count
Source
259
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
353
0
        UniValue o(UniValue::VOBJ);
354
0
        for (const CTxMemPoolEntry& e : pool.entryAll()) {
355
0
            UniValue info(UniValue::VOBJ);
356
0
            entryToJSON(pool, info, e);
357
            // Mempool has unique entries so there is no advantage in using
358
            // UniValue::pushKV, which checks if the key already exists in O(N).
359
            // UniValue::pushKVEnd is used instead which currently is O(1).
360
0
            o.pushKVEnd(e.GetTx().GetHash().ToString(), std::move(info));
361
0
        }
362
0
        return o;
363
0
    } else {
364
0
        UniValue a(UniValue::VARR);
365
0
        uint64_t mempool_sequence;
366
0
        {
367
0
            LOCK(pool.cs);
Line
Count
Source
259
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
368
0
            for (const CTxMemPoolEntry& e : pool.entryAll()) {
369
0
                a.push_back(e.GetTx().GetHash().ToString());
370
0
            }
371
0
            mempool_sequence = pool.GetSequence();
372
0
        }
373
0
        if (!include_mempool_sequence) {
374
0
            return a;
375
0
        } else {
376
0
            UniValue o(UniValue::VOBJ);
377
0
            o.pushKV("txids", std::move(a));
378
0
            o.pushKV("mempool_sequence", mempool_sequence);
379
0
            return o;
380
0
        }
381
0
    }
382
0
}
383
384
static RPCHelpMan getrawmempool()
385
0
{
386
0
    return RPCHelpMan{
387
0
        "getrawmempool",
388
0
        "Returns all transaction ids in memory pool as a json array of string transaction ids.\n"
389
0
        "\nHint: use getmempoolentry to fetch a specific transaction from the mempool.\n",
390
0
        {
391
0
            {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"},
392
0
            {"mempool_sequence", RPCArg::Type::BOOL, RPCArg::Default{false}, "If verbose=false, returns a json object with transaction list and mempool sequence number attached."},
393
0
        },
394
0
        {
395
0
            RPCResult{"for verbose = false",
396
0
                RPCResult::Type::ARR, "", "",
397
0
                {
398
0
                    {RPCResult::Type::STR_HEX, "", "The transaction id"},
399
0
                }},
400
0
            RPCResult{"for verbose = true",
401
0
                RPCResult::Type::OBJ_DYN, "", "",
402
0
                {
403
0
                    {RPCResult::Type::OBJ, "transactionid", "", MempoolEntryDescription()},
404
0
                }},
405
0
            RPCResult{"for verbose = false and mempool_sequence = true",
406
0
                RPCResult::Type::OBJ, "", "",
407
0
                {
408
0
                    {RPCResult::Type::ARR, "txids", "",
409
0
                    {
410
0
                        {RPCResult::Type::STR_HEX, "", "The transaction id"},
411
0
                    }},
412
0
                    {RPCResult::Type::NUM, "mempool_sequence", "The mempool sequence value."},
413
0
                }},
414
0
        },
415
0
        RPCExamples{
416
0
            HelpExampleCli("getrawmempool", "true")
417
0
            + HelpExampleRpc("getrawmempool", "true")
418
0
        },
419
0
        [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
420
0
{
421
0
    bool fVerbose = false;
422
0
    if (!request.params[0].isNull())
423
0
        fVerbose = request.params[0].get_bool();
424
425
0
    bool include_mempool_sequence = false;
426
0
    if (!request.params[1].isNull()) {
427
0
        include_mempool_sequence = request.params[1].get_bool();
428
0
    }
429
430
0
    return MempoolToJSON(EnsureAnyMemPool(request.context), fVerbose, include_mempool_sequence);
431
0
},
432
0
    };
433
0
}
434
435
static RPCHelpMan getmempoolancestors()
436
0
{
437
0
    return RPCHelpMan{
438
0
        "getmempoolancestors",
439
0
        "If txid is in the mempool, returns all in-mempool ancestors.\n",
440
0
        {
441
0
            {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
442
0
            {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"},
443
0
        },
444
0
        {
445
0
            RPCResult{"for verbose = false",
446
0
                RPCResult::Type::ARR, "", "",
447
0
                {{RPCResult::Type::STR_HEX, "", "The transaction id of an in-mempool ancestor transaction"}}},
448
0
            RPCResult{"for verbose = true",
449
0
                RPCResult::Type::OBJ_DYN, "", "",
450
0
                {
451
0
                    {RPCResult::Type::OBJ, "transactionid", "", MempoolEntryDescription()},
452
0
                }},
453
0
        },
454
0
        RPCExamples{
455
0
            HelpExampleCli("getmempoolancestors", "\"mytxid\"")
456
0
            + HelpExampleRpc("getmempoolancestors", "\"mytxid\"")
457
0
        },
458
0
        [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
459
0
{
460
0
    bool fVerbose = false;
461
0
    if (!request.params[1].isNull())
462
0
        fVerbose = request.params[1].get_bool();
463
464
0
    auto txid{Txid::FromUint256(ParseHashV(request.params[0], "txid"))};
465
466
0
    const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
467
0
    LOCK(mempool.cs);
Line
Count
Source
259
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
468
469
0
    const auto entry{mempool.GetEntry(txid)};
470
0
    if (entry == nullptr) {
471
0
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool");
472
0
    }
473
474
0
    auto ancestors{mempool.AssumeCalculateMemPoolAncestors(self.m_name, *entry, CTxMemPool::Limits::NoLimits(), /*fSearchForParents=*/false)};
475
476
0
    if (!fVerbose) {
477
0
        UniValue o(UniValue::VARR);
478
0
        for (CTxMemPool::txiter ancestorIt : ancestors) {
479
0
            o.push_back(ancestorIt->GetTx().GetHash().ToString());
480
0
        }
481
0
        return o;
482
0
    } else {
483
0
        UniValue o(UniValue::VOBJ);
484
0
        for (CTxMemPool::txiter ancestorIt : ancestors) {
485
0
            const CTxMemPoolEntry &e = *ancestorIt;
486
0
            UniValue info(UniValue::VOBJ);
487
0
            entryToJSON(mempool, info, e);
488
0
            o.pushKV(e.GetTx().GetHash().ToString(), std::move(info));
489
0
        }
490
0
        return o;
491
0
    }
492
0
},
493
0
    };
494
0
}
495
496
static RPCHelpMan getmempooldescendants()
497
0
{
498
0
    return RPCHelpMan{
499
0
        "getmempooldescendants",
500
0
        "If txid is in the mempool, returns all in-mempool descendants.\n",
501
0
        {
502
0
            {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
503
0
            {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"},
504
0
        },
505
0
        {
506
0
            RPCResult{"for verbose = false",
507
0
                RPCResult::Type::ARR, "", "",
508
0
                {{RPCResult::Type::STR_HEX, "", "The transaction id of an in-mempool descendant transaction"}}},
509
0
            RPCResult{"for verbose = true",
510
0
                RPCResult::Type::OBJ_DYN, "", "",
511
0
                {
512
0
                    {RPCResult::Type::OBJ, "transactionid", "", MempoolEntryDescription()},
513
0
                }},
514
0
        },
515
0
        RPCExamples{
516
0
            HelpExampleCli("getmempooldescendants", "\"mytxid\"")
517
0
            + HelpExampleRpc("getmempooldescendants", "\"mytxid\"")
518
0
        },
519
0
        [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
520
0
{
521
0
    bool fVerbose = false;
522
0
    if (!request.params[1].isNull())
523
0
        fVerbose = request.params[1].get_bool();
524
525
0
    auto txid{Txid::FromUint256(ParseHashV(request.params[0], "txid"))};
526
527
0
    const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
528
0
    LOCK(mempool.cs);
Line
Count
Source
259
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
529
530
0
    const auto it{mempool.GetIter(txid)};
531
0
    if (!it) {
532
0
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool");
533
0
    }
534
535
0
    CTxMemPool::setEntries setDescendants;
536
0
    mempool.CalculateDescendants(*it, setDescendants);
537
    // CTxMemPool::CalculateDescendants will include the given tx
538
0
    setDescendants.erase(*it);
539
540
0
    if (!fVerbose) {
541
0
        UniValue o(UniValue::VARR);
542
0
        for (CTxMemPool::txiter descendantIt : setDescendants) {
543
0
            o.push_back(descendantIt->GetTx().GetHash().ToString());
544
0
        }
545
546
0
        return o;
547
0
    } else {
548
0
        UniValue o(UniValue::VOBJ);
549
0
        for (CTxMemPool::txiter descendantIt : setDescendants) {
550
0
            const CTxMemPoolEntry &e = *descendantIt;
551
0
            UniValue info(UniValue::VOBJ);
552
0
            entryToJSON(mempool, info, e);
553
0
            o.pushKV(e.GetTx().GetHash().ToString(), std::move(info));
554
0
        }
555
0
        return o;
556
0
    }
557
0
},
558
0
    };
559
0
}
560
561
static RPCHelpMan getmempoolentry()
562
0
{
563
0
    return RPCHelpMan{
564
0
        "getmempoolentry",
565
0
        "Returns mempool data for given transaction\n",
566
0
        {
567
0
            {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
568
0
        },
569
0
        RPCResult{
570
0
            RPCResult::Type::OBJ, "", "", MempoolEntryDescription()},
571
0
        RPCExamples{
572
0
            HelpExampleCli("getmempoolentry", "\"mytxid\"")
573
0
            + HelpExampleRpc("getmempoolentry", "\"mytxid\"")
574
0
        },
575
0
        [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
576
0
{
577
0
    auto txid{Txid::FromUint256(ParseHashV(request.params[0], "txid"))};
578
579
0
    const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
580
0
    LOCK(mempool.cs);
Line
Count
Source
259
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
581
582
0
    const auto entry{mempool.GetEntry(txid)};
583
0
    if (entry == nullptr) {
584
0
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool");
585
0
    }
586
587
0
    UniValue info(UniValue::VOBJ);
588
0
    entryToJSON(mempool, info, *entry);
589
0
    return info;
590
0
},
591
0
    };
592
0
}
593
594
static RPCHelpMan gettxspendingprevout()
595
0
{
596
0
    return RPCHelpMan{"gettxspendingprevout",
597
0
        "Scans the mempool to find transactions spending any of the given outputs",
598
0
        {
599
0
            {"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The transaction outputs that we want to check, and within each, the txid (string) vout (numeric).",
600
0
                {
601
0
                    {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
602
0
                        {
603
0
                            {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
604
0
                            {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
605
0
                        },
606
0
                    },
607
0
                },
608
0
            },
609
0
        },
610
0
        RPCResult{
611
0
            RPCResult::Type::ARR, "", "",
612
0
            {
613
0
                {RPCResult::Type::OBJ, "", "",
614
0
                {
615
0
                    {RPCResult::Type::STR_HEX, "txid", "the transaction id of the checked output"},
616
0
                    {RPCResult::Type::NUM, "vout", "the vout value of the checked output"},
617
0
                    {RPCResult::Type::STR_HEX, "spendingtxid", /*optional=*/true, "the transaction id of the mempool transaction spending this output (omitted if unspent)"},
618
0
                }},
619
0
            }
620
0
        },
621
0
        RPCExamples{
622
0
            HelpExampleCli("gettxspendingprevout", "\"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":3}]\"")
623
0
            + HelpExampleRpc("gettxspendingprevout", "\"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":3}]\"")
624
0
        },
625
0
        [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
626
0
        {
627
0
            const UniValue& output_params = request.params[0].get_array();
628
0
            if (output_params.empty()) {
629
0
                throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, outputs are missing");
630
0
            }
631
632
0
            std::vector<COutPoint> prevouts;
633
0
            prevouts.reserve(output_params.size());
634
635
0
            for (unsigned int idx = 0; idx < output_params.size(); idx++) {
636
0
                const UniValue& o = output_params[idx].get_obj();
637
638
0
                RPCTypeCheckObj(o,
639
0
                                {
640
0
                                    {"txid", UniValueType(UniValue::VSTR)},
641
0
                                    {"vout", UniValueType(UniValue::VNUM)},
642
0
                                }, /*fAllowNull=*/false, /*fStrict=*/true);
643
644
0
                const Txid txid = Txid::FromUint256(ParseHashO(o, "txid"));
645
0
                const int nOutput{o.find_value("vout").getInt<int>()};
646
0
                if (nOutput < 0) {
647
0
                    throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative");
648
0
                }
649
650
0
                prevouts.emplace_back(txid, nOutput);
651
0
            }
652
653
0
            const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
654
0
            LOCK(mempool.cs);
Line
Count
Source
259
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
655
656
0
            UniValue result{UniValue::VARR};
657
658
0
            for (const COutPoint& prevout : prevouts) {
659
0
                UniValue o(UniValue::VOBJ);
660
0
                o.pushKV("txid", prevout.hash.ToString());
661
0
                o.pushKV("vout", (uint64_t)prevout.n);
662
663
0
                const CTransaction* spendingTx = mempool.GetConflictTx(prevout);
664
0
                if (spendingTx != nullptr) {
665
0
                    o.pushKV("spendingtxid", spendingTx->GetHash().ToString());
666
0
                }
667
668
0
                result.push_back(std::move(o));
669
0
            }
670
671
0
            return result;
672
0
        },
673
0
    };
674
0
}
675
676
UniValue MempoolInfoToJSON(const CTxMemPool& pool)
677
0
{
678
    // Make sure this call is atomic in the pool.
679
0
    LOCK(pool.cs);
Line
Count
Source
259
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
680
0
    UniValue ret(UniValue::VOBJ);
681
0
    ret.pushKV("loaded", pool.GetLoadTried());
682
0
    ret.pushKV("size", (int64_t)pool.size());
683
0
    ret.pushKV("bytes", (int64_t)pool.GetTotalTxSize());
684
0
    ret.pushKV("usage", (int64_t)pool.DynamicMemoryUsage());
685
0
    ret.pushKV("total_fee", ValueFromAmount(pool.GetTotalFee()));
686
0
    ret.pushKV("maxmempool", pool.m_opts.max_size_bytes);
687
0
    ret.pushKV("mempoolminfee", ValueFromAmount(std::max(pool.GetMinFee(), pool.m_opts.min_relay_feerate).GetFeePerK()));
688
0
    ret.pushKV("minrelaytxfee", ValueFromAmount(pool.m_opts.min_relay_feerate.GetFeePerK()));
689
0
    ret.pushKV("incrementalrelayfee", ValueFromAmount(pool.m_opts.incremental_relay_feerate.GetFeePerK()));
690
0
    ret.pushKV("unbroadcastcount", uint64_t{pool.GetUnbroadcastTxs().size()});
691
0
    ret.pushKV("fullrbf", true);
692
0
    ret.pushKV("permitbaremultisig", pool.m_opts.permit_bare_multisig);
693
0
    ret.pushKV("maxdatacarriersize", pool.m_opts.max_datacarrier_bytes.value_or(0));
694
0
    return ret;
695
0
}
696
697
static RPCHelpMan getmempoolinfo()
698
0
{
699
0
    return RPCHelpMan{"getmempoolinfo",
700
0
        "Returns details on the active state of the TX memory pool.",
701
0
        {},
702
0
        RPCResult{
703
0
            RPCResult::Type::OBJ, "", "",
704
0
            {
705
0
                {RPCResult::Type::BOOL, "loaded", "True if the initial load attempt of the persisted mempool finished"},
706
0
                {RPCResult::Type::NUM, "size", "Current tx count"},
707
0
                {RPCResult::Type::NUM, "bytes", "Sum of all virtual transaction sizes as defined in BIP 141. Differs from actual serialized size because witness data is discounted"},
708
0
                {RPCResult::Type::NUM, "usage", "Total memory usage for the mempool"},
709
0
                {RPCResult::Type::STR_AMOUNT, "total_fee", "Total fees for the mempool in " + CURRENCY_UNIT + ", ignoring modified fees through prioritisetransaction"},
710
0
                {RPCResult::Type::NUM, "maxmempool", "Maximum memory usage for the mempool"},
711
0
                {RPCResult::Type::STR_AMOUNT, "mempoolminfee", "Minimum fee rate in " + CURRENCY_UNIT + "/kvB for tx to be accepted. Is the maximum of minrelaytxfee and minimum mempool fee"},
712
0
                {RPCResult::Type::STR_AMOUNT, "minrelaytxfee", "Current minimum relay fee for transactions"},
713
0
                {RPCResult::Type::NUM, "incrementalrelayfee", "minimum fee rate increment for mempool limiting or replacement in " + CURRENCY_UNIT + "/kvB"},
714
0
                {RPCResult::Type::NUM, "unbroadcastcount", "Current number of transactions that haven't passed initial broadcast yet"},
715
0
                {RPCResult::Type::BOOL, "fullrbf", "True if the mempool accepts RBF without replaceability signaling inspection (DEPRECATED)"},
716
0
                {RPCResult::Type::BOOL, "permitbaremultisig", "True if the mempool accepts transactions with bare multisig outputs"},
717
0
                {RPCResult::Type::NUM, "maxdatacarriersize", "Maximum number of bytes that can be used by OP_RETURN outputs in the mempool"},
718
0
            }},
719
0
        RPCExamples{
720
0
            HelpExampleCli("getmempoolinfo", "")
721
0
            + HelpExampleRpc("getmempoolinfo", "")
722
0
        },
723
0
        [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
724
0
{
725
0
    return MempoolInfoToJSON(EnsureAnyMemPool(request.context));
726
0
},
727
0
    };
728
0
}
729
730
static RPCHelpMan importmempool()
731
0
{
732
0
    return RPCHelpMan{
733
0
        "importmempool",
734
0
        "Import a mempool.dat file and attempt to add its contents to the mempool.\n"
735
0
        "Warning: Importing untrusted files is dangerous, especially if metadata from the file is taken over.",
736
0
        {
737
0
            {"filepath", RPCArg::Type::STR, RPCArg::Optional::NO, "The mempool file"},
738
0
            {"options",
739
0
             RPCArg::Type::OBJ_NAMED_PARAMS,
740
0
             RPCArg::Optional::OMITTED,
741
0
             "",
742
0
             {
743
0
                 {"use_current_time", RPCArg::Type::BOOL, RPCArg::Default{true},
744
0
                  "Whether to use the current system time or use the entry time metadata from the mempool file.\n"
745
0
                  "Warning: Importing untrusted metadata may lead to unexpected issues and undesirable behavior."},
746
0
                 {"apply_fee_delta_priority", RPCArg::Type::BOOL, RPCArg::Default{false},
747
0
                  "Whether to apply the fee delta metadata from the mempool file.\n"
748
0
                  "It will be added to any existing fee deltas.\n"
749
0
                  "The fee delta can be set by the prioritisetransaction RPC.\n"
750
0
                  "Warning: Importing untrusted metadata may lead to unexpected issues and undesirable behavior.\n"
751
0
                  "Only set this bool if you understand what it does."},
752
0
                 {"apply_unbroadcast_set", RPCArg::Type::BOOL, RPCArg::Default{false},
753
0
                  "Whether to apply the unbroadcast set metadata from the mempool file.\n"
754
0
                  "Warning: Importing untrusted metadata may lead to unexpected issues and undesirable behavior."},
755
0
             },
756
0
             RPCArgOptions{.oneline_description = "options"}},
757
0
        },
758
0
        RPCResult{RPCResult::Type::OBJ, "", "", std::vector<RPCResult>{}},
759
0
        RPCExamples{HelpExampleCli("importmempool", "/path/to/mempool.dat") + HelpExampleRpc("importmempool", "/path/to/mempool.dat")},
760
0
        [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue {
761
0
            const NodeContext& node{EnsureAnyNodeContext(request.context)};
762
763
0
            CTxMemPool& mempool{EnsureMemPool(node)};
764
0
            ChainstateManager& chainman = EnsureChainman(node);
765
0
            Chainstate& chainstate = chainman.ActiveChainstate();
766
767
0
            if (chainman.IsInitialBlockDownload()) {
768
0
                throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Can only import the mempool after the block download and sync is done.");
769
0
            }
770
771
0
            const fs::path load_path{fs::u8path(request.params[0].get_str())};
772
0
            const UniValue& use_current_time{request.params[1]["use_current_time"]};
773
0
            const UniValue& apply_fee_delta{request.params[1]["apply_fee_delta_priority"]};
774
0
            const UniValue& apply_unbroadcast{request.params[1]["apply_unbroadcast_set"]};
775
0
            node::ImportMempoolOptions opts{
776
0
                .use_current_time = use_current_time.isNull() ? true : use_current_time.get_bool(),
777
0
                .apply_fee_delta_priority = apply_fee_delta.isNull() ? false : apply_fee_delta.get_bool(),
778
0
                .apply_unbroadcast_set = apply_unbroadcast.isNull() ? false : apply_unbroadcast.get_bool(),
779
0
            };
780
781
0
            if (!node::LoadMempool(mempool, load_path, chainstate, std::move(opts))) {
782
0
                throw JSONRPCError(RPC_MISC_ERROR, "Unable to import mempool file, see debug.log for details.");
783
0
            }
784
785
0
            UniValue ret{UniValue::VOBJ};
786
0
            return ret;
787
0
        },
788
0
    };
789
0
}
790
791
static RPCHelpMan savemempool()
792
0
{
793
0
    return RPCHelpMan{
794
0
        "savemempool",
795
0
        "Dumps the mempool to disk. It will fail until the previous dump is fully loaded.\n",
796
0
        {},
797
0
        RPCResult{
798
0
            RPCResult::Type::OBJ, "", "",
799
0
            {
800
0
                {RPCResult::Type::STR, "filename", "the directory and file where the mempool was saved"},
801
0
            }},
802
0
        RPCExamples{
803
0
            HelpExampleCli("savemempool", "")
804
0
            + HelpExampleRpc("savemempool", "")
805
0
        },
806
0
        [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
807
0
{
808
0
    const ArgsManager& args{EnsureAnyArgsman(request.context)};
809
0
    const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
810
811
0
    if (!mempool.GetLoadTried()) {
812
0
        throw JSONRPCError(RPC_MISC_ERROR, "The mempool was not loaded yet");
813
0
    }
814
815
0
    const fs::path& dump_path = MempoolPath(args);
816
817
0
    if (!DumpMempool(mempool, dump_path)) {
818
0
        throw JSONRPCError(RPC_MISC_ERROR, "Unable to dump mempool to disk");
819
0
    }
820
821
0
    UniValue ret(UniValue::VOBJ);
822
0
    ret.pushKV("filename", dump_path.utf8string());
823
824
0
    return ret;
825
0
},
826
0
    };
827
0
}
828
829
static std::vector<RPCResult> OrphanDescription()
830
0
{
831
0
    return {
832
0
        RPCResult{RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
833
0
        RPCResult{RPCResult::Type::STR_HEX, "wtxid", "The transaction witness hash in hex"},
834
0
        RPCResult{RPCResult::Type::NUM, "bytes", "The serialized transaction size in bytes"},
835
0
        RPCResult{RPCResult::Type::NUM, "vsize", "The virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted."},
836
0
        RPCResult{RPCResult::Type::NUM, "weight", "The transaction weight as defined in BIP 141."},
837
0
        RPCResult{RPCResult::Type::ARR, "from", "",
838
0
        {
839
0
            RPCResult{RPCResult::Type::NUM, "peer_id", "Peer ID"},
840
0
        }},
841
0
    };
842
0
}
843
844
static UniValue OrphanToJSON(const node::TxOrphanage::OrphanInfo& orphan)
845
0
{
846
0
    UniValue o(UniValue::VOBJ);
847
0
    o.pushKV("txid", orphan.tx->GetHash().ToString());
848
0
    o.pushKV("wtxid", orphan.tx->GetWitnessHash().ToString());
849
0
    o.pushKV("bytes", orphan.tx->GetTotalSize());
850
0
    o.pushKV("vsize", GetVirtualTransactionSize(*orphan.tx));
851
0
    o.pushKV("weight", GetTransactionWeight(*orphan.tx));
852
0
    UniValue from(UniValue::VARR);
853
0
    for (const auto fromPeer: orphan.announcers) {
854
0
        from.push_back(fromPeer);
855
0
    }
856
0
    o.pushKV("from", from);
857
0
    return o;
858
0
}
859
860
static RPCHelpMan getorphantxs()
861
0
{
862
0
    return RPCHelpMan{
863
0
        "getorphantxs",
864
0
        "Shows transactions in the tx orphanage.\n"
865
0
        "\nEXPERIMENTAL warning: this call may be changed in future releases.\n",
866
0
        {
867
0
            {"verbosity", RPCArg::Type::NUM, RPCArg::Default{0}, "0 for an array of txids (may contain duplicates), 1 for an array of objects with tx details, and 2 for details from (1) and tx hex",
868
0
             RPCArgOptions{.skip_type_check = true}},
869
0
        },
870
0
        {
871
0
            RPCResult{"for verbose = 0",
872
0
                RPCResult::Type::ARR, "", "",
873
0
                {
874
0
                    {RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
875
0
                }},
876
0
            RPCResult{"for verbose = 1",
877
0
                RPCResult::Type::ARR, "", "",
878
0
                {
879
0
                    {RPCResult::Type::OBJ, "", "", OrphanDescription()},
880
0
                }},
881
0
            RPCResult{"for verbose = 2",
882
0
                RPCResult::Type::ARR, "", "",
883
0
                {
884
0
                    {RPCResult::Type::OBJ, "", "",
885
0
                        Cat<std::vector<RPCResult>>(
886
0
                            OrphanDescription(),
887
0
                            {{RPCResult::Type::STR_HEX, "hex", "The serialized, hex-encoded transaction data"}}
888
0
                        )
889
0
                    },
890
0
                }},
891
0
        },
892
0
        RPCExamples{
893
0
            HelpExampleCli("getorphantxs", "2")
894
0
            + HelpExampleRpc("getorphantxs", "2")
895
0
        },
896
0
        [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
897
0
        {
898
0
            const NodeContext& node = EnsureAnyNodeContext(request.context);
899
0
            PeerManager& peerman = EnsurePeerman(node);
900
0
            std::vector<node::TxOrphanage::OrphanInfo> orphanage = peerman.GetOrphanTransactions();
901
902
0
            int verbosity{ParseVerbosity(request.params[0], /*default_verbosity=*/0, /*allow_bool*/false)};
903
904
0
            UniValue ret(UniValue::VARR);
905
906
0
            if (verbosity == 0) {
907
0
                for (auto const& orphan : orphanage) {
908
0
                    ret.push_back(orphan.tx->GetHash().ToString());
909
0
                }
910
0
            } else if (verbosity == 1) {
911
0
                for (auto const& orphan : orphanage) {
912
0
                    ret.push_back(OrphanToJSON(orphan));
913
0
                }
914
0
            } else if (verbosity == 2) {
915
0
                for (auto const& orphan : orphanage) {
916
0
                    UniValue o{OrphanToJSON(orphan)};
917
0
                    o.pushKV("hex", EncodeHexTx(*orphan.tx));
918
0
                    ret.push_back(o);
919
0
                }
920
0
            } else {
921
0
                throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid verbosity value " + ToString(verbosity));
922
0
            }
923
924
0
            return ret;
925
0
        },
926
0
    };
927
0
}
928
929
static RPCHelpMan submitpackage()
930
0
{
931
0
    return RPCHelpMan{"submitpackage",
932
0
        "Submit a package of raw transactions (serialized, hex-encoded) to local node.\n"
933
0
        "The package will be validated according to consensus and mempool policy rules. If any transaction passes, it will be accepted to mempool.\n"
934
0
        "This RPC is experimental and the interface may be unstable. Refer to doc/policy/packages.md for documentation on package policies.\n"
935
0
        "Warning: successful submission does not mean the transactions will propagate throughout the network.\n"
936
0
        ,
937
0
        {
938
0
            {"package", RPCArg::Type::ARR, RPCArg::Optional::NO, "An array of raw transactions.\n"
939
0
                "The package must solely consist of a child transaction and all of its unconfirmed parents, if any. None of the parents may depend on each other.\n"
940
0
                "The package must be topologically sorted, with the child being the last element in the array.",
941
0
                {
942
0
                    {"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
943
0
                },
944
0
            },
945
0
            {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())},
946
0
             "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT +
947
0
                 "/kvB.\nFee rates larger than 1BTC/kvB are rejected.\nSet to 0 to accept any fee rate."},
948
0
            {"maxburnamount", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_BURN_AMOUNT)},
949
0
             "Reject transactions with provably unspendable outputs (e.g. 'datacarrier' outputs that use the OP_RETURN opcode) greater than the specified value, expressed in " + CURRENCY_UNIT + ".\n"
950
0
             "If burning funds through unspendable outputs is desired, increase this value.\n"
951
0
             "This check is based on heuristics and does not guarantee spendability of outputs.\n"
952
0
            },
953
0
        },
954
0
        RPCResult{
955
0
            RPCResult::Type::OBJ, "", "",
956
0
            {
957
0
                {RPCResult::Type::STR, "package_msg", "The transaction package result message. \"success\" indicates all transactions were accepted into or are already in the mempool."},
958
0
                {RPCResult::Type::OBJ_DYN, "tx-results", "transaction results keyed by wtxid",
959
0
                {
960
0
                    {RPCResult::Type::OBJ, "wtxid", "transaction wtxid", {
961
0
                        {RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
962
0
                        {RPCResult::Type::STR_HEX, "other-wtxid", /*optional=*/true, "The wtxid of a different transaction with the same txid but different witness found in the mempool. This means the submitted transaction was ignored."},
963
0
                        {RPCResult::Type::NUM, "vsize", /*optional=*/true, "Sigops-adjusted virtual transaction size."},
964
0
                        {RPCResult::Type::OBJ, "fees", /*optional=*/true, "Transaction fees", {
965
0
                            {RPCResult::Type::STR_AMOUNT, "base", "transaction fee in " + CURRENCY_UNIT},
966
0
                            {RPCResult::Type::STR_AMOUNT, "effective-feerate", /*optional=*/true, "if the transaction was not already in the mempool, the effective feerate in " + CURRENCY_UNIT + " per KvB. For example, the package feerate and/or feerate with modified fees from prioritisetransaction."},
967
0
                            {RPCResult::Type::ARR, "effective-includes", /*optional=*/true, "if effective-feerate is provided, the wtxids of the transactions whose fees and vsizes are included in effective-feerate.",
968
0
                                {{RPCResult::Type::STR_HEX, "", "transaction wtxid in hex"},
969
0
                            }},
970
0
                        }},
971
0
                        {RPCResult::Type::STR, "error", /*optional=*/true, "The transaction error string, if it was rejected by the mempool"},
972
0
                    }}
973
0
                }},
974
0
                {RPCResult::Type::ARR, "replaced-transactions", /*optional=*/true, "List of txids of replaced transactions",
975
0
                {
976
0
                    {RPCResult::Type::STR_HEX, "", "The transaction id"},
977
0
                }},
978
0
            },
979
0
        },
980
0
        RPCExamples{
981
0
            HelpExampleRpc("submitpackage", R"(["raw-parent-tx-1", "raw-parent-tx-2", "raw-child-tx"])") +
982
0
            HelpExampleCli("submitpackage", R"('["raw-tx-without-unconfirmed-parents"]')")
983
0
        },
984
0
        [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
985
0
        {
986
0
            const UniValue raw_transactions = request.params[0].get_array();
987
0
            if (raw_transactions.empty() || raw_transactions.size() > MAX_PACKAGE_COUNT) {
988
0
                throw JSONRPCError(RPC_INVALID_PARAMETER,
989
0
                                   "Array must contain between 1 and " + ToString(MAX_PACKAGE_COUNT) + " transactions.");
990
0
            }
991
992
            // Fee check needs to be run with chainstate and package context
993
0
            const CFeeRate max_raw_tx_fee_rate{ParseFeeRate(self.Arg<UniValue>("maxfeerate"))};
994
0
            std::optional<CFeeRate> client_maxfeerate{max_raw_tx_fee_rate};
995
            // 0-value is special; it's mapped to no sanity check
996
0
            if (max_raw_tx_fee_rate == CFeeRate(0)) {
997
0
                client_maxfeerate = std::nullopt;
998
0
            }
999
1000
            // Burn sanity check is run with no context
1001
0
            const CAmount max_burn_amount = request.params[2].isNull() ? 0 : AmountFromValue(request.params[2]);
1002
1003
0
            std::vector<CTransactionRef> txns;
1004
0
            txns.reserve(raw_transactions.size());
1005
0
            for (const auto& rawtx : raw_transactions.getValues()) {
1006
0
                CMutableTransaction mtx;
1007
0
                if (!DecodeHexTx(mtx, rawtx.get_str())) {
1008
0
                    throw JSONRPCError(RPC_DESERIALIZATION_ERROR,
1009
0
                                       "TX decode failed: " + rawtx.get_str() + " Make sure the tx has at least one input.");
1010
0
                }
1011
1012
0
                for (const auto& out : mtx.vout) {
1013
0
                    if((out.scriptPubKey.IsUnspendable() || !out.scriptPubKey.HasValidOps()) && out.nValue > max_burn_amount) {
1014
0
                        throw JSONRPCTransactionError(TransactionError::MAX_BURN_EXCEEDED);
1015
0
                    }
1016
0
                }
1017
1018
0
                txns.emplace_back(MakeTransactionRef(std::move(mtx)));
1019
0
            }
1020
0
            CHECK_NONFATAL(!txns.empty());
Line
Count
Source
103
0
    inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition)
1021
0
            if (txns.size() > 1 && !IsChildWithParentsTree(txns)) {
1022
0
                throw JSONRPCTransactionError(TransactionError::INVALID_PACKAGE, "package topology disallowed. not child-with-parents or parents depend on each other.");
1023
0
            }
1024
1025
0
            NodeContext& node = EnsureAnyNodeContext(request.context);
1026
0
            CTxMemPool& mempool = EnsureMemPool(node);
1027
0
            Chainstate& chainstate = EnsureChainman(node).ActiveChainstate();
1028
0
            const auto package_result = WITH_LOCK(::cs_main, return ProcessNewPackage(chainstate, mempool, txns, /*test_accept=*/ false, client_maxfeerate));
Line
Count
Source
290
0
#define WITH_LOCK(cs, code) (MaybeCheckNotHeld(cs), [&]() -> decltype(auto) { LOCK(cs); code; }())
1029
1030
0
            std::string package_msg = "success";
1031
1032
            // First catch package-wide errors, continue if we can
1033
0
            switch(package_result.m_state.GetResult()) {
1034
0
                case PackageValidationResult::PCKG_RESULT_UNSET:
1035
0
                {
1036
                    // Belt-and-suspenders check; everything should be successful here
1037
0
                    CHECK_NONFATAL(package_result.m_tx_results.size() == txns.size());
Line
Count
Source
103
0
    inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition)
1038
0
                    for (const auto& tx : txns) {
1039
0
                        CHECK_NONFATAL(mempool.exists(tx->GetHash()));
Line
Count
Source
103
0
    inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition)
1040
0
                    }
1041
0
                    break;
1042
0
                }
1043
0
                case PackageValidationResult::PCKG_MEMPOOL_ERROR:
1044
0
                {
1045
                    // This only happens with internal bug; user should stop and report
1046
0
                    throw JSONRPCTransactionError(TransactionError::MEMPOOL_ERROR,
1047
0
                        package_result.m_state.GetRejectReason());
1048
0
                }
1049
0
                case PackageValidationResult::PCKG_POLICY:
1050
0
                case PackageValidationResult::PCKG_TX:
1051
0
                {
1052
                    // Package-wide error we want to return, but we also want to return individual responses
1053
0
                    package_msg = package_result.m_state.ToString();
1054
0
                    CHECK_NONFATAL(package_result.m_tx_results.size() == txns.size() ||
Line
Count
Source
103
0
    inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition)
1055
0
                            package_result.m_tx_results.empty());
1056
0
                    break;
1057
0
                }
1058
0
            }
1059
1060
0
            size_t num_broadcast{0};
1061
0
            for (const auto& tx : txns) {
1062
                // We don't want to re-submit the txn for validation in BroadcastTransaction
1063
0
                if (!mempool.exists(tx->GetHash())) {
1064
0
                    continue;
1065
0
                }
1066
1067
                // We do not expect an error here; we are only broadcasting things already/still in mempool
1068
0
                std::string err_string;
1069
0
                const auto err = BroadcastTransaction(node, tx, err_string, /*max_tx_fee=*/0, /*relay=*/true, /*wait_callback=*/true);
1070
0
                if (err != TransactionError::OK) {
1071
0
                    throw JSONRPCTransactionError(err,
1072
0
                        strprintf("transaction broadcast failed: %s (%d transactions were broadcast successfully)",
Line
Count
Source
1172
0
#define strprintf tfm::format
1073
0
                            err_string, num_broadcast));
1074
0
                }
1075
0
                num_broadcast++;
1076
0
            }
1077
1078
0
            UniValue rpc_result{UniValue::VOBJ};
1079
0
            rpc_result.pushKV("package_msg", package_msg);
1080
0
            UniValue tx_result_map{UniValue::VOBJ};
1081
0
            std::set<Txid> replaced_txids;
1082
0
            for (const auto& tx : txns) {
1083
0
                UniValue result_inner{UniValue::VOBJ};
1084
0
                result_inner.pushKV("txid", tx->GetHash().GetHex());
1085
0
                auto it = package_result.m_tx_results.find(tx->GetWitnessHash());
1086
0
                if (it == package_result.m_tx_results.end()) {
1087
                    // No results, report error and continue
1088
0
                    result_inner.pushKV("error", "unevaluated");
1089
0
                    continue;
1090
0
                }
1091
0
                const auto& tx_result = it->second;
1092
0
                switch(it->second.m_result_type) {
1093
0
                case MempoolAcceptResult::ResultType::DIFFERENT_WITNESS:
1094
0
                    result_inner.pushKV("other-wtxid", it->second.m_other_wtxid.value().GetHex());
1095
0
                    break;
1096
0
                case MempoolAcceptResult::ResultType::INVALID:
1097
0
                    result_inner.pushKV("error", it->second.m_state.ToString());
1098
0
                    break;
1099
0
                case MempoolAcceptResult::ResultType::VALID:
1100
0
                case MempoolAcceptResult::ResultType::MEMPOOL_ENTRY:
1101
0
                    result_inner.pushKV("vsize", int64_t{it->second.m_vsize.value()});
1102
0
                    UniValue fees(UniValue::VOBJ);
1103
0
                    fees.pushKV("base", ValueFromAmount(it->second.m_base_fees.value()));
1104
0
                    if (tx_result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
1105
                        // Effective feerate is not provided for MEMPOOL_ENTRY transactions even
1106
                        // though modified fees is known, because it is unknown whether package
1107
                        // feerate was used when it was originally submitted.
1108
0
                        fees.pushKV("effective-feerate", ValueFromAmount(tx_result.m_effective_feerate.value().GetFeePerK()));
1109
0
                        UniValue effective_includes_res(UniValue::VARR);
1110
0
                        for (const auto& wtxid : tx_result.m_wtxids_fee_calculations.value()) {
1111
0
                            effective_includes_res.push_back(wtxid.ToString());
1112
0
                        }
1113
0
                        fees.pushKV("effective-includes", std::move(effective_includes_res));
1114
0
                    }
1115
0
                    result_inner.pushKV("fees", std::move(fees));
1116
0
                    for (const auto& ptx : it->second.m_replaced_transactions) {
1117
0
                        replaced_txids.insert(ptx->GetHash());
1118
0
                    }
1119
0
                    break;
1120
0
                }
1121
0
                tx_result_map.pushKV(tx->GetWitnessHash().GetHex(), std::move(result_inner));
1122
0
            }
1123
0
            rpc_result.pushKV("tx-results", std::move(tx_result_map));
1124
0
            UniValue replaced_list(UniValue::VARR);
1125
0
            for (const auto& txid : replaced_txids) replaced_list.push_back(txid.ToString());
1126
0
            rpc_result.pushKV("replaced-transactions", std::move(replaced_list));
1127
0
            return rpc_result;
1128
0
        },
1129
0
    };
1130
0
}
1131
1132
void RegisterMempoolRPCCommands(CRPCTable& t)
1133
38.8k
{
1134
38.8k
    static const CRPCCommand commands[]{
1135
38.8k
        {"rawtransactions", &sendrawtransaction},
1136
38.8k
        {"rawtransactions", &testmempoolaccept},
1137
38.8k
        {"blockchain", &getmempoolancestors},
1138
38.8k
        {"blockchain", &getmempooldescendants},
1139
38.8k
        {"blockchain", &getmempoolentry},
1140
38.8k
        {"blockchain", &gettxspendingprevout},
1141
38.8k
        {"blockchain", &getmempoolinfo},
1142
38.8k
        {"blockchain", &getrawmempool},
1143
38.8k
        {"blockchain", &importmempool},
1144
38.8k
        {"blockchain", &savemempool},
1145
38.8k
        {"hidden", &getorphantxs},
1146
38.8k
        {"rawtransactions", &submitpackage},
1147
38.8k
    };
1148
466k
    for (const auto& c : commands) {
1149
466k
        t.appendCommand(c.name, &c);
1150
466k
    }
1151
38.8k
}