Coverage Report

Created: 2026-09-14 20:36

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