LCOV - code coverage report
Current view: top level - src/rpc - mempool.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 1 681 0.1 %
Date: 2024-01-03 14:57:27 Functions: 0 30 0.0 %
Branches: 0 2474 0.0 %

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

Generated by: LCOV version 1.14