LCOV - code coverage report
Current view: top level - src/rpc - mempool.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 569 585 97.3 %
Date: 2022-04-21 14:51:19 Functions: 22 22 100.0 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 90 98 91.8 %

           Branch data     Line data    Source code
#       1                 :            : // Copyright (c) 2010 Satoshi Nakamoto
#       2                 :            : // Copyright (c) 2009-2022 The Bitcoin Core developers
#       3                 :            : // Distributed under the MIT software license, see the accompanying
#       4                 :            : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#       5                 :            : 
#       6                 :            : #include <rpc/blockchain.h>
#       7                 :            : 
#       8                 :            : #include <core_io.h>
#       9                 :            : #include <fs.h>
#      10                 :            : #include <policy/rbf.h>
#      11                 :            : #include <primitives/transaction.h>
#      12                 :            : #include <rpc/server.h>
#      13                 :            : #include <rpc/server_util.h>
#      14                 :            : #include <rpc/util.h>
#      15                 :            : #include <txmempool.h>
#      16                 :            : #include <univalue.h>
#      17                 :            : #include <util/moneystr.h>
#      18                 :            : #include <validation.h>
#      19                 :            : 
#      20                 :            : using node::DEFAULT_MAX_RAW_TX_FEE_RATE;
#      21                 :            : using node::NodeContext;
#      22                 :            : 
#      23                 :            : static RPCHelpMan sendrawtransaction()
#      24                 :      12786 : {
#      25                 :      12786 :     return RPCHelpMan{"sendrawtransaction",
#      26                 :      12786 :         "\nSubmit a raw transaction (serialized, hex-encoded) to local node and network.\n"
#      27                 :      12786 :         "\nThe transaction will be sent unconditionally to all peers, so using sendrawtransaction\n"
#      28                 :      12786 :         "for manual rebroadcast may degrade privacy by leaking the transaction's origin, as\n"
#      29                 :      12786 :         "nodes will normally not rebroadcast non-wallet transactions already in their mempool.\n"
#      30                 :      12786 :         "\nA specific exception, RPC_TRANSACTION_ALREADY_IN_CHAIN, may throw if the transaction cannot be added to the mempool.\n"
#      31                 :      12786 :         "\nRelated RPCs: createrawtransaction, signrawtransactionwithkey\n",
#      32                 :      12786 :         {
#      33                 :      12786 :             {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"},
#      34                 :      12786 :             {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())},
#      35                 :      12786 :              "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT +
#      36                 :      12786 :                  "/kvB.\nSet to 0 to accept any fee rate.\n"},
#      37                 :      12786 :         },
#      38                 :      12786 :         RPCResult{
#      39                 :      12786 :             RPCResult::Type::STR_HEX, "", "The transaction hash in hex"
#      40                 :      12786 :         },
#      41                 :      12786 :         RPCExamples{
#      42                 :      12786 :             "\nCreate a transaction\n"
#      43                 :      12786 :             + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") +
#      44                 :      12786 :             "Sign the transaction, and get back the hex\n"
#      45                 :      12786 :             + HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") +
#      46                 :      12786 :             "\nSend the transaction (signed hex)\n"
#      47                 :      12786 :             + HelpExampleCli("sendrawtransaction", "\"signedhex\"") +
#      48                 :      12786 :             "\nAs a JSON-RPC call\n"
#      49                 :      12786 :             + HelpExampleRpc("sendrawtransaction", "\"signedhex\"")
#      50                 :      12786 :                 },
#      51                 :      12786 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#      52                 :      12786 :         {
#      53                 :      11190 :             RPCTypeCheck(request.params, {
#      54                 :      11190 :                 UniValue::VSTR,
#      55                 :      11190 :                 UniValueType(), // VNUM or VSTR, checked inside AmountFromValue()
#      56                 :      11190 :             });
#      57                 :            : 
#      58                 :      11190 :             CMutableTransaction mtx;
#      59         [ +  + ]:      11190 :             if (!DecodeHexTx(mtx, request.params[0].get_str())) {
#      60                 :          4 :                 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input.");
#      61                 :          4 :             }
#      62                 :      11186 :             CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
#      63                 :            : 
#      64         [ +  + ]:      11186 :             const CFeeRate max_raw_tx_fee_rate = request.params[1].isNull() ?
#      65                 :       2197 :                                                      DEFAULT_MAX_RAW_TX_FEE_RATE :
#      66                 :      11186 :                                                      CFeeRate(AmountFromValue(request.params[1]));
#      67                 :            : 
#      68                 :      11186 :             int64_t virtual_size = GetVirtualTransactionSize(*tx);
#      69                 :      11186 :             CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size);
#      70                 :            : 
#      71                 :      11186 :             std::string err_string;
#      72                 :      11186 :             AssertLockNotHeld(cs_main);
#      73                 :      11186 :             NodeContext& node = EnsureAnyNodeContext(request.context);
#      74                 :      11186 :             const TransactionError err = BroadcastTransaction(node, tx, err_string, max_raw_tx_fee, /*relay=*/true, /*wait_callback=*/true);
#      75         [ +  + ]:      11186 :             if (TransactionError::OK != err) {
#      76                 :       4221 :                 throw JSONRPCTransactionError(err, err_string);
#      77                 :       4221 :             }
#      78                 :            : 
#      79                 :       6965 :             return tx->GetHash().GetHex();
#      80                 :      11186 :         },
#      81                 :      12786 :     };
#      82                 :      12786 : }
#      83                 :            : 
#      84                 :            : static RPCHelpMan testmempoolaccept()
#      85                 :       6815 : {
#      86                 :       6815 :     return RPCHelpMan{"testmempoolaccept",
#      87                 :       6815 :         "\nReturns result of mempool acceptance tests indicating if raw transaction(s) (serialized, hex-encoded) would be accepted by mempool.\n"
#      88                 :       6815 :         "\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"
#      89                 :       6815 :         "\nIf one transaction fails, other transactions may not be fully validated (the 'allowed' key will be blank).\n"
#      90                 :       6815 :         "\nThe maximum number of transactions allowed is " + ToString(MAX_PACKAGE_COUNT) + ".\n"
#      91                 :       6815 :         "\nThis checks if transactions violate the consensus or policy rules.\n"
#      92                 :       6815 :         "\nSee sendrawtransaction call.\n",
#      93                 :       6815 :         {
#      94                 :       6815 :             {"rawtxs", RPCArg::Type::ARR, RPCArg::Optional::NO, "An array of hex strings of raw transactions.",
#      95                 :       6815 :                 {
#      96                 :       6815 :                     {"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
#      97                 :       6815 :                 },
#      98                 :       6815 :             },
#      99                 :       6815 :             {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())},
#     100                 :       6815 :              "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT + "/kvB\n"},
#     101                 :       6815 :         },
#     102                 :       6815 :         RPCResult{
#     103                 :       6815 :             RPCResult::Type::ARR, "", "The result of the mempool acceptance test for each raw transaction in the input array.\n"
#     104                 :       6815 :                                       "Returns results for each transaction in the same order they were passed in.\n"
#     105                 :       6815 :                                       "Transactions that cannot be fully validated due to failures in other transactions will not contain an 'allowed' result.\n",
#     106                 :       6815 :             {
#     107                 :       6815 :                 {RPCResult::Type::OBJ, "", "",
#     108                 :       6815 :                 {
#     109                 :       6815 :                     {RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
#     110                 :       6815 :                     {RPCResult::Type::STR_HEX, "wtxid", "The transaction witness hash in hex"},
#     111                 :       6815 :                     {RPCResult::Type::STR, "package-error", /*optional=*/true, "Package validation error, if any (only possible if rawtxs had more than 1 transaction)."},
#     112                 :       6815 :                     {RPCResult::Type::BOOL, "allowed", /*optional=*/true, "Whether this tx would be accepted to the mempool and pass client-specified maxfeerate. "
#     113                 :       6815 :                                                        "If not present, the tx was not fully validated due to a failure in another tx in the list."},
#     114                 :       6815 :                     {RPCResult::Type::NUM, "vsize", /*optional=*/true, "Virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted (only present when 'allowed' is true)"},
#     115                 :       6815 :                     {RPCResult::Type::OBJ, "fees", /*optional=*/true, "Transaction fees (only present if 'allowed' is true)",
#     116                 :       6815 :                     {
#     117                 :       6815 :                         {RPCResult::Type::STR_AMOUNT, "base", "transaction fee in " + CURRENCY_UNIT},
#     118                 :       6815 :                     }},
#     119                 :       6815 :                     {RPCResult::Type::STR, "reject-reason", /*optional=*/true, "Rejection string (only present when 'allowed' is false)"},
#     120                 :       6815 :                 }},
#     121                 :       6815 :             }
#     122                 :       6815 :         },
#     123                 :       6815 :         RPCExamples{
#     124                 :       6815 :             "\nCreate a transaction\n"
#     125                 :       6815 :             + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") +
#     126                 :       6815 :             "Sign the transaction, and get back the hex\n"
#     127                 :       6815 :             + HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") +
#     128                 :       6815 :             "\nTest acceptance of the transaction (signed hex)\n"
#     129                 :       6815 :             + HelpExampleCli("testmempoolaccept", R"('["signedhex"]')") +
#     130                 :       6815 :             "\nAs a JSON-RPC call\n"
#     131                 :       6815 :             + HelpExampleRpc("testmempoolaccept", "[\"signedhex\"]")
#     132                 :       6815 :                 },
#     133                 :       6815 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#     134                 :       6815 :         {
#     135                 :       5221 :             RPCTypeCheck(request.params, {
#     136                 :       5221 :                 UniValue::VARR,
#     137                 :       5221 :                 UniValueType(), // VNUM or VSTR, checked inside AmountFromValue()
#     138                 :       5221 :             });
#     139                 :       5221 :             const UniValue raw_transactions = request.params[0].get_array();
#     140 [ +  + ][ +  + ]:       5221 :             if (raw_transactions.size() < 1 || raw_transactions.size() > MAX_PACKAGE_COUNT) {
#     141                 :          2 :                 throw JSONRPCError(RPC_INVALID_PARAMETER,
#     142                 :          2 :                                    "Array must contain between 1 and " + ToString(MAX_PACKAGE_COUNT) + " transactions.");
#     143                 :          2 :             }
#     144                 :            : 
#     145         [ +  + ]:       5219 :             const CFeeRate max_raw_tx_fee_rate = request.params[1].isNull() ?
#     146                 :       5204 :                                                      DEFAULT_MAX_RAW_TX_FEE_RATE :
#     147                 :       5219 :                                                      CFeeRate(AmountFromValue(request.params[1]));
#     148                 :            : 
#     149                 :       5219 :             std::vector<CTransactionRef> txns;
#     150                 :       5219 :             txns.reserve(raw_transactions.size());
#     151         [ +  + ]:       5743 :             for (const auto& rawtx : raw_transactions.getValues()) {
#     152                 :       5743 :                 CMutableTransaction mtx;
#     153         [ +  + ]:       5743 :                 if (!DecodeHexTx(mtx, rawtx.get_str())) {
#     154                 :          1 :                     throw JSONRPCError(RPC_DESERIALIZATION_ERROR,
#     155                 :          1 :                                        "TX decode failed: " + rawtx.get_str() + " Make sure the tx has at least one input.");
#     156                 :          1 :                 }
#     157                 :       5742 :                 txns.emplace_back(MakeTransactionRef(std::move(mtx)));
#     158                 :       5742 :             }
#     159                 :            : 
#     160                 :       5218 :             NodeContext& node = EnsureAnyNodeContext(request.context);
#     161                 :       5218 :             CTxMemPool& mempool = EnsureMemPool(node);
#     162                 :       5218 :             ChainstateManager& chainman = EnsureChainman(node);
#     163                 :       5218 :             CChainState& chainstate = chainman.ActiveChainstate();
#     164                 :       5218 :             const PackageMempoolAcceptResult package_result = [&] {
#     165                 :       5217 :                 LOCK(::cs_main);
#     166         [ +  + ]:       5217 :                 if (txns.size() > 1) return ProcessNewPackage(chainstate, mempool, txns, /*test_accept=*/true);
#     167                 :       5155 :                 return PackageMempoolAcceptResult(txns[0]->GetWitnessHash(),
#     168                 :       5155 :                                                   chainman.ProcessTransaction(txns[0], /*test_accept=*/true));
#     169                 :       5217 :             }();
#     170                 :            : 
#     171                 :       5218 :             UniValue rpc_result(UniValue::VARR);
#     172                 :            :             // We will check transaction fees while we iterate through txns in order. If any transaction fee
#     173                 :            :             // exceeds maxfeerate, we will leave the rest of the validation results blank, because it
#     174                 :            :             // doesn't make sense to return a validation result for a transaction if its ancestor(s) would
#     175                 :            :             // not be submitted.
#     176                 :       5218 :             bool exit_early{false};
#     177         [ +  + ]:       5742 :             for (const auto& tx : txns) {
#     178                 :       5742 :                 UniValue result_inner(UniValue::VOBJ);
#     179                 :       5742 :                 result_inner.pushKV("txid", tx->GetHash().GetHex());
#     180                 :       5742 :                 result_inner.pushKV("wtxid", tx->GetWitnessHash().GetHex());
#     181         [ +  + ]:       5742 :                 if (package_result.m_state.GetResult() == PackageValidationResult::PCKG_POLICY) {
#     182                 :         89 :                     result_inner.pushKV("package-error", package_result.m_state.GetRejectReason());
#     183                 :         89 :                 }
#     184                 :       5742 :                 auto it = package_result.m_tx_results.find(tx->GetWitnessHash());
#     185 [ +  + ][ +  + ]:       5742 :                 if (exit_early || it == package_result.m_tx_results.end()) {
#                 [ +  + ]
#     186                 :            :                     // Validation unfinished. Just return the txid and wtxid.
#     187                 :         98 :                     rpc_result.push_back(result_inner);
#     188                 :         98 :                     continue;
#     189                 :         98 :                 }
#     190                 :       5644 :                 const auto& tx_result = it->second;
#     191                 :            :                 // Package testmempoolaccept doesn't allow transactions to already be in the mempool.
#     192         [ -  + ]:       5644 :                 CHECK_NONFATAL(tx_result.m_result_type != MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
#     193         [ +  + ]:       5644 :                 if (tx_result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
#     194                 :       1557 :                     const CAmount fee = tx_result.m_base_fees.value();
#     195                 :            :                     // Check that fee does not exceed maximum fee
#     196                 :       1557 :                     const int64_t virtual_size = tx_result.m_vsize.value();
#     197                 :       1557 :                     const CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size);
#     198 [ +  + ][ +  + ]:       1557 :                     if (max_raw_tx_fee && fee > max_raw_tx_fee) {
#     199                 :          6 :                         result_inner.pushKV("allowed", false);
#     200                 :          6 :                         result_inner.pushKV("reject-reason", "max-fee-exceeded");
#     201                 :          6 :                         exit_early = true;
#     202                 :       1551 :                     } else {
#     203                 :            :                         // Only return the fee and vsize if the transaction would pass ATMP.
#     204                 :            :                         // These can be used to calculate the feerate.
#     205                 :       1551 :                         result_inner.pushKV("allowed", true);
#     206                 :       1551 :                         result_inner.pushKV("vsize", virtual_size);
#     207                 :       1551 :                         UniValue fees(UniValue::VOBJ);
#     208                 :       1551 :                         fees.pushKV("base", ValueFromAmount(fee));
#     209                 :       1551 :                         result_inner.pushKV("fees", fees);
#     210                 :       1551 :                     }
#     211                 :       4087 :                 } else {
#     212                 :       4087 :                     result_inner.pushKV("allowed", false);
#     213                 :       4087 :                     const TxValidationState state = tx_result.m_state;
#     214         [ +  + ]:       4087 :                     if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
#     215                 :          6 :                         result_inner.pushKV("reject-reason", "missing-inputs");
#     216                 :       4081 :                     } else {
#     217                 :       4081 :                         result_inner.pushKV("reject-reason", state.GetRejectReason());
#     218                 :       4081 :                     }
#     219                 :       4087 :                 }
#     220                 :       5644 :                 rpc_result.push_back(result_inner);
#     221                 :       5644 :             }
#     222                 :       5218 :             return rpc_result;
#     223                 :       5218 :         },
#     224                 :       6815 :     };
#     225                 :       6815 : }
#     226                 :            : 
#     227                 :            : static std::vector<RPCResult> MempoolEntryDescription()
#     228                 :      15961 : {
#     229                 :      15961 :     return {
#     230                 :      15961 :         RPCResult{RPCResult::Type::NUM, "vsize", "virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted."},
#     231                 :      15961 :         RPCResult{RPCResult::Type::NUM, "weight", "transaction weight as defined in BIP 141."},
#     232                 :      15961 :         RPCResult{RPCResult::Type::STR_AMOUNT, "fee", /*optional=*/true,
#     233                 :      15961 :                   "transaction fee, denominated in " + CURRENCY_UNIT + " (DEPRECATED, returned only if config option -deprecatedrpc=fees is passed)"},
#     234                 :      15961 :         RPCResult{RPCResult::Type::STR_AMOUNT, "modifiedfee", /*optional=*/true,
#     235                 :      15961 :                   "transaction fee with fee deltas used for mining priority, denominated in " + CURRENCY_UNIT +
#     236                 :      15961 :                       " (DEPRECATED, returned only if config option -deprecatedrpc=fees is passed)"},
#     237                 :      15961 :         RPCResult{RPCResult::Type::NUM_TIME, "time", "local time transaction entered pool in seconds since 1 Jan 1970 GMT"},
#     238                 :      15961 :         RPCResult{RPCResult::Type::NUM, "height", "block height when transaction entered pool"},
#     239                 :      15961 :         RPCResult{RPCResult::Type::NUM, "descendantcount", "number of in-mempool descendant transactions (including this one)"},
#     240                 :      15961 :         RPCResult{RPCResult::Type::NUM, "descendantsize", "virtual transaction size of in-mempool descendants (including this one)"},
#     241                 :      15961 :         RPCResult{RPCResult::Type::STR_AMOUNT, "descendantfees", /*optional=*/true,
#     242                 :      15961 :                   "transaction fees of in-mempool descendants (including this one) with fee deltas used for mining priority, denominated in " +
#     243                 :      15961 :                       CURRENCY_ATOM + "s (DEPRECATED, returned only if config option -deprecatedrpc=fees is passed)"},
#     244                 :      15961 :         RPCResult{RPCResult::Type::NUM, "ancestorcount", "number of in-mempool ancestor transactions (including this one)"},
#     245                 :      15961 :         RPCResult{RPCResult::Type::NUM, "ancestorsize", "virtual transaction size of in-mempool ancestors (including this one)"},
#     246                 :      15961 :         RPCResult{RPCResult::Type::STR_AMOUNT, "ancestorfees", /*optional=*/true,
#     247                 :      15961 :                   "transaction fees of in-mempool ancestors (including this one) with fee deltas used for mining priority, denominated in " +
#     248                 :      15961 :                       CURRENCY_ATOM + "s (DEPRECATED, returned only if config option -deprecatedrpc=fees is passed)"},
#     249                 :      15961 :         RPCResult{RPCResult::Type::STR_HEX, "wtxid", "hash of serialized transaction, including witness data"},
#     250                 :      15961 :         RPCResult{RPCResult::Type::OBJ, "fees", "",
#     251                 :      15961 :             {
#     252                 :      15961 :                 RPCResult{RPCResult::Type::STR_AMOUNT, "base", "transaction fee, denominated in " + CURRENCY_UNIT},
#     253                 :      15961 :                 RPCResult{RPCResult::Type::STR_AMOUNT, "modified", "transaction fee with fee deltas used for mining priority, denominated in " + CURRENCY_UNIT},
#     254                 :      15961 :                 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},
#     255                 :      15961 :                 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},
#     256                 :      15961 :             }},
#     257                 :      15961 :         RPCResult{RPCResult::Type::ARR, "depends", "unconfirmed transactions used as inputs for this transaction",
#     258                 :      15961 :             {RPCResult{RPCResult::Type::STR_HEX, "transactionid", "parent transaction id"}}},
#     259                 :      15961 :         RPCResult{RPCResult::Type::ARR, "spentby", "unconfirmed transactions spending outputs from this transaction",
#     260                 :      15961 :             {RPCResult{RPCResult::Type::STR_HEX, "transactionid", "child transaction id"}}},
#     261                 :      15961 :         RPCResult{RPCResult::Type::BOOL, "bip125-replaceable", "Whether this transaction could be replaced due to BIP125 (replace-by-fee)"},
#     262                 :      15961 :         RPCResult{RPCResult::Type::BOOL, "unbroadcast", "Whether this transaction is currently unbroadcast (initial broadcast not yet acknowledged by any peers)"},
#     263                 :      15961 :     };
#     264                 :      15961 : }
#     265                 :            : 
#     266                 :            : static void entryToJSON(const CTxMemPool& pool, UniValue& info, const CTxMemPoolEntry& e) EXCLUSIVE_LOCKS_REQUIRED(pool.cs)
#     267                 :       1346 : {
#     268                 :       1346 :     AssertLockHeld(pool.cs);
#     269                 :            : 
#     270                 :       1346 :     info.pushKV("vsize", (int)e.GetTxSize());
#     271                 :       1346 :     info.pushKV("weight", (int)e.GetTxWeight());
#     272                 :            :     // TODO: top-level fee fields are deprecated. deprecated_fee_fields_enabled blocks should be removed in v24
#     273                 :       1346 :     const bool deprecated_fee_fields_enabled{IsDeprecatedRPCEnabled("fees")};
#     274         [ +  + ]:       1346 :     if (deprecated_fee_fields_enabled) {
#     275                 :          3 :         info.pushKV("fee", ValueFromAmount(e.GetFee()));
#     276                 :          3 :         info.pushKV("modifiedfee", ValueFromAmount(e.GetModifiedFee()));
#     277                 :          3 :     }
#     278                 :       1346 :     info.pushKV("time", count_seconds(e.GetTime()));
#     279                 :       1346 :     info.pushKV("height", (int)e.GetHeight());
#     280                 :       1346 :     info.pushKV("descendantcount", e.GetCountWithDescendants());
#     281                 :       1346 :     info.pushKV("descendantsize", e.GetSizeWithDescendants());
#     282         [ +  + ]:       1346 :     if (deprecated_fee_fields_enabled) {
#     283                 :          3 :         info.pushKV("descendantfees", e.GetModFeesWithDescendants());
#     284                 :          3 :     }
#     285                 :       1346 :     info.pushKV("ancestorcount", e.GetCountWithAncestors());
#     286                 :       1346 :     info.pushKV("ancestorsize", e.GetSizeWithAncestors());
#     287         [ +  + ]:       1346 :     if (deprecated_fee_fields_enabled) {
#     288                 :          3 :         info.pushKV("ancestorfees", e.GetModFeesWithAncestors());
#     289                 :          3 :     }
#     290                 :       1346 :     info.pushKV("wtxid", pool.vTxHashes[e.vTxHashesIdx].first.ToString());
#     291                 :            : 
#     292                 :       1346 :     UniValue fees(UniValue::VOBJ);
#     293                 :       1346 :     fees.pushKV("base", ValueFromAmount(e.GetFee()));
#     294                 :       1346 :     fees.pushKV("modified", ValueFromAmount(e.GetModifiedFee()));
#     295                 :       1346 :     fees.pushKV("ancestor", ValueFromAmount(e.GetModFeesWithAncestors()));
#     296                 :       1346 :     fees.pushKV("descendant", ValueFromAmount(e.GetModFeesWithDescendants()));
#     297                 :       1346 :     info.pushKV("fees", fees);
#     298                 :            : 
#     299                 :       1346 :     const CTransaction& tx = e.GetTx();
#     300                 :       1346 :     std::set<std::string> setDepends;
#     301         [ +  + ]:       1346 :     for (const CTxIn& txin : tx.vin)
#     302                 :      11128 :     {
#     303         [ +  + ]:      11128 :         if (pool.exists(GenTxid::Txid(txin.prevout.hash)))
#     304                 :       7033 :             setDepends.insert(txin.prevout.hash.ToString());
#     305                 :      11128 :     }
#     306                 :            : 
#     307                 :       1346 :     UniValue depends(UniValue::VARR);
#     308         [ +  + ]:       1346 :     for (const std::string& dep : setDepends)
#     309                 :       7033 :     {
#     310                 :       7033 :         depends.push_back(dep);
#     311                 :       7033 :     }
#     312                 :            : 
#     313                 :       1346 :     info.pushKV("depends", depends);
#     314                 :            : 
#     315                 :       1346 :     UniValue spent(UniValue::VARR);
#     316                 :       1346 :     const CTxMemPool::txiter& it = pool.mapTx.find(tx.GetHash());
#     317                 :       1346 :     const CTxMemPoolEntry::Children& children = it->GetMemPoolChildrenConst();
#     318         [ +  + ]:       5783 :     for (const CTxMemPoolEntry& child : children) {
#     319                 :       5783 :         spent.push_back(child.GetTx().GetHash().ToString());
#     320                 :       5783 :     }
#     321                 :            : 
#     322                 :       1346 :     info.pushKV("spentby", spent);
#     323                 :            : 
#     324                 :            :     // Add opt-in RBF status
#     325                 :       1346 :     bool rbfStatus = false;
#     326                 :       1346 :     RBFTransactionState rbfState = IsRBFOptIn(tx, pool);
#     327         [ -  + ]:       1346 :     if (rbfState == RBFTransactionState::UNKNOWN) {
#     328                 :          0 :         throw JSONRPCError(RPC_MISC_ERROR, "Transaction is not in mempool");
#     329         [ +  + ]:       1346 :     } else if (rbfState == RBFTransactionState::REPLACEABLE_BIP125) {
#     330                 :        997 :         rbfStatus = true;
#     331                 :        997 :     }
#     332                 :            : 
#     333                 :       1346 :     info.pushKV("bip125-replaceable", rbfStatus);
#     334                 :       1346 :     info.pushKV("unbroadcast", pool.IsUnbroadcastTx(tx.GetHash()));
#     335                 :       1346 : }
#     336                 :            : 
#     337                 :            : UniValue MempoolToJSON(const CTxMemPool& pool, bool verbose, bool include_mempool_sequence)
#     338                 :       8996 : {
#     339         [ +  + ]:       8996 :     if (verbose) {
#     340         [ -  + ]:         13 :         if (include_mempool_sequence) {
#     341                 :          0 :             throw JSONRPCError(RPC_INVALID_PARAMETER, "Verbose results cannot contain mempool sequence values.");
#     342                 :          0 :         }
#     343                 :         13 :         LOCK(pool.cs);
#     344                 :         13 :         UniValue o(UniValue::VOBJ);
#     345         [ +  + ]:        216 :         for (const CTxMemPoolEntry& e : pool.mapTx) {
#     346                 :        216 :             const uint256& hash = e.GetTx().GetHash();
#     347                 :        216 :             UniValue info(UniValue::VOBJ);
#     348                 :        216 :             entryToJSON(pool, info, e);
#     349                 :            :             // Mempool has unique entries so there is no advantage in using
#     350                 :            :             // UniValue::pushKV, which checks if the key already exists in O(N).
#     351                 :            :             // UniValue::__pushKV is used instead which currently is O(1).
#     352                 :        216 :             o.__pushKV(hash.ToString(), info);
#     353                 :        216 :         }
#     354                 :         13 :         return o;
#     355                 :       8983 :     } else {
#     356                 :       8983 :         uint64_t mempool_sequence;
#     357                 :       8983 :         std::vector<uint256> vtxid;
#     358                 :       8983 :         {
#     359                 :       8983 :             LOCK(pool.cs);
#     360                 :       8983 :             pool.queryHashes(vtxid);
#     361                 :       8983 :             mempool_sequence = pool.GetSequence();
#     362                 :       8983 :         }
#     363                 :       8983 :         UniValue a(UniValue::VARR);
#     364         [ +  + ]:       8983 :         for (const uint256& hash : vtxid)
#     365                 :     393787 :             a.push_back(hash.ToString());
#     366                 :            : 
#     367         [ +  - ]:       8983 :         if (!include_mempool_sequence) {
#     368                 :       8983 :             return a;
#     369                 :       8983 :         } else {
#     370                 :          0 :             UniValue o(UniValue::VOBJ);
#     371                 :          0 :             o.pushKV("txids", a);
#     372                 :          0 :             o.pushKV("mempool_sequence", mempool_sequence);
#     373                 :          0 :             return o;
#     374                 :          0 :         }
#     375                 :       8983 :     }
#     376                 :       8996 : }
#     377                 :            : 
#     378                 :            : static RPCHelpMan getrawmempool()
#     379                 :      10589 : {
#     380                 :      10589 :     return RPCHelpMan{"getrawmempool",
#     381                 :      10589 :         "\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n"
#     382                 :      10589 :         "\nHint: use getmempoolentry to fetch a specific transaction from the mempool.\n",
#     383                 :      10589 :         {
#     384                 :      10589 :             {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"},
#     385                 :      10589 :             {"mempool_sequence", RPCArg::Type::BOOL, RPCArg::Default{false}, "If verbose=false, returns a json object with transaction list and mempool sequence number attached."},
#     386                 :      10589 :         },
#     387                 :      10589 :         {
#     388                 :      10589 :             RPCResult{"for verbose = false",
#     389                 :      10589 :                 RPCResult::Type::ARR, "", "",
#     390                 :      10589 :                 {
#     391                 :      10589 :                     {RPCResult::Type::STR_HEX, "", "The transaction id"},
#     392                 :      10589 :                 }},
#     393                 :      10589 :             RPCResult{"for verbose = true",
#     394                 :      10589 :                 RPCResult::Type::OBJ_DYN, "", "",
#     395                 :      10589 :                 {
#     396                 :      10589 :                     {RPCResult::Type::OBJ, "transactionid", "", MempoolEntryDescription()},
#     397                 :      10589 :                 }},
#     398                 :      10589 :             RPCResult{"for verbose = false and mempool_sequence = true",
#     399                 :      10589 :                 RPCResult::Type::OBJ, "", "",
#     400                 :      10589 :                 {
#     401                 :      10589 :                     {RPCResult::Type::ARR, "txids", "",
#     402                 :      10589 :                     {
#     403                 :      10589 :                         {RPCResult::Type::STR_HEX, "", "The transaction id"},
#     404                 :      10589 :                     }},
#     405                 :      10589 :                     {RPCResult::Type::NUM, "mempool_sequence", "The mempool sequence value."},
#     406                 :      10589 :                 }},
#     407                 :      10589 :         },
#     408                 :      10589 :         RPCExamples{
#     409                 :      10589 :             HelpExampleCli("getrawmempool", "true")
#     410                 :      10589 :             + HelpExampleRpc("getrawmempool", "true")
#     411                 :      10589 :         },
#     412                 :      10589 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#     413                 :      10589 : {
#     414                 :       8995 :     bool fVerbose = false;
#     415         [ +  + ]:       8995 :     if (!request.params[0].isNull())
#     416                 :         16 :         fVerbose = request.params[0].get_bool();
#     417                 :            : 
#     418                 :       8995 :     bool include_mempool_sequence = false;
#     419         [ -  + ]:       8995 :     if (!request.params[1].isNull()) {
#     420                 :          0 :         include_mempool_sequence = request.params[1].get_bool();
#     421                 :          0 :     }
#     422                 :            : 
#     423                 :       8995 :     return MempoolToJSON(EnsureAnyMemPool(request.context), fVerbose, include_mempool_sequence);
#     424                 :       8995 : },
#     425                 :      10589 :     };
#     426                 :      10589 : }
#     427                 :            : 
#     428                 :            : static RPCHelpMan getmempoolancestors()
#     429                 :       1645 : {
#     430                 :       1645 :     return RPCHelpMan{"getmempoolancestors",
#     431                 :       1645 :         "\nIf txid is in the mempool, returns all in-mempool ancestors.\n",
#     432                 :       1645 :         {
#     433                 :       1645 :             {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
#     434                 :       1645 :             {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"},
#     435                 :       1645 :         },
#     436                 :       1645 :         {
#     437                 :       1645 :             RPCResult{"for verbose = false",
#     438                 :       1645 :                 RPCResult::Type::ARR, "", "",
#     439                 :       1645 :                 {{RPCResult::Type::STR_HEX, "", "The transaction id of an in-mempool ancestor transaction"}}},
#     440                 :       1645 :             RPCResult{"for verbose = true",
#     441                 :       1645 :                 RPCResult::Type::OBJ_DYN, "", "",
#     442                 :       1645 :                 {
#     443                 :       1645 :                     {RPCResult::Type::OBJ, "transactionid", "", MempoolEntryDescription()},
#     444                 :       1645 :                 }},
#     445                 :       1645 :         },
#     446                 :       1645 :         RPCExamples{
#     447                 :       1645 :             HelpExampleCli("getmempoolancestors", "\"mytxid\"")
#     448                 :       1645 :             + HelpExampleRpc("getmempoolancestors", "\"mytxid\"")
#     449                 :       1645 :         },
#     450                 :       1645 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#     451                 :       1645 : {
#     452                 :         51 :     bool fVerbose = false;
#     453         [ +  + ]:         51 :     if (!request.params[1].isNull())
#     454                 :         26 :         fVerbose = request.params[1].get_bool();
#     455                 :            : 
#     456                 :         51 :     uint256 hash = ParseHashV(request.params[0], "parameter 1");
#     457                 :            : 
#     458                 :         51 :     const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
#     459                 :         51 :     LOCK(mempool.cs);
#     460                 :            : 
#     461                 :         51 :     CTxMemPool::txiter it = mempool.mapTx.find(hash);
#     462         [ -  + ]:         51 :     if (it == mempool.mapTx.end()) {
#     463                 :          0 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool");
#     464                 :          0 :     }
#     465                 :            : 
#     466                 :         51 :     CTxMemPool::setEntries setAncestors;
#     467                 :         51 :     uint64_t noLimit = std::numeric_limits<uint64_t>::max();
#     468                 :         51 :     std::string dummy;
#     469                 :         51 :     mempool.CalculateMemPoolAncestors(*it, setAncestors, noLimit, noLimit, noLimit, noLimit, dummy, false);
#     470                 :            : 
#     471         [ +  + ]:         51 :     if (!fVerbose) {
#     472                 :         25 :         UniValue o(UniValue::VARR);
#     473         [ +  + ]:        300 :         for (CTxMemPool::txiter ancestorIt : setAncestors) {
#     474                 :        300 :             o.push_back(ancestorIt->GetTx().GetHash().ToString());
#     475                 :        300 :         }
#     476                 :         25 :         return o;
#     477                 :         26 :     } else {
#     478                 :         26 :         UniValue o(UniValue::VOBJ);
#     479         [ +  + ]:        324 :         for (CTxMemPool::txiter ancestorIt : setAncestors) {
#     480                 :        324 :             const CTxMemPoolEntry &e = *ancestorIt;
#     481                 :        324 :             const uint256& _hash = e.GetTx().GetHash();
#     482                 :        324 :             UniValue info(UniValue::VOBJ);
#     483                 :        324 :             entryToJSON(mempool, info, e);
#     484                 :        324 :             o.pushKV(_hash.ToString(), info);
#     485                 :        324 :         }
#     486                 :         26 :         return o;
#     487                 :         26 :     }
#     488                 :         51 : },
#     489                 :       1645 :     };
#     490                 :       1645 : }
#     491                 :            : 
#     492                 :            : static RPCHelpMan getmempooldescendants()
#     493                 :       1645 : {
#     494                 :       1645 :     return RPCHelpMan{"getmempooldescendants",
#     495                 :       1645 :         "\nIf txid is in the mempool, returns all in-mempool descendants.\n",
#     496                 :       1645 :         {
#     497                 :       1645 :             {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
#     498                 :       1645 :             {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"},
#     499                 :       1645 :         },
#     500                 :       1645 :         {
#     501                 :       1645 :             RPCResult{"for verbose = false",
#     502                 :       1645 :                 RPCResult::Type::ARR, "", "",
#     503                 :       1645 :                 {{RPCResult::Type::STR_HEX, "", "The transaction id of an in-mempool descendant transaction"}}},
#     504                 :       1645 :             RPCResult{"for verbose = true",
#     505                 :       1645 :                 RPCResult::Type::OBJ_DYN, "", "",
#     506                 :       1645 :                 {
#     507                 :       1645 :                     {RPCResult::Type::OBJ, "transactionid", "", MempoolEntryDescription()},
#     508                 :       1645 :                 }},
#     509                 :       1645 :         },
#     510                 :       1645 :         RPCExamples{
#     511                 :       1645 :             HelpExampleCli("getmempooldescendants", "\"mytxid\"")
#     512                 :       1645 :             + HelpExampleRpc("getmempooldescendants", "\"mytxid\"")
#     513                 :       1645 :         },
#     514                 :       1645 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#     515                 :       1645 : {
#     516                 :         51 :     bool fVerbose = false;
#     517         [ +  + ]:         51 :     if (!request.params[1].isNull())
#     518                 :         26 :         fVerbose = request.params[1].get_bool();
#     519                 :            : 
#     520                 :         51 :     uint256 hash = ParseHashV(request.params[0], "parameter 1");
#     521                 :            : 
#     522                 :         51 :     const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
#     523                 :         51 :     LOCK(mempool.cs);
#     524                 :            : 
#     525                 :         51 :     CTxMemPool::txiter it = mempool.mapTx.find(hash);
#     526         [ -  + ]:         51 :     if (it == mempool.mapTx.end()) {
#     527                 :          0 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool");
#     528                 :          0 :     }
#     529                 :            : 
#     530                 :         51 :     CTxMemPool::setEntries setDescendants;
#     531                 :         51 :     mempool.CalculateDescendants(it, setDescendants);
#     532                 :            :     // CTxMemPool::CalculateDescendants will include the given tx
#     533                 :         51 :     setDescendants.erase(it);
#     534                 :            : 
#     535         [ +  + ]:         51 :     if (!fVerbose) {
#     536                 :         25 :         UniValue o(UniValue::VARR);
#     537         [ +  + ]:        300 :         for (CTxMemPool::txiter descendantIt : setDescendants) {
#     538                 :        300 :             o.push_back(descendantIt->GetTx().GetHash().ToString());
#     539                 :        300 :         }
#     540                 :            : 
#     541                 :         25 :         return o;
#     542                 :         26 :     } else {
#     543                 :         26 :         UniValue o(UniValue::VOBJ);
#     544         [ +  + ]:        324 :         for (CTxMemPool::txiter descendantIt : setDescendants) {
#     545                 :        324 :             const CTxMemPoolEntry &e = *descendantIt;
#     546                 :        324 :             const uint256& _hash = e.GetTx().GetHash();
#     547                 :        324 :             UniValue info(UniValue::VOBJ);
#     548                 :        324 :             entryToJSON(mempool, info, e);
#     549                 :        324 :             o.pushKV(_hash.ToString(), info);
#     550                 :        324 :         }
#     551                 :         26 :         return o;
#     552                 :         26 :     }
#     553                 :         51 : },
#     554                 :       1645 :     };
#     555                 :       1645 : }
#     556                 :            : 
#     557                 :            : static RPCHelpMan getmempoolentry()
#     558                 :       2082 : {
#     559                 :       2082 :     return RPCHelpMan{"getmempoolentry",
#     560                 :       2082 :         "\nReturns mempool data for given transaction\n",
#     561                 :       2082 :         {
#     562                 :       2082 :             {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
#     563                 :       2082 :         },
#     564                 :       2082 :         RPCResult{
#     565                 :       2082 :             RPCResult::Type::OBJ, "", "", MempoolEntryDescription()},
#     566                 :       2082 :         RPCExamples{
#     567                 :       2082 :             HelpExampleCli("getmempoolentry", "\"mytxid\"")
#     568                 :       2082 :             + HelpExampleRpc("getmempoolentry", "\"mytxid\"")
#     569                 :       2082 :         },
#     570                 :       2082 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#     571                 :       2082 : {
#     572                 :        488 :     uint256 hash = ParseHashV(request.params[0], "parameter 1");
#     573                 :            : 
#     574                 :        488 :     const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
#     575                 :        488 :     LOCK(mempool.cs);
#     576                 :            : 
#     577                 :        488 :     CTxMemPool::txiter it = mempool.mapTx.find(hash);
#     578         [ +  + ]:        488 :     if (it == mempool.mapTx.end()) {
#     579                 :          6 :         throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool");
#     580                 :          6 :     }
#     581                 :            : 
#     582                 :        482 :     const CTxMemPoolEntry &e = *it;
#     583                 :        482 :     UniValue info(UniValue::VOBJ);
#     584                 :        482 :     entryToJSON(mempool, info, e);
#     585                 :        482 :     return info;
#     586                 :        488 : },
#     587                 :       2082 :     };
#     588                 :       2082 : }
#     589                 :            : 
#     590                 :            : UniValue MempoolInfoToJSON(const CTxMemPool& pool)
#     591                 :        910 : {
#     592                 :            :     // Make sure this call is atomic in the pool.
#     593                 :        910 :     LOCK(pool.cs);
#     594                 :        910 :     UniValue ret(UniValue::VOBJ);
#     595                 :        910 :     ret.pushKV("loaded", pool.IsLoaded());
#     596                 :        910 :     ret.pushKV("size", (int64_t)pool.size());
#     597                 :        910 :     ret.pushKV("bytes", (int64_t)pool.GetTotalTxSize());
#     598                 :        910 :     ret.pushKV("usage", (int64_t)pool.DynamicMemoryUsage());
#     599                 :        910 :     ret.pushKV("total_fee", ValueFromAmount(pool.GetTotalFee()));
#     600                 :        910 :     int64_t maxmempool{gArgs.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000};
#     601                 :        910 :     ret.pushKV("maxmempool", maxmempool);
#     602                 :        910 :     ret.pushKV("mempoolminfee", ValueFromAmount(std::max(pool.GetMinFee(maxmempool), ::minRelayTxFee).GetFeePerK()));
#     603                 :        910 :     ret.pushKV("minrelaytxfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()));
#     604                 :        910 :     ret.pushKV("unbroadcastcount", uint64_t{pool.GetUnbroadcastTxs().size()});
#     605                 :        910 :     return ret;
#     606                 :        910 : }
#     607                 :            : 
#     608                 :            : static RPCHelpMan getmempoolinfo()
#     609                 :       2503 : {
#     610                 :       2503 :     return RPCHelpMan{"getmempoolinfo",
#     611                 :       2503 :         "\nReturns details on the active state of the TX memory pool.\n",
#     612                 :       2503 :         {},
#     613                 :       2503 :         RPCResult{
#     614                 :       2503 :             RPCResult::Type::OBJ, "", "",
#     615                 :       2503 :             {
#     616                 :       2503 :                 {RPCResult::Type::BOOL, "loaded", "True if the mempool is fully loaded"},
#     617                 :       2503 :                 {RPCResult::Type::NUM, "size", "Current tx count"},
#     618                 :       2503 :                 {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"},
#     619                 :       2503 :                 {RPCResult::Type::NUM, "usage", "Total memory usage for the mempool"},
#     620                 :       2503 :                 {RPCResult::Type::STR_AMOUNT, "total_fee", "Total fees for the mempool in " + CURRENCY_UNIT + ", ignoring modified fees through prioritisetransaction"},
#     621                 :       2503 :                 {RPCResult::Type::NUM, "maxmempool", "Maximum memory usage for the mempool"},
#     622                 :       2503 :                 {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"},
#     623                 :       2503 :                 {RPCResult::Type::STR_AMOUNT, "minrelaytxfee", "Current minimum relay fee for transactions"},
#     624                 :       2503 :                 {RPCResult::Type::NUM, "unbroadcastcount", "Current number of transactions that haven't passed initial broadcast yet"}
#     625                 :       2503 :             }},
#     626                 :       2503 :         RPCExamples{
#     627                 :       2503 :             HelpExampleCli("getmempoolinfo", "")
#     628                 :       2503 :             + HelpExampleRpc("getmempoolinfo", "")
#     629                 :       2503 :         },
#     630                 :       2503 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#     631                 :       2503 : {
#     632                 :        909 :     return MempoolInfoToJSON(EnsureAnyMemPool(request.context));
#     633                 :        909 : },
#     634                 :       2503 :     };
#     635                 :       2503 : }
#     636                 :            : 
#     637                 :            : static RPCHelpMan savemempool()
#     638                 :       1596 : {
#     639                 :       1596 :     return RPCHelpMan{"savemempool",
#     640                 :       1596 :         "\nDumps the mempool to disk. It will fail until the previous dump is fully loaded.\n",
#     641                 :       1596 :         {},
#     642                 :       1596 :         RPCResult{
#     643                 :       1596 :             RPCResult::Type::OBJ, "", "",
#     644                 :       1596 :             {
#     645                 :       1596 :                 {RPCResult::Type::STR, "filename", "the directory and file where the mempool was saved"},
#     646                 :       1596 :             }},
#     647                 :       1596 :         RPCExamples{
#     648                 :       1596 :             HelpExampleCli("savemempool", "")
#     649                 :       1596 :             + HelpExampleRpc("savemempool", "")
#     650                 :       1596 :         },
#     651                 :       1596 :         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
#     652                 :       1596 : {
#     653                 :          2 :     const ArgsManager& args{EnsureAnyArgsman(request.context)};
#     654                 :          2 :     const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
#     655                 :            : 
#     656         [ -  + ]:          2 :     if (!mempool.IsLoaded()) {
#     657                 :          0 :         throw JSONRPCError(RPC_MISC_ERROR, "The mempool was not loaded yet");
#     658                 :          0 :     }
#     659                 :            : 
#     660         [ +  + ]:          2 :     if (!DumpMempool(mempool)) {
#     661                 :          1 :         throw JSONRPCError(RPC_MISC_ERROR, "Unable to dump mempool to disk");
#     662                 :          1 :     }
#     663                 :            : 
#     664                 :          1 :     UniValue ret(UniValue::VOBJ);
#     665                 :          1 :     ret.pushKV("filename", fs::path((args.GetDataDirNet() / "mempool.dat")).u8string());
#     666                 :            : 
#     667                 :          1 :     return ret;
#     668                 :          2 : },
#     669                 :       1596 :     };
#     670                 :       1596 : }
#     671                 :            : 
#     672                 :            : void RegisterMempoolRPCCommands(CRPCTable& t)
#     673                 :        993 : {
#     674                 :        993 :     static const CRPCCommand commands[]{
#     675                 :            :         // category     actor (function)
#     676                 :            :         // --------     ----------------
#     677                 :        993 :         {"rawtransactions", &sendrawtransaction},
#     678                 :        993 :         {"rawtransactions", &testmempoolaccept},
#     679                 :        993 :         {"blockchain", &getmempoolancestors},
#     680                 :        993 :         {"blockchain", &getmempooldescendants},
#     681                 :        993 :         {"blockchain", &getmempoolentry},
#     682                 :        993 :         {"blockchain", &getmempoolinfo},
#     683                 :        993 :         {"blockchain", &getrawmempool},
#     684                 :        993 :         {"blockchain", &savemempool},
#     685                 :        993 :     };
#     686         [ +  + ]:       7944 :     for (const auto& c : commands) {
#     687                 :       7944 :         t.appendCommand(c.name, &c);
#     688                 :       7944 :     }
#     689                 :        993 : }

Generated by: LCOV version 0-eol-96201-ge66f56f4af6a