LCOV - code coverage report
Current view: top level - src/rpc - mempool.cpp (source / functions) Coverage Total Hit
Test: fuzz_coverage.info Lines: 68.6 % 1030 707
Test Date: 2026-02-22 04:23:07 Functions: 90.7 % 43 39
Branches: 38.9 % 3544 1377

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

Generated by: LCOV version 2.0-1