LCOV - code coverage report
Current view: top level - src/rpc - mempool.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 270 682 39.6 %
Date: 2023-09-26 12:08:55 Functions: 17 33 51.5 %

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

Generated by: LCOV version 1.14