Coverage Report

Created: 2026-09-02 14:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/tmp/bitcoin/src/rpc/mempool.cpp
Line
Count
Source
1
// Copyright (c) 2010 Satoshi Nakamoto
2
// Copyright (c) 2009-present 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 <common/args.h>
12
#include <consensus/validation.h>
13
#include <core_io.h>
14
#include <index/txospenderindex.h>
15
#include <kernel/mempool_entry.h>
16
#include <net_processing.h>
17
#include <netbase.h>
18
#include <node/mempool_persist_args.h>
19
#include <node/types.h>
20
#include <policy/rbf.h>
21
#include <policy/settings.h>
22
#include <primitives/transaction.h>
23
#include <rpc/server.h>
24
#include <rpc/server_util.h>
25
#include <rpc/util.h>
26
#include <txmempool.h>
27
#include <univalue.h>
28
#include <util/fs.h>
29
#include <util/moneystr.h>
30
#include <util/strencodings.h>
31
#include <util/time.h>
32
#include <util/vector.h>
33
34
#include <map>
35
#include <ranges>
36
#include <string_view>
37
#include <utility>
38
39
using node::DumpMempool;
40
41
using node::DEFAULT_MAX_BURN_AMOUNT;
42
using node::DEFAULT_MAX_RAW_TX_FEE_RATE;
43
using node::MempoolPath;
44
using node::NodeContext;
45
using node::TransactionError;
46
using util::ToString;
47
48
static RPCMethod sendrawtransaction()
49
38.5k
{
50
38.5k
    return RPCMethod{
51
38.5k
        "sendrawtransaction",
52
38.5k
        "Submit a raw transaction (serialized, hex-encoded) to the network.\n"
53
54
38.5k
        "\nIf -privatebroadcast is disabled, then the transaction will be put into the\n"
55
38.5k
        "local mempool of the node and will be sent unconditionally to all currently\n"
56
38.5k
        "connected peers, so using sendrawtransaction for manual rebroadcast will degrade\n"
57
38.5k
        "privacy by leaking the transaction's origin, as nodes will normally not\n"
58
38.5k
        "rebroadcast non-wallet transactions already in their mempool.\n"
59
60
38.5k
        "\nIf -privatebroadcast is enabled, then the transaction will be sent only via\n"
61
38.5k
        "dedicated, short-lived connections to Tor or I2P peers or IPv4/IPv6 peers\n"
62
38.5k
        "via the Tor network. This conceals the transaction's origin. The transaction\n"
63
38.5k
        "will only enter the local mempool when it is received back from the network.\n"
64
38.5k
        "The private broadcast queue is bounded: when it is full, this RPC fails and\n"
65
38.5k
        "the transaction is not scheduled, until an existing one completes or is\n"
66
38.5k
        "aborted. Use getprivatebroadcastinfo to inspect the queue and abortprivatebroadcast to abort.\n"
67
68
38.5k
        "\nA specific exception, RPC_TRANSACTION_ALREADY_IN_UTXO_SET, may throw if the transaction cannot be added to the mempool.\n"
69
70
38.5k
        "\nRelated RPCs: createrawtransaction, signrawtransactionwithkey\n",
71
38.5k
        {
72
38.5k
            {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"},
73
38.5k
            {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())},
74
38.5k
             "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT +
75
38.5k
                 "/kvB.\nFee rates larger than 1BTC/kvB are rejected.\nSet to 0 to accept any fee rate."},
76
38.5k
            {"maxburnamount", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_BURN_AMOUNT)},
77
38.5k
             "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"
78
38.5k
             "If burning funds through unspendable outputs is desired, increase this value.\n"
79
38.5k
             "This check is based on heuristics and does not guarantee spendability of outputs.\n"},
80
38.5k
        },
81
38.5k
        RPCResult{
82
38.5k
            RPCResult::Type::STR_HEX, "", "The transaction hash in hex"
83
38.5k
        },
84
38.5k
        RPCExamples{
85
38.5k
            "\nCreate a transaction\n"
86
38.5k
            + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") +
87
38.5k
            "Sign the transaction, and get back the hex\n"
88
38.5k
            + HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") +
89
38.5k
            "\nSend the transaction (signed hex)\n"
90
38.5k
            + HelpExampleCli("sendrawtransaction", "\"signedhex\"") +
91
38.5k
            "\nAs a JSON-RPC call\n"
92
38.5k
            + HelpExampleRpc("sendrawtransaction", "\"signedhex\"")
93
38.5k
                },
94
38.5k
        [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
95
38.5k
        {
96
36.0k
            const CAmount max_burn_amount = request.params[2].isNull() ? 0 : AmountFromValue(request.params[2]);
97
98
36.0k
            CMutableTransaction mtx;
99
36.0k
            if (!DecodeHexTx(mtx, request.params[0].get_str())) {
100
142
                throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input.");
101
142
            }
102
103
71.7k
            for (const auto& out : mtx.vout) {
104
71.7k
                if((out.scriptPubKey.IsUnspendable() || !out.scriptPubKey.HasValidOps()) && out.nValue > max_burn_amount) {
105
4
                    throw JSONRPCTransactionError(TransactionError::MAX_BURN_EXCEEDED);
106
4
                }
107
71.7k
            }
108
109
35.9k
            CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
110
111
35.9k
            const CFeeRate max_raw_tx_fee_rate{ParseFeeRate(self.Arg<UniValue>("maxfeerate"))};
112
113
35.9k
            int64_t virtual_size = GetVirtualTransactionSize(*tx);
114
35.9k
            CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size);
115
116
35.9k
            std::string err_string;
117
35.9k
            AssertLockNotHeld(cs_main);
118
35.9k
            NodeContext& node = EnsureAnyNodeContext(request.context);
119
35.9k
            const bool private_broadcast_enabled{gArgs.GetBoolArg("-privatebroadcast", DEFAULT_PRIVATE_BROADCAST)};
120
35.9k
            if (private_broadcast_enabled &&
121
35.9k
                !g_reachable_nets.Contains(NET_ONION) &&
122
35.9k
                !g_reachable_nets.Contains(NET_I2P)) {
123
1
                throw JSONRPCError(RPC_MISC_ERROR,
124
1
                                   "-privatebroadcast is enabled, but none of the Tor or I2P networks is "
125
1
                                   "reachable. Maybe the location of the Tor proxy couldn't be retrieved "
126
1
                                   "from the Tor daemon at startup. Check whether the Tor daemon is running "
127
1
                                   "and that -torcontrol, -torpassword and -i2psam are configured properly.");
128
1
            }
129
35.9k
            const auto method = private_broadcast_enabled ? node::TxBroadcast::NO_MEMPOOL_PRIVATE_BROADCAST
130
35.9k
                                                          : node::TxBroadcast::MEMPOOL_AND_BROADCAST_TO_ALL;
131
35.9k
            const TransactionError err = BroadcastTransaction(node,
132
35.9k
                                                              tx,
133
35.9k
                                                              err_string,
134
35.9k
                                                              max_raw_tx_fee,
135
35.9k
                                                              method,
136
35.9k
                                                              /*wait_callback=*/true);
137
35.9k
            if (TransactionError::OK != err) {
138
4.42k
                throw JSONRPCTransactionError(err, err_string);
139
4.42k
            }
140
141
31.5k
            return tx->GetHash().GetHex();
142
35.9k
        },
143
38.5k
    };
144
38.5k
}
145
146
static RPCMethod getprivatebroadcastinfo()
147
2.46k
{
148
2.46k
    return RPCMethod{
149
2.46k
        "getprivatebroadcastinfo",
150
2.46k
        "Returns information about transactions tracked for private broadcast.\n"
151
2.46k
        "Transactions that have reached the send-attempt limit remain in the result with attempts_remaining=0.\n"
152
2.46k
        "This method is only available when running with -privatebroadcast enabled.\n",
153
2.46k
        {},
154
2.46k
        RPCResult{
155
2.46k
            RPCResult::Type::OBJ, "", "",
156
2.46k
            {
157
2.46k
                {RPCResult::Type::ARR, "transactions", "",
158
2.46k
                    {
159
2.46k
                        {RPCResult::Type::OBJ, "", "",
160
2.46k
                            {
161
2.46k
                                {RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
162
2.46k
                                {RPCResult::Type::STR_HEX, "wtxid", "The transaction witness hash in hex"},
163
2.46k
                                {RPCResult::Type::STR_HEX, "hex", "The serialized, hex-encoded transaction data"},
164
2.46k
                                {RPCResult::Type::NUM_TIME, "time_added", "The time this transaction was added to the private broadcast queue (seconds since epoch)"},
165
2.46k
                                {RPCResult::Type::NUM, "attempts_remaining", "The number of additional private broadcast send attempts allowed for this transaction"},
166
2.46k
                                {RPCResult::Type::ARR, "peers", "Per-peer send and acknowledgment information for this transaction",
167
2.46k
                                    {
168
2.46k
                                        {RPCResult::Type::OBJ, "", "",
169
2.46k
                                            {
170
2.46k
                                                {RPCResult::Type::STR, "address", "The address of the peer to which the transaction was sent"},
171
2.46k
                                                {RPCResult::Type::NUM_TIME, "sent", "The time this transaction was picked for sending to this peer via private broadcast (seconds since epoch)"},
172
2.46k
                                                {RPCResult::Type::NUM_TIME, "received", /*optional=*/true, "The time this peer acknowledged reception of the transaction (seconds since epoch)"},
173
2.46k
                                            }},
174
2.46k
                                    }},
175
2.46k
                            }},
176
2.46k
                    }},
177
2.46k
            }},
178
2.46k
        RPCExamples{
179
2.46k
            HelpExampleCli("getprivatebroadcastinfo", "")
180
2.46k
            + HelpExampleRpc("getprivatebroadcastinfo", "")
181
2.46k
        },
182
2.46k
        [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
183
2.46k
        {
184
13
            const NodeContext& node{EnsureAnyNodeContext(request.context)};
185
13
            const PeerManager& peerman{EnsurePeerman(node)};
186
13
            if (!peerman.GetInfo().private_broadcast) {
187
1
                throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Private broadcast is not enabled. Ensure you're running Bitcoin Core with -privatebroadcast=1.");
188
1
            }
189
190
12
            const auto txs{peerman.GetPrivateBroadcastInfo()};
191
192
12
            UniValue transactions(UniValue::VARR);
193
50.0k
            for (const auto& tx_info : txs) {
194
50.0k
                UniValue o(UniValue::VOBJ);
195
50.0k
                o.pushKV("txid", tx_info.tx->GetHash().ToString());
196
50.0k
                o.pushKV("wtxid", tx_info.tx->GetWitnessHash().ToString());
197
50.0k
                o.pushKV("hex", EncodeHexTx(*tx_info.tx));
198
50.0k
                o.pushKV("time_added", TicksSinceEpoch<std::chrono::seconds>(tx_info.time_added));
199
50.0k
                o.pushKV("attempts_remaining", tx_info.attempts_remaining);
200
50.0k
                UniValue peers(UniValue::VARR);
201
50.0k
                for (const auto& peer : tx_info.peers) {
202
24
                    UniValue p(UniValue::VOBJ);
203
24
                    p.pushKV("address", peer.address.ToStringAddrPort());
204
24
                    p.pushKV("sent", TicksSinceEpoch<std::chrono::seconds>(peer.sent));
205
24
                    if (peer.received.has_value()) {
206
24
                        p.pushKV("received", TicksSinceEpoch<std::chrono::seconds>(*peer.received));
207
24
                    }
208
24
                    peers.push_back(std::move(p));
209
24
                }
210
50.0k
                o.pushKV("peers", std::move(peers));
211
50.0k
                transactions.push_back(std::move(o));
212
50.0k
            }
213
214
12
            UniValue ret(UniValue::VOBJ);
215
12
            ret.pushKV("transactions", std::move(transactions));
216
12
            return ret;
217
13
        },
218
2.46k
    };
219
2.46k
}
220
221
static RPCMethod abortprivatebroadcast()
222
2.45k
{
223
2.45k
    return RPCMethod{
224
2.45k
        "abortprivatebroadcast",
225
2.45k
        "Abort private broadcast attempts for a transaction currently being privately broadcast.\n"
226
2.45k
        "The transaction will be removed from the private broadcast queue.\n"
227
2.45k
        "This method is only available when running with -privatebroadcast enabled.\n",
228
2.45k
        {
229
2.45k
            {"id", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "A transaction identifier to abort. It will be matched against both txid and wtxid for all transactions in the private broadcast queue.\n"
230
2.45k
                                                                "If the provided id matches a txid that corresponds to multiple transactions with different wtxids, multiple transactions will be removed and returned."},
231
2.45k
        },
232
2.45k
        RPCResult{
233
2.45k
            RPCResult::Type::OBJ, "", "",
234
2.45k
            {
235
2.45k
                {RPCResult::Type::ARR, "removed_transactions", "Transactions removed from the private broadcast queue",
236
2.45k
                    {
237
2.45k
                        {RPCResult::Type::OBJ, "", "",
238
2.45k
                            {
239
2.45k
                                {RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
240
2.45k
                                {RPCResult::Type::STR_HEX, "wtxid", "The transaction witness hash in hex"},
241
2.45k
                                {RPCResult::Type::STR_HEX, "hex", "The serialized, hex-encoded transaction data"},
242
2.45k
                            }},
243
2.45k
                    }},
244
2.45k
            }
245
2.45k
        },
246
2.45k
        RPCExamples{
247
2.45k
            HelpExampleCli("abortprivatebroadcast", "\"id\"")
248
2.45k
            + HelpExampleRpc("abortprivatebroadcast", "\"id\"")
249
2.45k
        },
250
2.45k
        [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
251
2.45k
        {
252
253
4
            const NodeContext& node{EnsureAnyNodeContext(request.context)};
254
4
            PeerManager& peerman{EnsurePeerman(node)};
255
4
            if (!peerman.GetInfo().private_broadcast) {
256
1
                throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Private broadcast is not enabled. Ensure you're running Bitcoin Core with -privatebroadcast=1.");
257
1
            }
258
259
3
            const uint256 id{ParseHashV(self.Arg<UniValue>("id"), "id")};
260
261
3
            const auto removed_txs{peerman.AbortPrivateBroadcast(id)};
262
3
            if (removed_txs.empty()) {
263
1
                throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in private broadcast queue. Check getprivatebroadcastinfo.");
264
1
            }
265
266
2
            UniValue removed_transactions(UniValue::VARR);
267
2
            for (const auto& tx : removed_txs) {
268
2
                UniValue o(UniValue::VOBJ);
269
2
                o.pushKV("txid", tx->GetHash().ToString());
270
2
                o.pushKV("wtxid", tx->GetWitnessHash().ToString());
271
2
                o.pushKV("hex", EncodeHexTx(*tx));
272
2
                removed_transactions.push_back(std::move(o));
273
2
            }
274
2
            UniValue ret(UniValue::VOBJ);
275
2
            ret.pushKV("removed_transactions", std::move(removed_transactions));
276
2
            return ret;
277
3
        },
278
2.45k
    };
279
2.45k
}
280
281
static RPCMethod testmempoolaccept()
282
3.87k
{
283
3.87k
    return RPCMethod{
284
3.87k
        "testmempoolaccept",
285
3.87k
        "Returns result of mempool acceptance tests indicating if raw transaction(s) (serialized, hex-encoded) would be accepted by mempool.\n"
286
3.87k
        "\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"
287
3.87k
        "\nIf one transaction fails, other transactions may not be fully validated (the 'allowed' key will be blank).\n"
288
3.87k
        "\nThe maximum number of transactions allowed is " + ToString(MAX_PACKAGE_COUNT) + ".\n"
289
3.87k
        "\nThis checks if transactions violate the consensus or policy rules.\n"
290
3.87k
        "\nSee sendrawtransaction call.\n",
291
3.87k
        {
292
3.87k
            {"rawtxs", RPCArg::Type::ARR, RPCArg::Optional::NO, "An array of hex strings of raw transactions.",
293
3.87k
                {
294
3.87k
                    {"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
295
3.87k
                },
296
3.87k
            },
297
3.87k
            {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())},
298
3.87k
             "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT +
299
3.87k
                 "/kvB.\nFee rates larger than 1BTC/kvB are rejected.\nSet to 0 to accept any fee rate."},
300
3.87k
        },
301
3.87k
        RPCResult{
302
3.87k
            RPCResult::Type::ARR, "", "The result of the mempool acceptance test for each raw transaction in the input array.\n"
303
3.87k
                                      "Returns results for each transaction in the same order they were passed in.\n"
304
3.87k
                                      "Transactions that cannot be fully validated due to failures in other transactions will not contain an 'allowed' result.\n",
305
3.87k
            {
306
3.87k
                {RPCResult::Type::OBJ, "", "",
307
3.87k
                {
308
3.87k
                    {RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
309
3.87k
                    {RPCResult::Type::STR_HEX, "wtxid", "The transaction witness hash in hex"},
310
3.87k
                    {RPCResult::Type::STR, "package-error", /*optional=*/true, "Package validation error, if any (only possible if rawtxs had more than 1 transaction)."},
311
3.87k
                    {RPCResult::Type::BOOL, "allowed", /*optional=*/true, "Whether this tx would be accepted to the mempool and pass client-specified maxfeerate. "
312
3.87k
                                                       "If not present, the tx was not fully validated due to a failure in another tx in the list."},
313
3.87k
                    {RPCResult::Type::NUM, "vsize_adjusted", /*optional=*/true, "Maximum of sigop-adjusted size (-bytespersigop) and virtual transaction size as defined in BIP 141 (only present when 'allowed' is true)."},
314
3.87k
                    {RPCResult::Type::NUM, "vsize", /*optional=*/true, "(DEPRECATED) Was previously erroneously described as the BIP 141 vsize, but is actually sigops-adjusted vsize.\n"
315
3.87k
                                                                "Use vsize_bip141 to actually get that behavior or switch to the explicit vsize_adjusted for retained behavior."},
316
3.87k
                    {RPCResult::Type::NUM, "vsize_bip141", /*optional=*/true, "Virtual transaction size as defined in BIP 141.\n"
317
3.87k
                                                                       "This is different from actual serialized size for witness transactions as witness data is discounted (only present when 'allowed' is true)."},
318
3.87k
                    {RPCResult::Type::OBJ, "fees", /*optional=*/true, "Transaction fees (only present if 'allowed' is true)",
319
3.87k
                    {
320
3.87k
                        {RPCResult::Type::STR_AMOUNT, "base", "transaction fee in " + CURRENCY_UNIT},
321
3.87k
                        {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."},
322
3.87k
                        {RPCResult::Type::ARR, "effective-includes", /*optional=*/false, "transactions whose fees and vsizes are included in effective-feerate.",
323
3.87k
                            {RPCResult{RPCResult::Type::STR_HEX, "", "transaction wtxid in hex"},
324
3.87k
                        }},
325
3.87k
                    }},
326
3.87k
                    {RPCResult::Type::STR, "reject-reason", /*optional=*/true, "Rejection reason (only present when 'allowed' is false)"},
327
3.87k
                    {RPCResult::Type::STR, "reject-details", /*optional=*/true, "Rejection details (only present when 'allowed' is false and rejection details exist)"},
328
3.87k
                }},
329
3.87k
            }
330
3.87k
        },
331
3.87k
        RPCExamples{
332
3.87k
            "\nCreate a transaction\n"
333
3.87k
            + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") +
334
3.87k
            "Sign the transaction, and get back the hex\n"
335
3.87k
            + HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") +
336
3.87k
            "\nTest acceptance of the transaction (signed hex)\n"
337
3.87k
            + HelpExampleCli("testmempoolaccept", R"('["signedhex"]')") +
338
3.87k
            "\nAs a JSON-RPC call\n"
339
3.87k
            + HelpExampleRpc("testmempoolaccept", "[\"signedhex\"]")
340
3.87k
                },
341
3.87k
        [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
342
3.87k
        {
343
1.42k
            const UniValue raw_transactions = request.params[0].get_array();
344
1.42k
            if (raw_transactions.size() < 1 || raw_transactions.size() > MAX_PACKAGE_COUNT) {
345
2
                throw JSONRPCError(RPC_INVALID_PARAMETER,
346
2
                                   "Array must contain between 1 and " + ToString(MAX_PACKAGE_COUNT) + " transactions.");
347
2
            }
348
349
1.42k
            const CFeeRate max_raw_tx_fee_rate{ParseFeeRate(self.Arg<UniValue>("maxfeerate"))};
350
351
1.42k
            std::vector<CTransactionRef> txns;
352
1.42k
            txns.reserve(raw_transactions.size());
353
2.00k
            for (const auto& rawtx : raw_transactions.getValues()) {
354
2.00k
                CMutableTransaction mtx;
355
2.00k
                if (!DecodeHexTx(mtx, rawtx.get_str())) {
356
1
                    throw JSONRPCError(RPC_DESERIALIZATION_ERROR,
357
1
                                       "TX decode failed: " + rawtx.get_str() + " Make sure the tx has at least one input.");
358
1
                }
359
2.00k
                txns.emplace_back(MakeTransactionRef(std::move(mtx)));
360
2.00k
            }
361
362
1.42k
            NodeContext& node = EnsureAnyNodeContext(request.context);
363
1.42k
            CTxMemPool& mempool = EnsureMemPool(node);
364
1.42k
            ChainstateManager& chainman = EnsureChainman(node);
365
1.42k
            Chainstate& chainstate = chainman.ActiveChainstate();
366
1.42k
            const PackageMempoolAcceptResult package_result = [&] {
367
1.41k
                LOCK(::cs_main);
368
1.41k
                if (txns.size() > 1) return ProcessNewPackage(chainstate, mempool, txns, /*test_accept=*/true, /*client_maxfeerate=*/{});
369
1.34k
                return PackageMempoolAcceptResult(txns[0]->GetWitnessHash(),
370
1.34k
                                                  chainman.ProcessTransaction(txns[0], /*test_accept=*/true));
371
1.41k
            }();
372
373
1.42k
            UniValue rpc_result(UniValue::VARR);
374
            // We will check transaction fees while we iterate through txns in order. If any transaction fee
375
            // exceeds maxfeerate, we will leave the rest of the validation results blank, because it
376
            // doesn't make sense to return a validation result for a transaction if its ancestor(s) would
377
            // not be submitted.
378
1.42k
            bool exit_early{false};
379
2.00k
            for (const auto& tx : txns) {
380
2.00k
                UniValue result_inner(UniValue::VOBJ);
381
2.00k
                result_inner.pushKV("txid", tx->GetHash().GetHex());
382
2.00k
                result_inner.pushKV("wtxid", tx->GetWitnessHash().GetHex());
383
2.00k
                if (package_result.m_state.GetResult() == PackageValidationResult::PCKG_POLICY) {
384
99
                    result_inner.pushKV("package-error", package_result.m_state.ToString());
385
99
                }
386
2.00k
                auto it = package_result.m_tx_results.find(tx->GetWitnessHash());
387
2.00k
                if (exit_early || it == package_result.m_tx_results.end()) {
388
                    // Validation unfinished. Just return the txid and wtxid.
389
139
                    rpc_result.push_back(std::move(result_inner));
390
139
                    continue;
391
139
                }
392
1.86k
                const auto& tx_result = it->second;
393
                // Package testmempoolaccept doesn't allow transactions to already be in the mempool.
394
1.86k
                CHECK_NONFATAL(tx_result.m_result_type != MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
395
1.86k
                if (tx_result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
396
1.61k
                    const CAmount fee = tx_result.m_base_fees.value();
397
                    // Check that fee does not exceed maximum fee
398
1.61k
                    const int64_t virtual_size = tx_result.m_vsize.value();
399
1.61k
                    const CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size);
400
1.61k
                    if (max_raw_tx_fee && fee > max_raw_tx_fee) {
401
4
                        result_inner.pushKV("allowed", false);
402
4
                        result_inner.pushKV("reject-reason", "max-fee-exceeded");
403
4
                        exit_early = true;
404
1.61k
                    } else {
405
                        // Only return the fee and vsize if the transaction would pass ATMP.
406
                        // These can be used to calculate the feerate.
407
1.61k
                        result_inner.pushKV("allowed", true);
408
1.61k
                        result_inner.pushKV("vsize_adjusted", virtual_size);
409
1.61k
                        result_inner.pushKV("vsize", virtual_size);
410
1.61k
                        result_inner.pushKV("vsize_bip141", GetVirtualTransactionSize(*tx));
411
1.61k
                        UniValue fees(UniValue::VOBJ);
412
1.61k
                        fees.pushKV("base", ValueFromAmount(fee));
413
1.61k
                        fees.pushKV("effective-feerate", ValueFromAmount(tx_result.m_effective_feerate.value().GetFeePerK()));
414
1.61k
                        UniValue effective_includes_res(UniValue::VARR);
415
1.61k
                        for (const auto& wtxid : tx_result.m_wtxids_fee_calculations.value()) {
416
1.61k
                            effective_includes_res.push_back(wtxid.ToString());
417
1.61k
                        }
418
1.61k
                        fees.pushKV("effective-includes", std::move(effective_includes_res));
419
1.61k
                        result_inner.pushKV("fees", std::move(fees));
420
1.61k
                    }
421
1.61k
                } else {
422
249
                    result_inner.pushKV("allowed", false);
423
249
                    const TxValidationState state = tx_result.m_state;
424
249
                    if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
425
116
                        result_inner.pushKV("reject-reason", "missing-inputs");
426
133
                    } else {
427
133
                        result_inner.pushKV("reject-reason", state.GetRejectReason());
428
133
                        result_inner.pushKV("reject-details", state.ToString());
429
133
                    }
430
249
                }
431
1.86k
                rpc_result.push_back(std::move(result_inner));
432
1.86k
            }
433
1.42k
            return rpc_result;
434
1.42k
        },
435
3.87k
    };
436
3.87k
}
437
438
static std::vector<RPCResult> ClusterDescription()
439
3.59k
{
440
3.59k
    return {
441
3.59k
        RPCResult{RPCResult::Type::NUM, "clusterweight", "total sigops-adjusted weight (as defined in BIP 141 and modified by '-bytespersigop')"},
442
3.59k
        RPCResult{RPCResult::Type::NUM, "txcount", "number of transactions"},
443
3.59k
        RPCResult{RPCResult::Type::ARR, "chunks", "chunks in this cluster (in mining order)",
444
3.59k
            {RPCResult{RPCResult::Type::OBJ, "chunk", "",
445
3.59k
                {
446
3.59k
                    RPCResult{RPCResult::Type::NUM, "chunkfee", "fees of the transactions in this chunk"},
447
3.59k
                    RPCResult{RPCResult::Type::NUM, "chunkweight", "sigops-adjusted weight of all transactions in this chunk"},
448
3.59k
                    RPCResult{RPCResult::Type::ARR, "txs", "transactions in this chunk in mining order",
449
3.59k
                        {RPCResult{RPCResult::Type::STR_HEX, "txid", "transaction id"}}},
450
3.59k
                }
451
3.59k
            }}
452
3.59k
        }
453
3.59k
    };
454
3.59k
}
455
456
static std::vector<RPCResult> MempoolEntryDescription()
457
28.3k
{
458
28.3k
    std::vector<RPCResult> list = {
459
28.3k
        {RPCResult::Type::NUM, "vsize", "(DEPRECATED) Was previously erroneously described as the BIP 141 vsize, but is actually sigops-adjusted vsize.\n"
460
28.3k
        "Use vsize_bip141 to actually get that behavior or switch to the explicit vsize_adjusted for retained behavior."},
461
28.3k
        {RPCResult::Type::NUM, "vsize_bip141", "Virtual transaction size as defined in BIP 141.\n"
462
28.3k
        "This is different from actual serialized size for witness transactions as witness data is discounted."},
463
28.3k
        {RPCResult::Type::NUM, "vsize_adjusted", "Maximum of sigop-adjusted size (-bytespersigop) and virtual transaction size as defined in BIP 141."},
464
28.3k
        RPCResult{RPCResult::Type::NUM, "weight", "transaction weight as defined in BIP 141."},
465
28.3k
        RPCResult{RPCResult::Type::NUM_TIME, "time", "local time transaction entered pool in seconds since 1 Jan 1970 GMT"},
466
28.3k
        RPCResult{RPCResult::Type::NUM, "height", "block height when transaction entered pool"},
467
28.3k
        RPCResult{RPCResult::Type::NUM, "descendantcount", "number of in-mempool descendant transactions (including this one)"},
468
28.3k
        RPCResult{RPCResult::Type::NUM, "descendantsize", "virtual transaction size of in-mempool descendants (including this one)"},
469
28.3k
        RPCResult{RPCResult::Type::NUM, "ancestorcount", "number of in-mempool ancestor transactions (including this one)"},
470
28.3k
        RPCResult{RPCResult::Type::NUM, "ancestorsize", "virtual transaction size of in-mempool ancestors (including this one)"},
471
28.3k
        RPCResult{RPCResult::Type::NUM, "chunkweight", "sigops-adjusted weight (as defined in BIP 141 and modified by '-bytespersigop') of this transaction's chunk"},
472
28.3k
        RPCResult{RPCResult::Type::STR_HEX, "wtxid", "hash of serialized transaction, including witness data"},
473
28.3k
        RPCResult{RPCResult::Type::OBJ, "fees", "",
474
28.3k
            {
475
28.3k
                RPCResult{RPCResult::Type::STR_AMOUNT, "base", "transaction fee, denominated in " + CURRENCY_UNIT},
476
28.3k
                RPCResult{RPCResult::Type::STR_AMOUNT, "modified", "transaction fee with fee deltas used for mining priority, denominated in " + CURRENCY_UNIT},
477
28.3k
                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},
478
28.3k
                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},
479
28.3k
                RPCResult{RPCResult::Type::STR_AMOUNT, "chunk", "transaction fees of chunk, denominated in " + CURRENCY_UNIT},
480
28.3k
            }},
481
28.3k
        RPCResult{RPCResult::Type::ARR, "depends", "unconfirmed transactions used as inputs for this transaction",
482
28.3k
            {RPCResult{RPCResult::Type::STR_HEX, "transactionid", "parent transaction id"}}},
483
28.3k
        RPCResult{RPCResult::Type::ARR, "spentby", "unconfirmed transactions spending outputs from this transaction",
484
28.3k
            {RPCResult{RPCResult::Type::STR_HEX, "transactionid", "child transaction id"}}},
485
28.3k
        RPCResult{RPCResult::Type::BOOL, "unbroadcast", "Whether this transaction is currently unbroadcast (initial broadcast not yet acknowledged by any peers)"},
486
28.3k
    };
487
28.3k
    if (IsDeprecatedRPCEnabled("bip125")) {
488
68
        list.emplace_back(RPCResult::Type::BOOL, "bip125-replaceable", "Whether this transaction signals BIP125 replaceability or has an unconfirmed ancestor signaling BIP125 replaceability. (DEPRECATED)\n");
489
68
    }
490
28.3k
    return list;
491
28.3k
}
492
493
void AppendChunkInfo(UniValue& all_chunks, FeePerWeight chunk_feerate, std::vector<const CTxMemPoolEntry *> chunk_txs)
494
25.8k
{
495
25.8k
    UniValue chunk(UniValue::VOBJ);
496
25.8k
    chunk.pushKV("chunkfee", ValueFromAmount(chunk_feerate.fee));
497
25.8k
    chunk.pushKV("chunkweight", chunk_feerate.size);
498
25.8k
    UniValue chunk_txids(UniValue::VARR);
499
25.9k
    for (const auto& chunk_tx : chunk_txs) {
500
25.9k
        chunk_txids.push_back(chunk_tx->GetTx().GetHash().ToString());
501
25.9k
    }
502
25.8k
    chunk.pushKV("txs", std::move(chunk_txids));
503
25.8k
    all_chunks.push_back(std::move(chunk));
504
25.8k
}
505
506
static void clusterToJSON(const CTxMemPool& pool, UniValue& info, std::vector<const CTxMemPoolEntry *> cluster) EXCLUSIVE_LOCKS_REQUIRED(pool.cs)
507
1.14k
{
508
1.14k
    AssertLockHeld(pool.cs);
509
1.14k
    int total_weight{0};
510
25.9k
    for (const auto& tx : cluster) {
511
25.9k
        total_weight += tx->GetAdjustedWeight();
512
25.9k
    }
513
1.14k
    info.pushKV("clusterweight", total_weight);
514
1.14k
    info.pushKV("txcount", cluster.size());
515
516
    // Output the cluster by chunk. This isn't handed to us by the mempool, but
517
    // we can calculate it by looking at the chunk feerates of each transaction
518
    // in the cluster.
519
1.14k
    FeePerWeight current_chunk_feerate = pool.GetMainChunkFeerate(*cluster[0]);
520
1.14k
    std::vector<const CTxMemPoolEntry *> current_chunk;
521
1.14k
    current_chunk.reserve(cluster.size());
522
523
1.14k
    UniValue all_chunks(UniValue::VARR);
524
25.9k
    for (const auto& tx : cluster) {
525
25.9k
        if (current_chunk_feerate.size == 0) {
526
            // We've iterated all the transactions in the previous chunk; so
527
            // append it to the output.
528
24.7k
            AppendChunkInfo(all_chunks, pool.GetMainChunkFeerate(*current_chunk[0]), current_chunk);
529
24.7k
            current_chunk.clear();
530
24.7k
            current_chunk_feerate = pool.GetMainChunkFeerate(*tx);
531
24.7k
        }
532
25.9k
        current_chunk.push_back(tx);
533
25.9k
        current_chunk_feerate.size -= tx->GetAdjustedWeight();
534
25.9k
    }
535
1.14k
    AppendChunkInfo(all_chunks, pool.GetMainChunkFeerate(*current_chunk[0]), current_chunk);
536
1.14k
    current_chunk.clear();
537
1.14k
    info.pushKV("chunks", std::move(all_chunks));
538
1.14k
}
539
540
static void entryToJSON(const CTxMemPool& pool, UniValue& info, const CTxMemPoolEntry& e) EXCLUSIVE_LOCKS_REQUIRED(pool.cs)
541
9.49k
{
542
9.49k
    AssertLockHeld(pool.cs);
543
544
9.49k
    auto [ancestor_count, ancestor_size, ancestor_fees] = pool.CalculateAncestorData(e);
545
9.49k
    auto [descendant_count, descendant_size, descendant_fees] = pool.CalculateDescendantData(e);
546
547
9.49k
    info.pushKV("vsize_adjusted", e.GetTxSize());
548
9.49k
    info.pushKV("vsize", e.GetTxSize());
549
9.49k
    info.pushKV("vsize_bip141", GetVirtualTransactionSize(e.GetTx()));
550
9.49k
    info.pushKV("weight", e.GetTxWeight());
551
9.49k
    info.pushKV("time", count_seconds(e.GetTime()));
552
9.49k
    info.pushKV("height", e.GetHeight());
553
9.49k
    info.pushKV("descendantcount", descendant_count);
554
9.49k
    info.pushKV("descendantsize", descendant_size);
555
9.49k
    info.pushKV("ancestorcount", ancestor_count);
556
9.49k
    info.pushKV("ancestorsize", ancestor_size);
557
9.49k
    info.pushKV("wtxid", e.GetTx().GetWitnessHash().ToString());
558
9.49k
    auto feerate = pool.GetMainChunkFeerate(e);
559
9.49k
    info.pushKV("chunkweight", feerate.size);
560
561
9.49k
    UniValue fees(UniValue::VOBJ);
562
9.49k
    fees.pushKV("base", ValueFromAmount(e.GetFee()));
563
9.49k
    fees.pushKV("modified", ValueFromAmount(e.GetModifiedFee()));
564
9.49k
    fees.pushKV("ancestor", ValueFromAmount(ancestor_fees));
565
9.49k
    fees.pushKV("descendant", ValueFromAmount(descendant_fees));
566
9.49k
    fees.pushKV("chunk", ValueFromAmount(feerate.fee));
567
9.49k
    info.pushKV("fees", std::move(fees));
568
569
9.49k
    const CTransaction& tx = e.GetTx();
570
9.49k
    std::set<std::string> setDepends;
571
9.49k
    for (const CTxIn& txin : tx.vin)
572
14.9k
    {
573
14.9k
        if (pool.exists(txin.prevout.hash))
574
7.74k
            setDepends.insert(txin.prevout.hash.ToString());
575
14.9k
    }
576
577
9.49k
    UniValue depends(UniValue::VARR);
578
9.49k
    for (const std::string& dep : setDepends)
579
7.74k
    {
580
7.74k
        depends.push_back(dep);
581
7.74k
    }
582
583
9.49k
    info.pushKV("depends", std::move(depends));
584
585
9.49k
    UniValue spent(UniValue::VARR);
586
9.49k
    for (const CTxMemPoolEntry& child : pool.GetChildren(e)) {
587
7.76k
        spent.push_back(child.GetTx().GetHash().ToString());
588
7.76k
    }
589
590
9.49k
    info.pushKV("spentby", std::move(spent));
591
9.49k
    info.pushKV("unbroadcast", pool.IsUnbroadcastTx(tx.GetHash()));
592
593
    // Add opt-in RBF status
594
9.49k
    if (IsDeprecatedRPCEnabled("bip125")) {
595
1
        bool rbfStatus = false;
596
1
        RBFTransactionState rbfState = IsRBFOptIn(tx, pool);
597
1
        if (rbfState == RBFTransactionState::UNKNOWN) {
598
0
            throw JSONRPCError(RPC_MISC_ERROR, "Transaction is not in mempool");
599
1
        } else if (rbfState == RBFTransactionState::REPLACEABLE_BIP125) {
600
0
            rbfStatus = true;
601
0
        }
602
1
        info.pushKV("bip125-replaceable", rbfStatus);
603
1
    }
604
9.49k
}
605
606
UniValue MempoolToJSON(const CTxMemPool& pool, bool verbose, bool include_mempool_sequence)
607
7.55k
{
608
7.55k
    if (verbose) {
609
1.08k
        if (include_mempool_sequence) {
610
0
            throw JSONRPCError(RPC_INVALID_PARAMETER, "Verbose results cannot contain mempool sequence values.");
611
0
        }
612
1.08k
        LOCK(pool.cs);
613
1.08k
        UniValue o(UniValue::VOBJ);
614
4.53k
        for (const CTxMemPoolEntry& e : pool.entryAll()) {
615
4.53k
            UniValue info(UniValue::VOBJ);
616
4.53k
            entryToJSON(pool, info, e);
617
            // Mempool has unique entries so there is no advantage in using
618
            // UniValue::pushKV, which checks if the key already exists in O(N).
619
            // UniValue::pushKVEnd is used instead which currently is O(1).
620
4.53k
            o.pushKVEnd(e.GetTx().GetHash().ToString(), std::move(info));
621
4.53k
        }
622
1.08k
        return o;
623
6.47k
    } else {
624
6.47k
        UniValue a(UniValue::VARR);
625
6.47k
        uint64_t mempool_sequence;
626
6.47k
        {
627
6.47k
            LOCK(pool.cs);
628
297k
            for (const CTxMemPoolEntry& e : pool.entryAll()) {
629
297k
                a.push_back(e.GetTx().GetHash().ToString());
630
297k
            }
631
6.47k
            mempool_sequence = pool.GetSequence();
632
6.47k
        }
633
6.47k
        if (!include_mempool_sequence) {
634
6.46k
            return a;
635
6.46k
        } else {
636
6
            UniValue o(UniValue::VOBJ);
637
6
            o.pushKV("txids", std::move(a));
638
6
            o.pushKV("mempool_sequence", mempool_sequence);
639
6
            return o;
640
6
        }
641
6.47k
    }
642
7.55k
}
643
644
static RPCMethod getmempoolfeeratediagram()
645
2.44k
{
646
2.44k
    return RPCMethod{"getmempoolfeeratediagram",
647
2.44k
        "Returns the feerate diagram for the whole mempool.",
648
2.44k
        {},
649
2.44k
        {
650
2.44k
            RPCResult{"mempool chunks",
651
2.44k
                RPCResult::Type::ARR, "", "",
652
2.44k
                {
653
2.44k
                    {
654
2.44k
                        RPCResult::Type::OBJ, "", "",
655
2.44k
                        {
656
2.44k
                            {RPCResult::Type::NUM, "weight", "cumulative sigops-adjusted weight"},
657
2.44k
                            {RPCResult::Type::NUM, "fee", "cumulative fee"}
658
2.44k
                        }
659
2.44k
                    }
660
2.44k
                }
661
2.44k
            }
662
2.44k
        },
663
2.44k
        RPCExamples{
664
2.44k
            HelpExampleCli("getmempoolfeeratediagram", "")
665
2.44k
            + HelpExampleRpc("getmempoolfeeratediagram", "")
666
2.44k
        },
667
2.44k
        [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
668
2.44k
        {
669
5
            const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
670
5
            LOCK(mempool.cs);
671
672
5
            UniValue result(UniValue::VARR);
673
674
5
            auto diagram = mempool.GetFeerateDiagram();
675
676
131
            for (auto f : diagram) {
677
131
                UniValue o(UniValue::VOBJ);
678
131
                o.pushKV("weight", f.size);
679
131
                o.pushKV("fee", ValueFromAmount(f.fee));
680
131
                result.push_back(o);
681
131
            }
682
5
            return result;
683
5
        }
684
2.44k
    };
685
2.44k
}
686
687
static RPCMethod getrawmempool()
688
10.0k
{
689
10.0k
    return RPCMethod{
690
10.0k
        "getrawmempool",
691
10.0k
        "Returns all transaction ids in memory pool as a json array of string transaction ids.\n"
692
10.0k
        "\nHint: use getmempoolentry to fetch a specific transaction from the mempool.\n",
693
10.0k
        {
694
10.0k
            {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"},
695
10.0k
            {"mempool_sequence", RPCArg::Type::BOOL, RPCArg::Default{false}, "If verbose=false, returns a json object with transaction list and mempool sequence number attached."},
696
10.0k
        },
697
10.0k
        {
698
10.0k
            RPCResult{"for verbose = false",
699
10.0k
                RPCResult::Type::ARR, "", "",
700
10.0k
                {
701
10.0k
                    {RPCResult::Type::STR_HEX, "", "The transaction id"},
702
10.0k
                }},
703
10.0k
            RPCResult{"for verbose = true",
704
10.0k
                RPCResult::Type::OBJ_DYN, "", "",
705
10.0k
                {
706
10.0k
                    {RPCResult::Type::OBJ, "transactionid", "", MempoolEntryDescription()},
707
10.0k
                }},
708
10.0k
            RPCResult{"for verbose = false and mempool_sequence = true",
709
10.0k
                RPCResult::Type::OBJ, "", "",
710
10.0k
                {
711
10.0k
                    {RPCResult::Type::ARR, "txids", "",
712
10.0k
                    {
713
10.0k
                        {RPCResult::Type::STR_HEX, "", "The transaction id"},
714
10.0k
                    }},
715
10.0k
                    {RPCResult::Type::NUM, "mempool_sequence", "The mempool sequence value."},
716
10.0k
                }},
717
10.0k
        },
718
10.0k
        RPCExamples{
719
10.0k
            HelpExampleCli("getrawmempool", "true")
720
10.0k
            + HelpExampleRpc("getrawmempool", "true")
721
10.0k
        },
722
10.0k
        [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
723
10.0k
{
724
7.55k
    bool fVerbose = false;
725
7.55k
    if (!request.params[0].isNull())
726
1.14k
        fVerbose = request.params[0].get_bool();
727
728
7.55k
    bool include_mempool_sequence = false;
729
7.55k
    if (!request.params[1].isNull()) {
730
5
        include_mempool_sequence = request.params[1].get_bool();
731
5
    }
732
733
7.55k
    return MempoolToJSON(EnsureAnyMemPool(request.context), fVerbose, include_mempool_sequence);
734
7.55k
},
735
10.0k
    };
736
10.0k
}
737
738
static RPCMethod getmempoolancestors()
739
3.06k
{
740
3.06k
    return RPCMethod{
741
3.06k
        "getmempoolancestors",
742
3.06k
        "If txid is in the mempool, returns all in-mempool ancestors.\n",
743
3.06k
        {
744
3.06k
            {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
745
3.06k
            {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"},
746
3.06k
        },
747
3.06k
        {
748
3.06k
            RPCResult{"for verbose = false",
749
3.06k
                RPCResult::Type::ARR, "", "",
750
3.06k
                {{RPCResult::Type::STR_HEX, "", "The transaction id of an in-mempool ancestor transaction"}}},
751
3.06k
            RPCResult{"for verbose = true",
752
3.06k
                RPCResult::Type::OBJ_DYN, "", "",
753
3.06k
                {
754
3.06k
                    {RPCResult::Type::OBJ, "transactionid", "", MempoolEntryDescription()},
755
3.06k
                }},
756
3.06k
        },
757
3.06k
        RPCExamples{
758
3.06k
            HelpExampleCli("getmempoolancestors", "\"mytxid\"")
759
3.06k
            + HelpExampleRpc("getmempoolancestors", "\"mytxid\"")
760
3.06k
        },
761
3.06k
        [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
762
3.06k
{
763
613
    bool fVerbose = false;
764
613
    if (!request.params[1].isNull())
765
65
        fVerbose = request.params[1].get_bool();
766
767
613
    auto txid{Txid::FromUint256(ParseHashV(request.params[0], "txid"))};
768
769
613
    const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
770
613
    LOCK(mempool.cs);
771
772
613
    const auto entry{mempool.GetEntry(txid)};
773
613
    if (entry == nullptr) {
774
0
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool");
775
0
    }
776
777
613
    auto ancestors{mempool.CalculateMemPoolAncestors(*entry)};
778
779
613
    if (!fVerbose) {
780
548
        UniValue o(UniValue::VARR);
781
11.4k
        for (CTxMemPool::txiter ancestorIt : ancestors) {
782
11.4k
            o.push_back(ancestorIt->GetTx().GetHash().ToString());
783
11.4k
        }
784
548
        return o;
785
548
    } else {
786
65
        UniValue o(UniValue::VOBJ);
787
2.07k
        for (CTxMemPool::txiter ancestorIt : ancestors) {
788
2.07k
            const CTxMemPoolEntry &e = *ancestorIt;
789
2.07k
            UniValue info(UniValue::VOBJ);
790
2.07k
            entryToJSON(mempool, info, e);
791
2.07k
            o.pushKV(e.GetTx().GetHash().ToString(), std::move(info));
792
2.07k
        }
793
65
        return o;
794
65
    }
795
613
},
796
3.06k
    };
797
3.06k
}
798
799
static RPCMethod getmempooldescendants()
800
11.9k
{
801
11.9k
    return RPCMethod{
802
11.9k
        "getmempooldescendants",
803
11.9k
        "If txid is in the mempool, returns all in-mempool descendants.\n",
804
11.9k
        {
805
11.9k
            {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
806
11.9k
            {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"},
807
11.9k
        },
808
11.9k
        {
809
11.9k
            RPCResult{"for verbose = false",
810
11.9k
                RPCResult::Type::ARR, "", "",
811
11.9k
                {{RPCResult::Type::STR_HEX, "", "The transaction id of an in-mempool descendant transaction"}}},
812
11.9k
            RPCResult{"for verbose = true",
813
11.9k
                RPCResult::Type::OBJ_DYN, "", "",
814
11.9k
                {
815
11.9k
                    {RPCResult::Type::OBJ, "transactionid", "", MempoolEntryDescription()},
816
11.9k
                }},
817
11.9k
        },
818
11.9k
        RPCExamples{
819
11.9k
            HelpExampleCli("getmempooldescendants", "\"mytxid\"")
820
11.9k
            + HelpExampleRpc("getmempooldescendants", "\"mytxid\"")
821
11.9k
        },
822
11.9k
        [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
823
11.9k
{
824
9.51k
    bool fVerbose = false;
825
9.51k
    if (!request.params[1].isNull())
826
65
        fVerbose = request.params[1].get_bool();
827
828
9.51k
    auto txid{Txid::FromUint256(ParseHashV(request.params[0], "txid"))};
829
830
9.51k
    const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
831
9.51k
    LOCK(mempool.cs);
832
833
9.51k
    const auto it{mempool.GetIter(txid)};
834
9.51k
    if (!it) {
835
0
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool");
836
0
    }
837
838
9.51k
    CTxMemPool::setEntries setDescendants;
839
9.51k
    mempool.CalculateDescendants(*it, setDescendants);
840
    // CTxMemPool::CalculateDescendants will include the given tx
841
9.51k
    setDescendants.erase(*it);
842
843
9.51k
    if (!fVerbose) {
844
9.45k
        UniValue o(UniValue::VARR);
845
166k
        for (CTxMemPool::txiter descendantIt : setDescendants) {
846
166k
            o.push_back(descendantIt->GetTx().GetHash().ToString());
847
166k
        }
848
849
9.45k
        return o;
850
9.45k
    } else {
851
65
        UniValue o(UniValue::VOBJ);
852
2.07k
        for (CTxMemPool::txiter descendantIt : setDescendants) {
853
2.07k
            const CTxMemPoolEntry &e = *descendantIt;
854
2.07k
            UniValue info(UniValue::VOBJ);
855
2.07k
            entryToJSON(mempool, info, e);
856
2.07k
            o.pushKV(e.GetTx().GetHash().ToString(), std::move(info));
857
2.07k
        }
858
65
        return o;
859
65
    }
860
9.51k
},
861
11.9k
    };
862
11.9k
}
863
864
static RPCMethod getmempoolcluster()
865
3.59k
{
866
3.59k
    return RPCMethod{"getmempoolcluster",
867
3.59k
        "Returns mempool data for given cluster\n",
868
3.59k
        {
869
3.59k
            {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The txid of a transaction in the cluster"},
870
3.59k
        },
871
3.59k
        RPCResult{
872
3.59k
            RPCResult::Type::OBJ, "", "", ClusterDescription()},
873
3.59k
        RPCExamples{
874
3.59k
            HelpExampleCli("getmempoolcluster", "txid")
875
3.59k
            + HelpExampleRpc("getmempoolcluster", R"("txid")")
876
3.59k
        },
877
3.59k
        [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
878
3.59k
{
879
1.14k
    uint256 hash = ParseHashV(request.params[0], "txid");
880
881
1.14k
    const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
882
1.14k
    LOCK(mempool.cs);
883
884
1.14k
    auto txid = Txid::FromUint256(hash);
885
1.14k
    const auto entry{mempool.GetEntry(txid)};
886
1.14k
    if (entry == nullptr) {
887
1
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool");
888
1
    }
889
890
1.14k
    auto cluster = mempool.GetCluster(txid);
891
892
1.14k
    UniValue info(UniValue::VOBJ);
893
1.14k
    clusterToJSON(mempool, info, cluster);
894
1.14k
    return info;
895
1.14k
},
896
3.59k
    };
897
3.59k
}
898
899
static RPCMethod getmempoolentry()
900
3.27k
{
901
3.27k
    return RPCMethod{
902
3.27k
        "getmempoolentry",
903
3.27k
        "Returns mempool data for given transaction\n",
904
3.27k
        {
905
3.27k
            {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
906
3.27k
        },
907
3.27k
        RPCResult{
908
3.27k
            RPCResult::Type::OBJ, "", "", MempoolEntryDescription()},
909
3.27k
        RPCExamples{
910
3.27k
            HelpExampleCli("getmempoolentry", "\"mytxid\"")
911
3.27k
            + HelpExampleRpc("getmempoolentry", "\"mytxid\"")
912
3.27k
        },
913
3.27k
        [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
914
3.27k
{
915
825
    auto txid{Txid::FromUint256(ParseHashV(request.params[0], "txid"))};
916
917
825
    const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
918
825
    LOCK(mempool.cs);
919
920
825
    const auto entry{mempool.GetEntry(txid)};
921
825
    if (entry == nullptr) {
922
24
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool");
923
24
    }
924
925
801
    UniValue info(UniValue::VOBJ);
926
801
    entryToJSON(mempool, info, *entry);
927
801
    return info;
928
825
},
929
3.27k
    };
930
3.27k
}
931
932
static RPCMethod gettxspendingprevout()
933
2.54k
{
934
2.54k
    return RPCMethod{"gettxspendingprevout",
935
2.54k
        "Scans the mempool (and the txospenderindex, if available) to find transactions spending any of the given outputs",
936
2.54k
        {
937
2.54k
            {"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The transaction outputs that we want to check, and within each, the txid (string) vout (numeric).",
938
2.54k
                {
939
2.54k
                    {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
940
2.54k
                        {
941
2.54k
                            {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
942
2.54k
                            {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
943
2.54k
                        },
944
2.54k
                    },
945
2.54k
                },
946
2.54k
            },
947
2.54k
            {"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "",
948
2.54k
                {
949
2.54k
                    {"mempool_only", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true if txospenderindex unavailable, otherwise false"}, "If false and mempool lacks a relevant spend, use txospenderindex (throws an exception if not available)."},
950
2.54k
                    {"return_spending_tx", RPCArg::Type::BOOL, RPCArg::DefaultHint{"false"}, "If true, return the full spending tx."},
951
2.54k
                },
952
2.54k
            },
953
2.54k
        },
954
2.54k
        RPCResult{
955
2.54k
            RPCResult::Type::ARR, "", "",
956
2.54k
            {
957
2.54k
                {RPCResult::Type::OBJ, "", "",
958
2.54k
                {
959
2.54k
                    {RPCResult::Type::STR_HEX, "txid", "the transaction id of the checked output"},
960
2.54k
                    {RPCResult::Type::NUM, "vout", "the vout value of the checked output"},
961
2.54k
                    {RPCResult::Type::STR_HEX, "spendingtxid", /*optional=*/true, "the transaction id of the mempool transaction spending this output (omitted if unspent)"},
962
2.54k
                    {RPCResult::Type::STR_HEX, "spendingtx", /*optional=*/true, "the transaction spending this output (only if return_spending_tx is set, omitted if unspent)"},
963
2.54k
                    {RPCResult::Type::STR_HEX, "blockhash", /*optional=*/true, "the hash of the spending block (omitted if unspent or the spending tx is not confirmed)"},
964
2.54k
                }},
965
2.54k
            }
966
2.54k
        },
967
2.54k
        RPCExamples{
968
2.54k
            HelpExampleCli("gettxspendingprevout", "\"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":3}]\"")
969
2.54k
            + HelpExampleRpc("gettxspendingprevout", "\"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":3}]\"")
970
2.54k
            + HelpExampleCliNamed("gettxspendingprevout", {{"outputs", "[{\"txid\":\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\",\"vout\":3}]"}, {"return_spending_tx", true}})
971
2.54k
        },
972
2.54k
        [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
973
2.54k
        {
974
92
            const UniValue& output_params = request.params[0].get_array();
975
92
            if (output_params.empty()) {
976
1
                throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, outputs are missing");
977
1
            }
978
91
            const UniValue options{request.params[1].isNull() ? UniValue::VOBJ : request.params[1]};
979
91
            RPCTypeCheckObj(options,
980
91
                            {
981
91
                                {"mempool_only", UniValueType(UniValue::VBOOL)},
982
91
                                {"return_spending_tx", UniValueType(UniValue::VBOOL)},
983
91
                            }, /*fAllowNull=*/true, /*fStrict=*/true);
984
985
91
            const bool mempool_only{options.exists("mempool_only") ? options["mempool_only"].get_bool() : !g_txospenderindex};
986
91
            const bool return_spending_tx{options.exists("return_spending_tx") ? options["return_spending_tx"].get_bool() : false};
987
988
            // Worklist of outpoints to resolve
989
91
            struct Entry {
990
91
                COutPoint outpoint;
991
91
                size_t request_index;
992
91
            };
993
91
            std::vector<Entry> prevouts_to_process;
994
91
            prevouts_to_process.reserve(output_params.size());
995
101
            for (const size_t idx : std::views::iota(size_t{0}, output_params.size())) {
996
101
                const UniValue& o = output_params[idx].get_obj();
997
998
101
                RPCTypeCheckObj(o,
999
101
                                {
1000
101
                                    {"txid", UniValueType(UniValue::VSTR)},
1001
101
                                    {"vout", UniValueType(UniValue::VNUM)},
1002
101
                                }, /*fAllowNull=*/false, /*fStrict=*/true);
1003
1004
101
                const Txid txid = Txid::FromUint256(ParseHashO(o, "txid"));
1005
101
                const int nOutput{o.find_value("vout").getInt<int>()};
1006
101
                if (nOutput < 0) {
1007
1
                    throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative");
1008
1
                }
1009
100
                prevouts_to_process.emplace_back(COutPoint{txid, static_cast<uint32_t>(nOutput)}, idx);
1010
100
            }
1011
1012
96
            auto make_output = [&output_params, return_spending_tx](const Entry& prevout, const CTransaction* spending_tx = nullptr) {
1013
96
                UniValue o{output_params[prevout.request_index]};
1014
96
                if (spending_tx) {
1015
86
                    o.pushKV("spendingtxid", spending_tx->GetHash().ToString());
1016
86
                    if (return_spending_tx) {
1017
11
                        o.pushKV("spendingtx", EncodeHexTx(*spending_tx));
1018
11
                    }
1019
86
                }
1020
96
                return o;
1021
96
            };
1022
1023
90
            std::vector<UniValue> results(output_params.size());
1024
1025
            // Search the mempool first
1026
90
            std::vector<Entry> unresolved;
1027
90
            unresolved.reserve(prevouts_to_process.size());
1028
90
            {
1029
90
                const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
1030
90
                LOCK(mempool.cs);
1031
1032
                // Make the result if the spending tx appears in the mempool or this is a mempool_only request
1033
96
                for (const auto& prevout : prevouts_to_process) {
1034
96
                    const auto* spending_tx{mempool.GetConflictTx(prevout.outpoint)};
1035
1036
                    // If the outpoint is not spent in the mempool and this is not a mempool-only
1037
                    // request, we cannot answer it yet.
1038
96
                    if (!spending_tx && !mempool_only) {
1039
16
                        unresolved.push_back(prevout);
1040
80
                    } else {
1041
80
                        results[prevout.request_index] = make_output(prevout, spending_tx);
1042
80
                    }
1043
96
                }
1044
90
            }
1045
1046
            // mempool_only requests resolve every outpoint above, so only other requests reach the index.
1047
90
            if (!unresolved.empty() && (!g_txospenderindex || !g_txospenderindex->BlockUntilSyncedToCurrentChain())) {
1048
0
                throw JSONRPCError(RPC_MISC_ERROR, "Mempool lacks a relevant spend, and txospenderindex is unavailable.");
1049
0
            }
1050
1051
90
            for (const auto& prevout : unresolved) {
1052
16
                const auto spender{g_txospenderindex->FindSpender(prevout.outpoint)};
1053
16
                if (!spender) {
1054
0
                    throw JSONRPCError(RPC_MISC_ERROR, spender.error());
1055
0
                }
1056
1057
16
                if (const auto& spender_opt{spender.value()}) {
1058
11
                    UniValue o{make_output(prevout, spender_opt->tx.get())};
1059
11
                    o.pushKV("blockhash", spender_opt->block_hash.GetHex());
1060
11
                    results[prevout.request_index] = std::move(o);
1061
11
                } else {
1062
                    // Only return the input outpoint itself, which indicates it is unspent.
1063
5
                    results[prevout.request_index] = make_output(prevout);
1064
5
                }
1065
16
            }
1066
1067
90
            UniValue result{UniValue::VARR};
1068
90
            result.reserve(results.size());
1069
96
            for (auto& output : results) result.push_back(std::move(output));
1070
90
            return result;
1071
90
        },
1072
2.54k
    };
1073
2.54k
}
1074
1075
UniValue MempoolInfoToJSON(const CTxMemPool& pool)
1076
1.42k
{
1077
    // Make sure this call is atomic in the pool.
1078
1.42k
    LOCK(pool.cs);
1079
1.42k
    UniValue ret(UniValue::VOBJ);
1080
1.42k
    ret.pushKV("loaded", pool.GetLoadTried());
1081
1.42k
    ret.pushKV("size", pool.size());
1082
1.42k
    ret.pushKV("bytes", pool.GetTotalTxSize());
1083
1.42k
    ret.pushKV("usage", pool.DynamicMemoryUsage());
1084
1.42k
    ret.pushKV("total_fee", ValueFromAmount(pool.GetTotalFee()));
1085
1.42k
    ret.pushKV("maxmempool", pool.m_opts.max_size_bytes);
1086
1.42k
    ret.pushKV("mempoolminfee", ValueFromAmount(std::max(pool.GetMinFee(), pool.m_opts.min_relay_feerate).GetFeePerK()));
1087
1.42k
    ret.pushKV("minrelaytxfee", ValueFromAmount(pool.m_opts.min_relay_feerate.GetFeePerK()));
1088
1.42k
    ret.pushKV("incrementalrelayfee", ValueFromAmount(pool.m_opts.incremental_relay_feerate.GetFeePerK()));
1089
1.42k
    ret.pushKV("unbroadcastcount", pool.GetUnbroadcastTxs().size());
1090
1.42k
    ret.pushKV("permitbaremultisig", pool.m_opts.permit_bare_multisig);
1091
1.42k
    ret.pushKV("maxdatacarriersize", pool.m_opts.max_datacarrier_bytes.value_or(0));
1092
1.42k
    ret.pushKV("limitclustercount", pool.m_opts.limits.cluster_count);
1093
1.42k
    ret.pushKV("limitclustersize", pool.m_opts.limits.cluster_size_vbytes);
1094
1.42k
    ret.pushKV("optimal", pool.m_txgraph->DoWork(0)); // 0 work is a quick check for known optimality
1095
1.42k
    if (IsDeprecatedRPCEnabled("fullrbf")) {
1096
3
        ret.pushKV("fullrbf", true);
1097
3
    }
1098
1.42k
    return ret;
1099
1.42k
}
1100
1101
static RPCMethod getmempoolinfo()
1102
3.87k
{
1103
3.87k
    return RPCMethod{"getmempoolinfo",
1104
3.87k
        "Returns details on the active state of the TX memory pool.",
1105
3.87k
        {},
1106
3.87k
        RPCResult{
1107
3.87k
            RPCResult::Type::OBJ, "", "",
1108
3.87k
            [](){
1109
3.87k
                std::vector<RPCResult> list = {
1110
3.87k
                    {RPCResult::Type::BOOL, "loaded", "True if the initial load attempt of the persisted mempool finished"},
1111
3.87k
                    {RPCResult::Type::NUM, "size", "Current tx count"},
1112
3.87k
                    {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"},
1113
3.87k
                    {RPCResult::Type::NUM, "usage", "Total memory usage for the mempool"},
1114
3.87k
                    {RPCResult::Type::STR_AMOUNT, "total_fee", "Total fees for the mempool in " + CURRENCY_UNIT + ", ignoring modified fees through prioritisetransaction"},
1115
3.87k
                    {RPCResult::Type::NUM, "maxmempool", "Maximum memory usage for the mempool"},
1116
3.87k
                    {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"},
1117
3.87k
                    {RPCResult::Type::STR_AMOUNT, "minrelaytxfee", "Current minimum relay fee for transactions"},
1118
3.87k
                    {RPCResult::Type::NUM, "incrementalrelayfee", "minimum fee rate increment for mempool limiting or replacement in " + CURRENCY_UNIT + "/kvB"},
1119
3.87k
                    {RPCResult::Type::NUM, "unbroadcastcount", "Current number of transactions that haven't passed initial broadcast yet"},
1120
3.87k
                    {RPCResult::Type::BOOL, "permitbaremultisig", "True if the mempool accepts transactions with bare multisig outputs"},
1121
3.87k
                    {RPCResult::Type::NUM, "maxdatacarriersize", "Maximum number of bytes that can be used by OP_RETURN outputs in the mempool"},
1122
3.87k
                    {RPCResult::Type::NUM, "limitclustercount", "Maximum number of transactions that can be in a cluster (configured by -limitclustercount)"},
1123
3.87k
                    {RPCResult::Type::NUM, "limitclustersize", "Maximum size of a cluster in virtual bytes (configured by -limitclustersize)"},
1124
3.87k
                    {RPCResult::Type::BOOL, "optimal", "If the mempool is in a known-optimal transaction ordering"},
1125
3.87k
                };
1126
3.87k
                if (IsDeprecatedRPCEnabled("fullrbf")) {
1127
5
                    list.emplace_back(RPCResult::Type::BOOL, "fullrbf", "True if the mempool accepts RBF without replaceability signaling inspection (DEPRECATED)");
1128
5
                }
1129
3.87k
                return list;
1130
3.87k
            }()
1131
3.87k
            },
1132
3.87k
        RPCExamples{
1133
3.87k
            HelpExampleCli("getmempoolinfo", "")
1134
3.87k
            + HelpExampleRpc("getmempoolinfo", "")
1135
3.87k
        },
1136
3.87k
        [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
1137
3.87k
{
1138
1.42k
    return MempoolInfoToJSON(EnsureAnyMemPool(request.context));
1139
1.42k
},
1140
3.87k
    };
1141
3.87k
}
1142
1143
static RPCMethod importmempool()
1144
2.45k
{
1145
2.45k
    return RPCMethod{
1146
2.45k
        "importmempool",
1147
2.45k
        "Import a mempool.dat file and attempt to add its contents to the mempool.\n"
1148
2.45k
        "Warning: Importing untrusted files is dangerous, especially if metadata from the file is taken over.",
1149
2.45k
        {
1150
2.45k
            {"filepath", RPCArg::Type::STR, RPCArg::Optional::NO, "The mempool file"},
1151
2.45k
            {"options",
1152
2.45k
             RPCArg::Type::OBJ_NAMED_PARAMS,
1153
2.45k
             RPCArg::Optional::OMITTED,
1154
2.45k
             "",
1155
2.45k
             {
1156
2.45k
                 {"use_current_time", RPCArg::Type::BOOL, RPCArg::Default{true},
1157
2.45k
                  "Whether to use the current system time or use the entry time metadata from the mempool file.\n"
1158
2.45k
                  "Warning: Importing untrusted metadata may lead to unexpected issues and undesirable behavior."},
1159
2.45k
                 {"apply_fee_delta_priority", RPCArg::Type::BOOL, RPCArg::Default{false},
1160
2.45k
                  "Whether to apply the fee delta metadata from the mempool file.\n"
1161
2.45k
                  "It will be added to any existing fee deltas.\n"
1162
2.45k
                  "The fee delta can be set by the prioritisetransaction RPC.\n"
1163
2.45k
                  "Warning: Importing untrusted metadata may lead to unexpected issues and undesirable behavior.\n"
1164
2.45k
                  "Only set this bool if you understand what it does."},
1165
2.45k
                 {"apply_unbroadcast_set", RPCArg::Type::BOOL, RPCArg::Default{false},
1166
2.45k
                  "Whether to apply the unbroadcast set metadata from the mempool file.\n"
1167
2.45k
                  "Warning: Importing untrusted metadata may lead to unexpected issues and undesirable behavior."},
1168
2.45k
             },
1169
2.45k
             RPCArgOptions{.oneline_description = "options"}},
1170
2.45k
        },
1171
2.45k
        RPCResult{RPCResult::Type::OBJ, "", "", std::vector<RPCResult>{}},
1172
2.45k
        RPCExamples{HelpExampleCli("importmempool", "/path/to/mempool.dat") + HelpExampleRpc("importmempool", R"("/path/to/mempool.dat")")},
1173
2.45k
        [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue {
1174
3
            const NodeContext& node{EnsureAnyNodeContext(request.context)};
1175
1176
3
            CTxMemPool& mempool{EnsureMemPool(node)};
1177
3
            ChainstateManager& chainman = EnsureChainman(node);
1178
3
            Chainstate& chainstate = chainman.ActiveChainstate();
1179
1180
3
            if (chainman.IsInitialBlockDownload()) {
1181
0
                throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Can only import the mempool after the block download and sync is done.");
1182
0
            }
1183
1184
3
            const fs::path load_path{fs::u8path(self.Arg<std::string_view>("filepath"))};
1185
3
            const UniValue& use_current_time{request.params[1]["use_current_time"]};
1186
3
            const UniValue& apply_fee_delta{request.params[1]["apply_fee_delta_priority"]};
1187
3
            const UniValue& apply_unbroadcast{request.params[1]["apply_unbroadcast_set"]};
1188
3
            node::ImportMempoolOptions opts{
1189
3
                .use_current_time = use_current_time.isNull() ? true : use_current_time.get_bool(),
1190
3
                .apply_fee_delta_priority = apply_fee_delta.isNull() ? false : apply_fee_delta.get_bool(),
1191
3
                .apply_unbroadcast_set = apply_unbroadcast.isNull() ? false : apply_unbroadcast.get_bool(),
1192
3
            };
1193
1194
3
            if (!node::LoadMempool(mempool, load_path, chainstate, std::move(opts))) {
1195
0
                throw JSONRPCError(RPC_MISC_ERROR, "Unable to import mempool file, see debug log for details.");
1196
0
            }
1197
1198
3
            UniValue ret{UniValue::VOBJ};
1199
3
            return ret;
1200
3
        },
1201
2.45k
    };
1202
2.45k
}
1203
1204
static RPCMethod savemempool()
1205
2.45k
{
1206
2.45k
    return RPCMethod{
1207
2.45k
        "savemempool",
1208
2.45k
        "Dumps the mempool to disk. It will fail until the previous dump is fully loaded.\n",
1209
2.45k
        {},
1210
2.45k
        RPCResult{
1211
2.45k
            RPCResult::Type::OBJ, "", "",
1212
2.45k
            {
1213
2.45k
                {RPCResult::Type::STR, "filename", "the directory and file where the mempool was saved"},
1214
2.45k
            }},
1215
2.45k
        RPCExamples{
1216
2.45k
            HelpExampleCli("savemempool", "")
1217
2.45k
            + HelpExampleRpc("savemempool", "")
1218
2.45k
        },
1219
2.45k
        [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
1220
2.45k
{
1221
4
    const ArgsManager& args{EnsureAnyArgsman(request.context)};
1222
4
    const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
1223
1224
4
    if (!mempool.GetLoadTried()) {
1225
0
        throw JSONRPCError(RPC_MISC_ERROR, "The mempool was not loaded yet");
1226
0
    }
1227
1228
4
    const fs::path& dump_path = MempoolPath(args);
1229
1230
4
    if (!DumpMempool(mempool, dump_path)) {
1231
1
        throw JSONRPCError(RPC_MISC_ERROR, "Unable to dump mempool to disk");
1232
1
    }
1233
1234
3
    UniValue ret(UniValue::VOBJ);
1235
3
    ret.pushKV("filename", dump_path.utf8string());
1236
1237
3
    return ret;
1238
4
},
1239
2.45k
    };
1240
2.45k
}
1241
1242
static std::vector<RPCResult> OrphanDescription()
1243
5.33k
{
1244
5.33k
    return {
1245
5.33k
        RPCResult{RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
1246
5.33k
        RPCResult{RPCResult::Type::STR_HEX, "wtxid", "The transaction witness hash in hex"},
1247
5.33k
        RPCResult{RPCResult::Type::NUM, "bytes", "The serialized transaction size in bytes"},
1248
5.33k
        RPCResult{RPCResult::Type::NUM, "vsize", "(DEPRECATED) use vsize_bip141 instead. The virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted."},
1249
5.33k
        RPCResult{RPCResult::Type::NUM, "vsize_bip141", "The virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted."},
1250
5.33k
        RPCResult{RPCResult::Type::NUM, "weight", "The transaction weight as defined in BIP 141."},
1251
5.33k
        RPCResult{RPCResult::Type::ARR, "from", "",
1252
5.33k
        {
1253
5.33k
            RPCResult{RPCResult::Type::NUM, "peer_id", "Peer ID"},
1254
5.33k
        }},
1255
5.33k
    };
1256
5.33k
}
1257
1258
static UniValue OrphanToJSON(const node::TxOrphanage::OrphanInfo& orphan)
1259
43
{
1260
43
    UniValue o(UniValue::VOBJ);
1261
43
    o.pushKV("txid", orphan.tx->GetHash().ToString());
1262
43
    o.pushKV("wtxid", orphan.tx->GetWitnessHash().ToString());
1263
43
    o.pushKV("bytes", orphan.tx->ComputeTotalSize());
1264
43
    o.pushKV("vsize", GetVirtualTransactionSize(*orphan.tx));
1265
43
    o.pushKV("vsize_bip141", GetVirtualTransactionSize(*orphan.tx));
1266
43
    o.pushKV("weight", GetTransactionWeight(*orphan.tx));
1267
43
    UniValue from(UniValue::VARR);
1268
49
    for (const auto fromPeer: orphan.announcers) {
1269
49
        from.push_back(fromPeer);
1270
49
    }
1271
43
    o.pushKV("from", from);
1272
43
    return o;
1273
43
}
1274
1275
static RPCMethod getorphantxs()
1276
2.66k
{
1277
2.66k
    return RPCMethod{
1278
2.66k
        "getorphantxs",
1279
2.66k
        "Shows transactions in the tx orphanage.\n"
1280
2.66k
        "\nEXPERIMENTAL warning: this call may be changed in future releases.\n",
1281
2.66k
        {
1282
2.66k
            {"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",
1283
2.66k
             RPCArgOptions{.skip_type_check = true}},
1284
2.66k
        },
1285
2.66k
        {
1286
2.66k
            RPCResult{"for verbose = 0",
1287
2.66k
                RPCResult::Type::ARR, "", "",
1288
2.66k
                {
1289
2.66k
                    {RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
1290
2.66k
                }},
1291
2.66k
            RPCResult{"for verbose = 1",
1292
2.66k
                RPCResult::Type::ARR, "", "",
1293
2.66k
                {
1294
2.66k
                    {RPCResult::Type::OBJ, "", "", OrphanDescription()},
1295
2.66k
                }},
1296
2.66k
            RPCResult{"for verbose = 2",
1297
2.66k
                RPCResult::Type::ARR, "", "",
1298
2.66k
                {
1299
2.66k
                    {RPCResult::Type::OBJ, "", "",
1300
2.66k
                        Cat<std::vector<RPCResult>>(
1301
2.66k
                            OrphanDescription(),
1302
2.66k
                            {{RPCResult::Type::STR_HEX, "hex", "The serialized, hex-encoded transaction data"}}
1303
2.66k
                        )
1304
2.66k
                    },
1305
2.66k
                }},
1306
2.66k
        },
1307
2.66k
        RPCExamples{
1308
2.66k
            HelpExampleCli("getorphantxs", "2")
1309
2.66k
            + HelpExampleRpc("getorphantxs", "2")
1310
2.66k
        },
1311
2.66k
        [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
1312
2.66k
        {
1313
228
            const NodeContext& node = EnsureAnyNodeContext(request.context);
1314
228
            PeerManager& peerman = EnsurePeerman(node);
1315
228
            std::vector<node::TxOrphanage::OrphanInfo> orphanage = peerman.GetOrphanTransactions();
1316
1317
228
            int verbosity{ParseVerbosity(request.params[0], /*default_verbosity=*/0, /*allow_bool=*/false)};
1318
1319
228
            UniValue ret(UniValue::VARR);
1320
1321
228
            if (verbosity == 0) {
1322
18.3k
                for (auto const& orphan : orphanage) {
1323
18.3k
                    ret.push_back(orphan.tx->GetHash().ToString());
1324
18.3k
                }
1325
190
            } else if (verbosity == 1) {
1326
33
                for (auto const& orphan : orphanage) {
1327
33
                    ret.push_back(OrphanToJSON(orphan));
1328
33
                }
1329
25
            } else if (verbosity == 2) {
1330
10
                for (auto const& orphan : orphanage) {
1331
10
                    UniValue o{OrphanToJSON(orphan)};
1332
10
                    o.pushKV("hex", EncodeHexTx(*orphan.tx));
1333
10
                    ret.push_back(o);
1334
10
                }
1335
9
            } else {
1336
4
                throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid verbosity value " + ToString(verbosity));
1337
4
            }
1338
1339
224
            return ret;
1340
228
        },
1341
2.66k
    };
1342
2.66k
}
1343
1344
static RPCMethod submitpackage()
1345
2.56k
{
1346
2.56k
    return RPCMethod{"submitpackage",
1347
2.56k
        "Submit a package of raw transactions (serialized, hex-encoded) to local node.\n"
1348
2.56k
        "The package will be validated according to consensus and mempool policy rules. If any transaction passes, it will be accepted to mempool.\n"
1349
2.56k
        "This RPC is experimental and the interface may be unstable. Refer to doc/policy/packages.md for documentation on package policies.\n"
1350
2.56k
        "Warning: successful submission does not mean the transactions will propagate throughout the network.\n"
1351
2.56k
        ,
1352
2.56k
        {
1353
2.56k
            {"package", RPCArg::Type::ARR, RPCArg::Optional::NO, "An array of raw transactions.\n"
1354
2.56k
                "The package must consist of a transaction with (some, all, or none of) its unconfirmed parents. A single transaction is permitted.\n"
1355
2.56k
                "None of the parents may depend on each other. Parents that are already in mempool do not need to be present in the package.\n"
1356
2.56k
                "The package must be topologically sorted, with the child being the last element in the array if there are multiple elements.",
1357
2.56k
                {
1358
2.56k
                    {"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
1359
2.56k
                },
1360
2.56k
            },
1361
2.56k
            {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())},
1362
2.56k
             "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT +
1363
2.56k
                 "/kvB.\nFee rates larger than 1BTC/kvB are rejected.\nSet to 0 to accept any fee rate."},
1364
2.56k
            {"maxburnamount", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_BURN_AMOUNT)},
1365
2.56k
             "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"
1366
2.56k
             "If burning funds through unspendable outputs is desired, increase this value.\n"
1367
2.56k
             "This check is based on heuristics and does not guarantee spendability of outputs.\n"
1368
2.56k
            },
1369
2.56k
        },
1370
2.56k
        RPCResult{
1371
2.56k
            RPCResult::Type::OBJ, "", "",
1372
2.56k
            {
1373
2.56k
                {RPCResult::Type::STR, "package_msg", "The transaction package result message. \"success\" indicates all transactions were accepted into or are already in the mempool."},
1374
2.56k
                {RPCResult::Type::OBJ_DYN, "tx-results", "The transaction results keyed by wtxid. An entry is returned for every submitted wtxid.",
1375
2.56k
                {
1376
2.56k
                    {RPCResult::Type::OBJ, "wtxid", "transaction wtxid", {
1377
2.56k
                        {RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
1378
2.56k
                        {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."},
1379
2.56k
                        {RPCResult::Type::NUM, "vsize_adjusted", /*optional=*/true, "Maximum of sigop-adjusted size (-bytespersigop) and virtual transaction size as defined in BIP 141."},
1380
2.56k
                        {RPCResult::Type::NUM, "vsize", /*optional=*/true, "(DEPRECATED) Was previously erroneously described as the BIP 141 vsize, but is actually sigops-adjusted vsize.\n"
1381
2.56k
                                                                    "Use vsize_bip141 to actually get that behavior or switch to the explicit vsize_adjusted for retained behavior."},
1382
2.56k
                        {RPCResult::Type::NUM, "vsize_bip141", /*optional=*/true, "Virtual transaction size as defined in BIP 141."},
1383
2.56k
                        {RPCResult::Type::OBJ, "fees", /*optional=*/true, "Transaction fees", {
1384
2.56k
                            {RPCResult::Type::STR_AMOUNT, "base", "transaction fee in " + CURRENCY_UNIT},
1385
2.56k
                            {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."},
1386
2.56k
                            {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.",
1387
2.56k
                                {{RPCResult::Type::STR_HEX, "", "transaction wtxid in hex"},
1388
2.56k
                            }},
1389
2.56k
                        }},
1390
2.56k
                        {RPCResult::Type::STR, "error", /*optional=*/true, "Error string if rejected from mempool, or \"package-not-validated\" when the package aborts before any per-tx processing."},
1391
2.56k
                    }}
1392
2.56k
                }},
1393
2.56k
                {RPCResult::Type::ARR, "replaced-transactions", /*optional=*/true, "List of txids of replaced transactions",
1394
2.56k
                {
1395
2.56k
                    {RPCResult::Type::STR_HEX, "", "The transaction id"},
1396
2.56k
                }},
1397
2.56k
            },
1398
2.56k
        },
1399
2.56k
        RPCExamples{
1400
2.56k
            HelpExampleRpc("submitpackage", R"(["raw-parent-tx-1", "raw-parent-tx-2", "raw-child-tx"])") +
1401
2.56k
            HelpExampleCli("submitpackage", R"('["raw-tx-without-unconfirmed-parents"]')")
1402
2.56k
        },
1403
2.56k
        [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
1404
2.56k
        {
1405
118
            const UniValue raw_transactions = request.params[0].get_array();
1406
118
            if (raw_transactions.empty() || raw_transactions.size() > MAX_PACKAGE_COUNT) {
1407
2
                throw JSONRPCError(RPC_INVALID_PARAMETER,
1408
2
                                   "Array must contain between 1 and " + ToString(MAX_PACKAGE_COUNT) + " transactions.");
1409
2
            }
1410
1411
            // Fee check needs to be run with chainstate and package context
1412
116
            const CFeeRate max_raw_tx_fee_rate{ParseFeeRate(self.Arg<UniValue>("maxfeerate"))};
1413
116
            std::optional<CFeeRate> client_maxfeerate{max_raw_tx_fee_rate};
1414
            // 0-value is special; it's mapped to no sanity check
1415
116
            if (max_raw_tx_fee_rate == CFeeRate(0)) {
1416
29
                client_maxfeerate = std::nullopt;
1417
29
            }
1418
1419
            // Burn sanity check is run with no context
1420
116
            const CAmount max_burn_amount = request.params[2].isNull() ? 0 : AmountFromValue(request.params[2]);
1421
1422
116
            std::vector<CTransactionRef> txns;
1423
116
            txns.reserve(raw_transactions.size());
1424
381
            for (const auto& rawtx : raw_transactions.getValues()) {
1425
381
                CMutableTransaction mtx;
1426
381
                if (!DecodeHexTx(mtx, rawtx.get_str())) {
1427
1
                    throw JSONRPCError(RPC_DESERIALIZATION_ERROR,
1428
1
                                       "TX decode failed: " + rawtx.get_str() + " Make sure the tx has at least one input.");
1429
1
                }
1430
1431
514
                for (const auto& out : mtx.vout) {
1432
514
                    if((out.scriptPubKey.IsUnspendable() || !out.scriptPubKey.HasValidOps()) && out.nValue > max_burn_amount) {
1433
1
                        throw JSONRPCTransactionError(TransactionError::MAX_BURN_EXCEEDED);
1434
1
                    }
1435
514
                }
1436
1437
379
                txns.emplace_back(MakeTransactionRef(std::move(mtx)));
1438
379
            }
1439
114
            CHECK_NONFATAL(!txns.empty());
1440
114
            if (txns.size() > 1 && !IsChildWithParentsTree(txns)) {
1441
2
                throw JSONRPCTransactionError(TransactionError::INVALID_PACKAGE, "package topology disallowed. not child-with-parents or parents depend on each other.");
1442
2
            }
1443
1444
112
            NodeContext& node = EnsureAnyNodeContext(request.context);
1445
112
            CTxMemPool& mempool = EnsureMemPool(node);
1446
112
            Chainstate& chainstate = EnsureChainman(node).ActiveChainstate();
1447
112
            const auto package_result = WITH_LOCK(::cs_main, return ProcessNewPackage(chainstate, mempool, txns, /*test_accept=*/ false, client_maxfeerate));
1448
1449
112
            std::string package_msg = "success";
1450
1451
            // First catch package-wide errors, continue if we can
1452
112
            switch(package_result.m_state.GetResult()) {
1453
66
                case PackageValidationResult::PCKG_RESULT_UNSET:
1454
66
                {
1455
                    // Belt-and-suspenders check; everything should be successful here
1456
66
                    CHECK_NONFATAL(package_result.m_tx_results.size() == txns.size());
1457
227
                    for (const auto& tx : txns) {
1458
227
                        CHECK_NONFATAL(mempool.exists(tx->GetHash()));
1459
227
                    }
1460
66
                    break;
1461
0
                }
1462
0
                case PackageValidationResult::PCKG_MEMPOOL_ERROR:
1463
0
                {
1464
                    // This only happens with internal bug; user should stop and report
1465
0
                    throw JSONRPCTransactionError(TransactionError::MEMPOOL_ERROR,
1466
0
                        package_result.m_state.GetRejectReason());
1467
0
                }
1468
13
                case PackageValidationResult::PCKG_POLICY:
1469
46
                case PackageValidationResult::PCKG_TX:
1470
46
                {
1471
                    // Package-wide error we want to return, but we also want to return individual responses
1472
46
                    package_msg = package_result.m_state.ToString();
1473
46
                    CHECK_NONFATAL(package_result.m_tx_results.size() == txns.size() ||
1474
46
                            package_result.m_tx_results.empty());
1475
46
                    break;
1476
13
                }
1477
112
            }
1478
1479
112
            size_t num_broadcast{0};
1480
371
            for (const auto& tx : txns) {
1481
                // We don't want to re-submit the txn for validation in BroadcastTransaction
1482
371
                if (!mempool.exists(tx->GetHash())) {
1483
82
                    continue;
1484
82
                }
1485
1486
                // We do not expect an error here; we are only broadcasting things already/still in mempool
1487
289
                std::string err_string;
1488
289
                const auto err = BroadcastTransaction(node,
1489
289
                                                      tx,
1490
289
                                                      err_string,
1491
289
                                                      /*max_tx_fee=*/0,
1492
289
                                                      node::TxBroadcast::MEMPOOL_AND_BROADCAST_TO_ALL,
1493
289
                                                      /*wait_callback=*/true);
1494
289
                if (err != TransactionError::OK) {
1495
0
                    throw JSONRPCTransactionError(err,
1496
0
                        strprintf("transaction broadcast failed: %s (%d transactions were broadcast successfully)",
1497
0
                            err_string, num_broadcast));
1498
0
                }
1499
289
                num_broadcast++;
1500
289
            }
1501
1502
112
            UniValue rpc_result{UniValue::VOBJ};
1503
112
            rpc_result.pushKV("package_msg", package_msg);
1504
112
            UniValue tx_result_map{UniValue::VOBJ};
1505
112
            std::set<Txid> replaced_txids;
1506
371
            for (const auto& tx : txns) {
1507
371
                UniValue result_inner{UniValue::VOBJ};
1508
371
                result_inner.pushKV("txid", tx->GetHash().GetHex());
1509
371
                const auto wtxid_hex = tx->GetWitnessHash().GetHex();
1510
371
                auto it = package_result.m_tx_results.find(tx->GetWitnessHash());
1511
371
                if (it == package_result.m_tx_results.end()) {
1512
                    // No per-tx result for this wtxid
1513
                    // Current invariant: per-tx results are all-or-none (every member or empty on package abort).
1514
                    // If any exist yet this one is missing, it's an unexpected partial map.
1515
6
                    CHECK_NONFATAL(package_result.m_tx_results.empty());
1516
6
                    result_inner.pushKV("error", "package-not-validated");
1517
6
                    tx_result_map.pushKV(wtxid_hex, std::move(result_inner));
1518
6
                    continue;
1519
6
                }
1520
365
                const auto& tx_result = it->second;
1521
365
                switch(it->second.m_result_type) {
1522
0
                case MempoolAcceptResult::ResultType::DIFFERENT_WITNESS:
1523
0
                    result_inner.pushKV("other-wtxid", it->second.m_other_wtxid.value().GetHex());
1524
0
                    break;
1525
77
                case MempoolAcceptResult::ResultType::INVALID:
1526
77
                    result_inner.pushKV("error", it->second.m_state.ToString());
1527
77
                    break;
1528
200
                case MempoolAcceptResult::ResultType::VALID:
1529
288
                case MempoolAcceptResult::ResultType::MEMPOOL_ENTRY:
1530
288
                    result_inner.pushKV("vsize_adjusted", it->second.m_vsize.value());
1531
288
                    result_inner.pushKV("vsize", it->second.m_vsize.value());
1532
288
                    result_inner.pushKV("vsize_bip141", GetVirtualTransactionSize(*tx));
1533
288
                    UniValue fees(UniValue::VOBJ);
1534
288
                    fees.pushKV("base", ValueFromAmount(it->second.m_base_fees.value()));
1535
288
                    if (tx_result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
1536
                        // Effective feerate is not provided for MEMPOOL_ENTRY transactions even
1537
                        // though modified fees is known, because it is unknown whether package
1538
                        // feerate was used when it was originally submitted.
1539
200
                        fees.pushKV("effective-feerate", ValueFromAmount(tx_result.m_effective_feerate.value().GetFeePerK()));
1540
200
                        UniValue effective_includes_res(UniValue::VARR);
1541
268
                        for (const auto& wtxid : tx_result.m_wtxids_fee_calculations.value()) {
1542
268
                            effective_includes_res.push_back(wtxid.ToString());
1543
268
                        }
1544
200
                        fees.pushKV("effective-includes", std::move(effective_includes_res));
1545
200
                    }
1546
288
                    result_inner.pushKV("fees", std::move(fees));
1547
393
                    for (const auto& ptx : it->second.m_replaced_transactions) {
1548
393
                        replaced_txids.insert(ptx->GetHash());
1549
393
                    }
1550
288
                    break;
1551
365
                }
1552
365
                tx_result_map.pushKV(wtxid_hex, std::move(result_inner));
1553
365
            }
1554
112
            rpc_result.pushKV("tx-results", std::move(tx_result_map));
1555
112
            UniValue replaced_list(UniValue::VARR);
1556
393
            for (const auto& txid : replaced_txids) replaced_list.push_back(txid.ToString());
1557
112
            rpc_result.pushKV("replaced-transactions", std::move(replaced_list));
1558
112
            return rpc_result;
1559
112
        },
1560
2.56k
    };
1561
2.56k
}
1562
1563
void RegisterMempoolRPCCommands(CRPCTable& t)
1564
1.34k
{
1565
1.34k
    static const CRPCCommand commands[]{
1566
1.34k
        {"rawtransactions", &sendrawtransaction},
1567
1.34k
        {"rawtransactions", &getprivatebroadcastinfo},
1568
1.34k
        {"rawtransactions", &abortprivatebroadcast},
1569
1.34k
        {"rawtransactions", &testmempoolaccept},
1570
1.34k
        {"blockchain", &getmempoolancestors},
1571
1.34k
        {"blockchain", &getmempooldescendants},
1572
1.34k
        {"blockchain", &getmempoolentry},
1573
1.34k
        {"blockchain", &getmempoolcluster},
1574
1.34k
        {"blockchain", &gettxspendingprevout},
1575
1.34k
        {"blockchain", &getmempoolinfo},
1576
1.34k
        {"hidden", &getmempoolfeeratediagram},
1577
1.34k
        {"blockchain", &getrawmempool},
1578
1.34k
        {"blockchain", &importmempool},
1579
1.34k
        {"blockchain", &savemempool},
1580
1.34k
        {"hidden", &getorphantxs},
1581
1.34k
        {"rawtransactions", &submitpackage},
1582
1.34k
    };
1583
21.5k
    for (const auto& c : commands) {
1584
21.5k
        t.appendCommand(c.name, &c);
1585
21.5k
    }
1586
1.34k
}