LCOV - code coverage report
Current view: top level - src/rpc - mempool.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 603 634 95.1 %
Date: 2026-06-25 07:23:43 Functions: 28 28 100.0 %

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

Generated by: LCOV version 1.16