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