mempool.cpp raw

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