/ 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              struct Entry {
 954                  const COutPoint prevout;
 955                  const UniValue& input;
 956                  UniValue output;
 957              };
 958              std::vector<Entry> prevouts;
 959              prevouts.reserve(output_params.size());
 960  
 961              for (unsigned int idx = 0; idx < output_params.size(); idx++) {
 962                  const UniValue& o = output_params[idx].get_obj();
 963  
 964                  RPCTypeCheckObj(o,
 965                                  {
 966                                      {"txid", UniValueType(UniValue::VSTR)},
 967                                      {"vout", UniValueType(UniValue::VNUM)},
 968                                  }, /*fAllowNull=*/false, /*fStrict=*/true);
 969  
 970                  const Txid txid = Txid::FromUint256(ParseHashO(o, "txid"));
 971                  const int nOutput{o.find_value("vout").getInt<int>()};
 972                  if (nOutput < 0) {
 973                      throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative");
 974                  }
 975                  prevouts.emplace_back(COutPoint{txid, uint32_t(nOutput)}, o, UniValue{});
 976              }
 977  
 978              // search the mempool first
 979              bool missing_from_mempool{false};
 980              {
 981                  const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
 982                  LOCK(mempool.cs);
 983                  for (auto& entry : prevouts) {
 984                      const CTransaction* spendingTx = mempool.GetConflictTx(entry.prevout);
 985                      if (spendingTx != nullptr) {
 986                          UniValue o{entry.input};
 987                          o.pushKV("spendingtxid", spendingTx->GetHash().ToString());
 988                          if (return_spending_tx) {
 989                              o.pushKV("spendingtx", EncodeHexTx(*spendingTx));
 990                          }
 991                          entry.output = std::move(o);
 992                      } else {
 993                          missing_from_mempool = true;
 994                      }
 995                  }
 996              }
 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              UniValue result{UniValue::VARR};
1000              bool txospenderindex_ready{mempool_only || !missing_from_mempool || (g_txospenderindex && g_txospenderindex->BlockUntilSyncedToCurrentChain())};
1001              for (auto& entry : prevouts) {
1002                  if (!entry.output.isNull()) {
1003                      result.push_back(std::move(entry.output));
1004                      continue;
1005                  }
1006                  UniValue o{entry.input};
1007                  if (mempool_only) {
1008                      // do nothing, caller has selected to only query the mempool
1009                  } else if (!txospenderindex_ready) {
1010                      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                      const auto spender{g_txospenderindex->FindSpender(entry.prevout)};
1014                      if (!spender) {
1015                          throw JSONRPCError(RPC_MISC_ERROR, spender.error());
1016                      }
1017                      if (spender.value()) {
1018                          o.pushKV("spendingtxid", spender.value()->tx->GetHash().GetHex());
1019                          o.pushKV("blockhash", spender.value()->block_hash.GetHex());
1020                          if (return_spending_tx) {
1021                              o.pushKV("spendingtx", EncodeHexTx(*spender.value()->tx));
1022                          }
1023                      }
1024                  }
1025                  result.push_back(std::move(o));
1026              }
1027  
1028              return result;
1029          },
1030      };
1031  }
1032  
1033  UniValue MempoolInfoToJSON(const CTxMemPool& pool)
1034  {
1035      // Make sure this call is atomic in the pool.
1036      LOCK(pool.cs);
1037      UniValue ret(UniValue::VOBJ);
1038      ret.pushKV("loaded", pool.GetLoadTried());
1039      ret.pushKV("size", pool.size());
1040      ret.pushKV("bytes", pool.GetTotalTxSize());
1041      ret.pushKV("usage", pool.DynamicMemoryUsage());
1042      ret.pushKV("total_fee", ValueFromAmount(pool.GetTotalFee()));
1043      ret.pushKV("maxmempool", pool.m_opts.max_size_bytes);
1044      ret.pushKV("mempoolminfee", ValueFromAmount(std::max(pool.GetMinFee(), pool.m_opts.min_relay_feerate).GetFeePerK()));
1045      ret.pushKV("minrelaytxfee", ValueFromAmount(pool.m_opts.min_relay_feerate.GetFeePerK()));
1046      ret.pushKV("incrementalrelayfee", ValueFromAmount(pool.m_opts.incremental_relay_feerate.GetFeePerK()));
1047      ret.pushKV("unbroadcastcount", pool.GetUnbroadcastTxs().size());
1048      ret.pushKV("fullrbf", true);
1049      ret.pushKV("permitbaremultisig", pool.m_opts.permit_bare_multisig);
1050      ret.pushKV("maxdatacarriersize", pool.m_opts.max_datacarrier_bytes.value_or(0));
1051      ret.pushKV("limitclustercount", pool.m_opts.limits.cluster_count);
1052      ret.pushKV("limitclustersize", pool.m_opts.limits.cluster_size_vbytes);
1053      ret.pushKV("optimal", pool.m_txgraph->DoWork(0)); // 0 work is a quick check for known optimality
1054      return ret;
1055  }
1056  
1057  static RPCHelpMan getmempoolinfo()
1058  {
1059      return RPCHelpMan{"getmempoolinfo",
1060          "Returns details on the active state of the TX memory pool.",
1061          {},
1062          RPCResult{
1063              RPCResult::Type::OBJ, "", "",
1064              {
1065                  {RPCResult::Type::BOOL, "loaded", "True if the initial load attempt of the persisted mempool finished"},
1066                  {RPCResult::Type::NUM, "size", "Current tx count"},
1067                  {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"},
1068                  {RPCResult::Type::NUM, "usage", "Total memory usage for the mempool"},
1069                  {RPCResult::Type::STR_AMOUNT, "total_fee", "Total fees for the mempool in " + CURRENCY_UNIT + ", ignoring modified fees through prioritisetransaction"},
1070                  {RPCResult::Type::NUM, "maxmempool", "Maximum memory usage for the mempool"},
1071                  {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"},
1072                  {RPCResult::Type::STR_AMOUNT, "minrelaytxfee", "Current minimum relay fee for transactions"},
1073                  {RPCResult::Type::NUM, "incrementalrelayfee", "minimum fee rate increment for mempool limiting or replacement in " + CURRENCY_UNIT + "/kvB"},
1074                  {RPCResult::Type::NUM, "unbroadcastcount", "Current number of transactions that haven't passed initial broadcast yet"},
1075                  {RPCResult::Type::BOOL, "fullrbf", "True if the mempool accepts RBF without replaceability signaling inspection (DEPRECATED)"},
1076                  {RPCResult::Type::BOOL, "permitbaremultisig", "True if the mempool accepts transactions with bare multisig outputs"},
1077                  {RPCResult::Type::NUM, "maxdatacarriersize", "Maximum number of bytes that can be used by OP_RETURN outputs in the mempool"},
1078                  {RPCResult::Type::NUM, "limitclustercount", "Maximum number of transactions that can be in a cluster (configured by -limitclustercount)"},
1079                  {RPCResult::Type::NUM, "limitclustersize", "Maximum size of a cluster in virtual bytes (configured by -limitclustersize)"},
1080                  {RPCResult::Type::BOOL, "optimal", "If the mempool is in a known-optimal transaction ordering"},
1081              }},
1082          RPCExamples{
1083              HelpExampleCli("getmempoolinfo", "")
1084              + HelpExampleRpc("getmempoolinfo", "")
1085          },
1086          [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1087  {
1088      return MempoolInfoToJSON(EnsureAnyMemPool(request.context));
1089  },
1090      };
1091  }
1092  
1093  static RPCHelpMan importmempool()
1094  {
1095      return RPCHelpMan{
1096          "importmempool",
1097          "Import a mempool.dat file and attempt to add its contents to the mempool.\n"
1098          "Warning: Importing untrusted files is dangerous, especially if metadata from the file is taken over.",
1099          {
1100              {"filepath", RPCArg::Type::STR, RPCArg::Optional::NO, "The mempool file"},
1101              {"options",
1102               RPCArg::Type::OBJ_NAMED_PARAMS,
1103               RPCArg::Optional::OMITTED,
1104               "",
1105               {
1106                   {"use_current_time", RPCArg::Type::BOOL, RPCArg::Default{true},
1107                    "Whether to use the current system time or use the entry time metadata from the mempool file.\n"
1108                    "Warning: Importing untrusted metadata may lead to unexpected issues and undesirable behavior."},
1109                   {"apply_fee_delta_priority", RPCArg::Type::BOOL, RPCArg::Default{false},
1110                    "Whether to apply the fee delta metadata from the mempool file.\n"
1111                    "It will be added to any existing fee deltas.\n"
1112                    "The fee delta can be set by the prioritisetransaction RPC.\n"
1113                    "Warning: Importing untrusted metadata may lead to unexpected issues and undesirable behavior.\n"
1114                    "Only set this bool if you understand what it does."},
1115                   {"apply_unbroadcast_set", RPCArg::Type::BOOL, RPCArg::Default{false},
1116                    "Whether to apply the unbroadcast set metadata from the mempool file.\n"
1117                    "Warning: Importing untrusted metadata may lead to unexpected issues and undesirable behavior."},
1118               },
1119               RPCArgOptions{.oneline_description = "options"}},
1120          },
1121          RPCResult{RPCResult::Type::OBJ, "", "", std::vector<RPCResult>{}},
1122          RPCExamples{HelpExampleCli("importmempool", "/path/to/mempool.dat") + HelpExampleRpc("importmempool", "/path/to/mempool.dat")},
1123          [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue {
1124              const NodeContext& node{EnsureAnyNodeContext(request.context)};
1125  
1126              CTxMemPool& mempool{EnsureMemPool(node)};
1127              ChainstateManager& chainman = EnsureChainman(node);
1128              Chainstate& chainstate = chainman.ActiveChainstate();
1129  
1130              if (chainman.IsInitialBlockDownload()) {
1131                  throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Can only import the mempool after the block download and sync is done.");
1132              }
1133  
1134              const fs::path load_path{fs::u8path(self.Arg<std::string_view>("filepath"))};
1135              const UniValue& use_current_time{request.params[1]["use_current_time"]};
1136              const UniValue& apply_fee_delta{request.params[1]["apply_fee_delta_priority"]};
1137              const UniValue& apply_unbroadcast{request.params[1]["apply_unbroadcast_set"]};
1138              node::ImportMempoolOptions opts{
1139                  .use_current_time = use_current_time.isNull() ? true : use_current_time.get_bool(),
1140                  .apply_fee_delta_priority = apply_fee_delta.isNull() ? false : apply_fee_delta.get_bool(),
1141                  .apply_unbroadcast_set = apply_unbroadcast.isNull() ? false : apply_unbroadcast.get_bool(),
1142              };
1143  
1144              if (!node::LoadMempool(mempool, load_path, chainstate, std::move(opts))) {
1145                  throw JSONRPCError(RPC_MISC_ERROR, "Unable to import mempool file, see debug.log for details.");
1146              }
1147  
1148              UniValue ret{UniValue::VOBJ};
1149              return ret;
1150          },
1151      };
1152  }
1153  
1154  static RPCHelpMan savemempool()
1155  {
1156      return RPCHelpMan{
1157          "savemempool",
1158          "Dumps the mempool to disk. It will fail until the previous dump is fully loaded.\n",
1159          {},
1160          RPCResult{
1161              RPCResult::Type::OBJ, "", "",
1162              {
1163                  {RPCResult::Type::STR, "filename", "the directory and file where the mempool was saved"},
1164              }},
1165          RPCExamples{
1166              HelpExampleCli("savemempool", "")
1167              + HelpExampleRpc("savemempool", "")
1168          },
1169          [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1170  {
1171      const ArgsManager& args{EnsureAnyArgsman(request.context)};
1172      const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
1173  
1174      if (!mempool.GetLoadTried()) {
1175          throw JSONRPCError(RPC_MISC_ERROR, "The mempool was not loaded yet");
1176      }
1177  
1178      const fs::path& dump_path = MempoolPath(args);
1179  
1180      if (!DumpMempool(mempool, dump_path)) {
1181          throw JSONRPCError(RPC_MISC_ERROR, "Unable to dump mempool to disk");
1182      }
1183  
1184      UniValue ret(UniValue::VOBJ);
1185      ret.pushKV("filename", dump_path.utf8string());
1186  
1187      return ret;
1188  },
1189      };
1190  }
1191  
1192  static std::vector<RPCResult> OrphanDescription()
1193  {
1194      return {
1195          RPCResult{RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
1196          RPCResult{RPCResult::Type::STR_HEX, "wtxid", "The transaction witness hash in hex"},
1197          RPCResult{RPCResult::Type::NUM, "bytes", "The serialized transaction size in bytes"},
1198          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."},
1199          RPCResult{RPCResult::Type::NUM, "weight", "The transaction weight as defined in BIP 141."},
1200          RPCResult{RPCResult::Type::ARR, "from", "",
1201          {
1202              RPCResult{RPCResult::Type::NUM, "peer_id", "Peer ID"},
1203          }},
1204      };
1205  }
1206  
1207  static UniValue OrphanToJSON(const node::TxOrphanage::OrphanInfo& orphan)
1208  {
1209      UniValue o(UniValue::VOBJ);
1210      o.pushKV("txid", orphan.tx->GetHash().ToString());
1211      o.pushKV("wtxid", orphan.tx->GetWitnessHash().ToString());
1212      o.pushKV("bytes", orphan.tx->ComputeTotalSize());
1213      o.pushKV("vsize", GetVirtualTransactionSize(*orphan.tx));
1214      o.pushKV("weight", GetTransactionWeight(*orphan.tx));
1215      UniValue from(UniValue::VARR);
1216      for (const auto fromPeer: orphan.announcers) {
1217          from.push_back(fromPeer);
1218      }
1219      o.pushKV("from", from);
1220      return o;
1221  }
1222  
1223  static RPCHelpMan getorphantxs()
1224  {
1225      return RPCHelpMan{
1226          "getorphantxs",
1227          "Shows transactions in the tx orphanage.\n"
1228          "\nEXPERIMENTAL warning: this call may be changed in future releases.\n",
1229          {
1230              {"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",
1231               RPCArgOptions{.skip_type_check = true}},
1232          },
1233          {
1234              RPCResult{"for verbose = 0",
1235                  RPCResult::Type::ARR, "", "",
1236                  {
1237                      {RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
1238                  }},
1239              RPCResult{"for verbose = 1",
1240                  RPCResult::Type::ARR, "", "",
1241                  {
1242                      {RPCResult::Type::OBJ, "", "", OrphanDescription()},
1243                  }},
1244              RPCResult{"for verbose = 2",
1245                  RPCResult::Type::ARR, "", "",
1246                  {
1247                      {RPCResult::Type::OBJ, "", "",
1248                          Cat<std::vector<RPCResult>>(
1249                              OrphanDescription(),
1250                              {{RPCResult::Type::STR_HEX, "hex", "The serialized, hex-encoded transaction data"}}
1251                          )
1252                      },
1253                  }},
1254          },
1255          RPCExamples{
1256              HelpExampleCli("getorphantxs", "2")
1257              + HelpExampleRpc("getorphantxs", "2")
1258          },
1259          [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1260          {
1261              const NodeContext& node = EnsureAnyNodeContext(request.context);
1262              PeerManager& peerman = EnsurePeerman(node);
1263              std::vector<node::TxOrphanage::OrphanInfo> orphanage = peerman.GetOrphanTransactions();
1264  
1265              int verbosity{ParseVerbosity(request.params[0], /*default_verbosity=*/0, /*allow_bool=*/false)};
1266  
1267              UniValue ret(UniValue::VARR);
1268  
1269              if (verbosity == 0) {
1270                  for (auto const& orphan : orphanage) {
1271                      ret.push_back(orphan.tx->GetHash().ToString());
1272                  }
1273              } else if (verbosity == 1) {
1274                  for (auto const& orphan : orphanage) {
1275                      ret.push_back(OrphanToJSON(orphan));
1276                  }
1277              } else if (verbosity == 2) {
1278                  for (auto const& orphan : orphanage) {
1279                      UniValue o{OrphanToJSON(orphan)};
1280                      o.pushKV("hex", EncodeHexTx(*orphan.tx));
1281                      ret.push_back(o);
1282                  }
1283              } else {
1284                  throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid verbosity value " + ToString(verbosity));
1285              }
1286  
1287              return ret;
1288          },
1289      };
1290  }
1291  
1292  static RPCHelpMan submitpackage()
1293  {
1294      return RPCHelpMan{"submitpackage",
1295          "Submit a package of raw transactions (serialized, hex-encoded) to local node.\n"
1296          "The package will be validated according to consensus and mempool policy rules. If any transaction passes, it will be accepted to mempool.\n"
1297          "This RPC is experimental and the interface may be unstable. Refer to doc/policy/packages.md for documentation on package policies.\n"
1298          "Warning: successful submission does not mean the transactions will propagate throughout the network.\n"
1299          ,
1300          {
1301              {"package", RPCArg::Type::ARR, RPCArg::Optional::NO, "An array of raw transactions.\n"
1302                  "The package must consist of a transaction with (some, all, or none of) its unconfirmed parents. A single transaction is permitted.\n"
1303                  "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"
1304                  "The package must be topologically sorted, with the child being the last element in the array if there are multiple elements.",
1305                  {
1306                      {"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
1307                  },
1308              },
1309              {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())},
1310               "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT +
1311                   "/kvB.\nFee rates larger than 1BTC/kvB are rejected.\nSet to 0 to accept any fee rate."},
1312              {"maxburnamount", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_BURN_AMOUNT)},
1313               "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"
1314               "If burning funds through unspendable outputs is desired, increase this value.\n"
1315               "This check is based on heuristics and does not guarantee spendability of outputs.\n"
1316              },
1317          },
1318          RPCResult{
1319              RPCResult::Type::OBJ, "", "",
1320              {
1321                  {RPCResult::Type::STR, "package_msg", "The transaction package result message. \"success\" indicates all transactions were accepted into or are already in the mempool."},
1322                  {RPCResult::Type::OBJ_DYN, "tx-results", "The transaction results keyed by wtxid. An entry is returned for every submitted wtxid.",
1323                  {
1324                      {RPCResult::Type::OBJ, "wtxid", "transaction wtxid", {
1325                          {RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
1326                          {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."},
1327                          {RPCResult::Type::NUM, "vsize", /*optional=*/true, "Sigops-adjusted virtual transaction size."},
1328                          {RPCResult::Type::OBJ, "fees", /*optional=*/true, "Transaction fees", {
1329                              {RPCResult::Type::STR_AMOUNT, "base", "transaction fee in " + CURRENCY_UNIT},
1330                              {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."},
1331                              {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.",
1332                                  {{RPCResult::Type::STR_HEX, "", "transaction wtxid in hex"},
1333                              }},
1334                          }},
1335                          {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."},
1336                      }}
1337                  }},
1338                  {RPCResult::Type::ARR, "replaced-transactions", /*optional=*/true, "List of txids of replaced transactions",
1339                  {
1340                      {RPCResult::Type::STR_HEX, "", "The transaction id"},
1341                  }},
1342              },
1343          },
1344          RPCExamples{
1345              HelpExampleRpc("submitpackage", R"(["raw-parent-tx-1", "raw-parent-tx-2", "raw-child-tx"])") +
1346              HelpExampleCli("submitpackage", R"('["raw-tx-without-unconfirmed-parents"]')")
1347          },
1348          [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1349          {
1350              const UniValue raw_transactions = request.params[0].get_array();
1351              if (raw_transactions.empty() || raw_transactions.size() > MAX_PACKAGE_COUNT) {
1352                  throw JSONRPCError(RPC_INVALID_PARAMETER,
1353                                     "Array must contain between 1 and " + ToString(MAX_PACKAGE_COUNT) + " transactions.");
1354              }
1355  
1356              // Fee check needs to be run with chainstate and package context
1357              const CFeeRate max_raw_tx_fee_rate{ParseFeeRate(self.Arg<UniValue>("maxfeerate"))};
1358              std::optional<CFeeRate> client_maxfeerate{max_raw_tx_fee_rate};
1359              // 0-value is special; it's mapped to no sanity check
1360              if (max_raw_tx_fee_rate == CFeeRate(0)) {
1361                  client_maxfeerate = std::nullopt;
1362              }
1363  
1364              // Burn sanity check is run with no context
1365              const CAmount max_burn_amount = request.params[2].isNull() ? 0 : AmountFromValue(request.params[2]);
1366  
1367              std::vector<CTransactionRef> txns;
1368              txns.reserve(raw_transactions.size());
1369              for (const auto& rawtx : raw_transactions.getValues()) {
1370                  CMutableTransaction mtx;
1371                  if (!DecodeHexTx(mtx, rawtx.get_str())) {
1372                      throw JSONRPCError(RPC_DESERIALIZATION_ERROR,
1373                                         "TX decode failed: " + rawtx.get_str() + " Make sure the tx has at least one input.");
1374                  }
1375  
1376                  for (const auto& out : mtx.vout) {
1377                      if((out.scriptPubKey.IsUnspendable() || !out.scriptPubKey.HasValidOps()) && out.nValue > max_burn_amount) {
1378                          throw JSONRPCTransactionError(TransactionError::MAX_BURN_EXCEEDED);
1379                      }
1380                  }
1381  
1382                  txns.emplace_back(MakeTransactionRef(std::move(mtx)));
1383              }
1384              CHECK_NONFATAL(!txns.empty());
1385              if (txns.size() > 1 && !IsChildWithParentsTree(txns)) {
1386                  throw JSONRPCTransactionError(TransactionError::INVALID_PACKAGE, "package topology disallowed. not child-with-parents or parents depend on each other.");
1387              }
1388  
1389              NodeContext& node = EnsureAnyNodeContext(request.context);
1390              CTxMemPool& mempool = EnsureMemPool(node);
1391              Chainstate& chainstate = EnsureChainman(node).ActiveChainstate();
1392              const auto package_result = WITH_LOCK(::cs_main, return ProcessNewPackage(chainstate, mempool, txns, /*test_accept=*/ false, client_maxfeerate));
1393  
1394              std::string package_msg = "success";
1395  
1396              // First catch package-wide errors, continue if we can
1397              switch(package_result.m_state.GetResult()) {
1398                  case PackageValidationResult::PCKG_RESULT_UNSET:
1399                  {
1400                      // Belt-and-suspenders check; everything should be successful here
1401                      CHECK_NONFATAL(package_result.m_tx_results.size() == txns.size());
1402                      for (const auto& tx : txns) {
1403                          CHECK_NONFATAL(mempool.exists(tx->GetHash()));
1404                      }
1405                      break;
1406                  }
1407                  case PackageValidationResult::PCKG_MEMPOOL_ERROR:
1408                  {
1409                      // This only happens with internal bug; user should stop and report
1410                      throw JSONRPCTransactionError(TransactionError::MEMPOOL_ERROR,
1411                          package_result.m_state.GetRejectReason());
1412                  }
1413                  case PackageValidationResult::PCKG_POLICY:
1414                  case PackageValidationResult::PCKG_TX:
1415                  {
1416                      // Package-wide error we want to return, but we also want to return individual responses
1417                      package_msg = package_result.m_state.ToString();
1418                      CHECK_NONFATAL(package_result.m_tx_results.size() == txns.size() ||
1419                              package_result.m_tx_results.empty());
1420                      break;
1421                  }
1422              }
1423  
1424              size_t num_broadcast{0};
1425              for (const auto& tx : txns) {
1426                  // We don't want to re-submit the txn for validation in BroadcastTransaction
1427                  if (!mempool.exists(tx->GetHash())) {
1428                      continue;
1429                  }
1430  
1431                  // We do not expect an error here; we are only broadcasting things already/still in mempool
1432                  std::string err_string;
1433                  const auto err = BroadcastTransaction(node,
1434                                                        tx,
1435                                                        err_string,
1436                                                        /*max_tx_fee=*/0,
1437                                                        node::TxBroadcast::MEMPOOL_AND_BROADCAST_TO_ALL,
1438                                                        /*wait_callback=*/true);
1439                  if (err != TransactionError::OK) {
1440                      throw JSONRPCTransactionError(err,
1441                          strprintf("transaction broadcast failed: %s (%d transactions were broadcast successfully)",
1442                              err_string, num_broadcast));
1443                  }
1444                  num_broadcast++;
1445              }
1446  
1447              UniValue rpc_result{UniValue::VOBJ};
1448              rpc_result.pushKV("package_msg", package_msg);
1449              UniValue tx_result_map{UniValue::VOBJ};
1450              std::set<Txid> replaced_txids;
1451              for (const auto& tx : txns) {
1452                  UniValue result_inner{UniValue::VOBJ};
1453                  result_inner.pushKV("txid", tx->GetHash().GetHex());
1454                  const auto wtxid_hex = tx->GetWitnessHash().GetHex();
1455                  auto it = package_result.m_tx_results.find(tx->GetWitnessHash());
1456                  if (it == package_result.m_tx_results.end()) {
1457                      // No per-tx result for this wtxid
1458                      // Current invariant: per-tx results are all-or-none (every member or empty on package abort).
1459                      // If any exist yet this one is missing, it's an unexpected partial map.
1460                      CHECK_NONFATAL(package_result.m_tx_results.empty());
1461                      result_inner.pushKV("error", "package-not-validated");
1462                      tx_result_map.pushKV(wtxid_hex, std::move(result_inner));
1463                      continue;
1464                  }
1465                  const auto& tx_result = it->second;
1466                  switch(it->second.m_result_type) {
1467                  case MempoolAcceptResult::ResultType::DIFFERENT_WITNESS:
1468                      result_inner.pushKV("other-wtxid", it->second.m_other_wtxid.value().GetHex());
1469                      break;
1470                  case MempoolAcceptResult::ResultType::INVALID:
1471                      result_inner.pushKV("error", it->second.m_state.ToString());
1472                      break;
1473                  case MempoolAcceptResult::ResultType::VALID:
1474                  case MempoolAcceptResult::ResultType::MEMPOOL_ENTRY:
1475                      result_inner.pushKV("vsize", it->second.m_vsize.value());
1476                      UniValue fees(UniValue::VOBJ);
1477                      fees.pushKV("base", ValueFromAmount(it->second.m_base_fees.value()));
1478                      if (tx_result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
1479                          // Effective feerate is not provided for MEMPOOL_ENTRY transactions even
1480                          // though modified fees is known, because it is unknown whether package
1481                          // feerate was used when it was originally submitted.
1482                          fees.pushKV("effective-feerate", ValueFromAmount(tx_result.m_effective_feerate.value().GetFeePerK()));
1483                          UniValue effective_includes_res(UniValue::VARR);
1484                          for (const auto& wtxid : tx_result.m_wtxids_fee_calculations.value()) {
1485                              effective_includes_res.push_back(wtxid.ToString());
1486                          }
1487                          fees.pushKV("effective-includes", std::move(effective_includes_res));
1488                      }
1489                      result_inner.pushKV("fees", std::move(fees));
1490                      for (const auto& ptx : it->second.m_replaced_transactions) {
1491                          replaced_txids.insert(ptx->GetHash());
1492                      }
1493                      break;
1494                  }
1495                  tx_result_map.pushKV(wtxid_hex, std::move(result_inner));
1496              }
1497              rpc_result.pushKV("tx-results", std::move(tx_result_map));
1498              UniValue replaced_list(UniValue::VARR);
1499              for (const auto& txid : replaced_txids) replaced_list.push_back(txid.ToString());
1500              rpc_result.pushKV("replaced-transactions", std::move(replaced_list));
1501              return rpc_result;
1502          },
1503      };
1504  }
1505  
1506  void RegisterMempoolRPCCommands(CRPCTable& t)
1507  {
1508      static const CRPCCommand commands[]{
1509          {"rawtransactions", &sendrawtransaction},
1510          {"rawtransactions", &getprivatebroadcastinfo},
1511          {"rawtransactions", &abortprivatebroadcast},
1512          {"rawtransactions", &testmempoolaccept},
1513          {"blockchain", &getmempoolancestors},
1514          {"blockchain", &getmempooldescendants},
1515          {"blockchain", &getmempoolentry},
1516          {"blockchain", &getmempoolcluster},
1517          {"blockchain", &gettxspendingprevout},
1518          {"blockchain", &getmempoolinfo},
1519          {"hidden", &getmempoolfeeratediagram},
1520          {"blockchain", &getrawmempool},
1521          {"blockchain", &importmempool},
1522          {"blockchain", &savemempool},
1523          {"hidden", &getorphantxs},
1524          {"rawtransactions", &submitpackage},
1525      };
1526      for (const auto& c : commands) {
1527          t.appendCommand(c.name, &c);
1528      }
1529  }