/ src / rpc / mempool.cpp
mempool.cpp
   1  // Copyright (c) 2010 Satoshi Nakamoto
   2  // Copyright (c) 2009-2022 The Bitcoin Core developers
   3  // Distributed under the MIT software license, see the accompanying
   4  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
   5  
   6  #include <rpc/blockchain.h>
   7  
   8  #include <kernel/mempool_persist.h>
   9  
  10  #include <chainparams.h>
  11  #include <core_io.h>
  12  #include <kernel/mempool_entry.h>
  13  #include <node/mempool_persist_args.h>
  14  #include <policy/rbf.h>
  15  #include <policy/settings.h>
  16  #include <primitives/transaction.h>
  17  #include <rpc/server.h>
  18  #include <rpc/server_util.h>
  19  #include <rpc/util.h>
  20  #include <txmempool.h>
  21  #include <univalue.h>
  22  #include <util/fs.h>
  23  #include <util/moneystr.h>
  24  #include <util/strencodings.h>
  25  #include <util/time.h>
  26  
  27  #include <utility>
  28  
  29  using kernel::DumpMempool;
  30  
  31  using node::DEFAULT_MAX_BURN_AMOUNT;
  32  using node::DEFAULT_MAX_RAW_TX_FEE_RATE;
  33  using node::MempoolPath;
  34  using node::NodeContext;
  35  
  36  static RPCHelpMan sendrawtransaction()
  37  {
  38      return RPCHelpMan{"sendrawtransaction",
  39          "\nSubmit a raw transaction (serialized, hex-encoded) to local node and network.\n"
  40          "\nThe transaction will be sent unconditionally to all peers, so using sendrawtransaction\n"
  41          "for manual rebroadcast may degrade privacy by leaking the transaction's origin, as\n"
  42          "nodes will normally not rebroadcast non-wallet transactions already in their mempool.\n"
  43          "\nA specific exception, RPC_TRANSACTION_ALREADY_IN_CHAIN, may throw if the transaction cannot be added to the mempool.\n"
  44          "\nRelated RPCs: createrawtransaction, signrawtransactionwithkey\n",
  45          {
  46              {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"},
  47              {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())},
  48               "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT +
  49                   "/kvB.\nFee rates larger than 1BTC/kvB are rejected.\nSet to 0 to accept any fee rate."},
  50              {"maxburnamount", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_BURN_AMOUNT)},
  51               "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"
  52               "If burning funds through unspendable outputs is desired, increase this value.\n"
  53               "This check is based on heuristics and does not guarantee spendability of outputs.\n"},
  54          },
  55          RPCResult{
  56              RPCResult::Type::STR_HEX, "", "The transaction hash in hex"
  57          },
  58          RPCExamples{
  59              "\nCreate a transaction\n"
  60              + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") +
  61              "Sign the transaction, and get back the hex\n"
  62              + HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") +
  63              "\nSend the transaction (signed hex)\n"
  64              + HelpExampleCli("sendrawtransaction", "\"signedhex\"") +
  65              "\nAs a JSON-RPC call\n"
  66              + HelpExampleRpc("sendrawtransaction", "\"signedhex\"")
  67                  },
  68          [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
  69          {
  70              const CAmount max_burn_amount = request.params[2].isNull() ? 0 : AmountFromValue(request.params[2]);
  71  
  72              CMutableTransaction mtx;
  73              if (!DecodeHexTx(mtx, request.params[0].get_str())) {
  74                  throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input.");
  75              }
  76  
  77              for (const auto& out : mtx.vout) {
  78                  if((out.scriptPubKey.IsUnspendable() || !out.scriptPubKey.HasValidOps()) && out.nValue > max_burn_amount) {
  79                      throw JSONRPCTransactionError(TransactionError::MAX_BURN_EXCEEDED);
  80                  }
  81              }
  82  
  83              CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
  84  
  85              const CFeeRate max_raw_tx_fee_rate{ParseFeeRate(self.Arg<UniValue>(1))};
  86  
  87              int64_t virtual_size = GetVirtualTransactionSize(*tx);
  88              CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size);
  89  
  90              std::string err_string;
  91              AssertLockNotHeld(cs_main);
  92              NodeContext& node = EnsureAnyNodeContext(request.context);
  93              const TransactionError err = BroadcastTransaction(node, tx, err_string, max_raw_tx_fee, /*relay=*/true, /*wait_callback=*/true);
  94              if (TransactionError::OK != err) {
  95                  throw JSONRPCTransactionError(err, err_string);
  96              }
  97  
  98              return tx->GetHash().GetHex();
  99          },
 100      };
 101  }
 102  
 103  static RPCHelpMan testmempoolaccept()
 104  {
 105      return RPCHelpMan{"testmempoolaccept",
 106          "\nReturns result of mempool acceptance tests indicating if raw transaction(s) (serialized, hex-encoded) would be accepted by mempool.\n"
 107          "\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"
 108          "\nIf one transaction fails, other transactions may not be fully validated (the 'allowed' key will be blank).\n"
 109          "\nThe maximum number of transactions allowed is " + ToString(MAX_PACKAGE_COUNT) + ".\n"
 110          "\nThis checks if transactions violate the consensus or policy rules.\n"
 111          "\nSee sendrawtransaction call.\n",
 112          {
 113              {"rawtxs", RPCArg::Type::ARR, RPCArg::Optional::NO, "An array of hex strings of raw transactions.",
 114                  {
 115                      {"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
 116                  },
 117              },
 118              {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())},
 119               "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT +
 120                   "/kvB.\nFee rates larger than 1BTC/kvB are rejected.\nSet to 0 to accept any fee rate."},
 121          },
 122          RPCResult{
 123              RPCResult::Type::ARR, "", "The result of the mempool acceptance test for each raw transaction in the input array.\n"
 124                                        "Returns results for each transaction in the same order they were passed in.\n"
 125                                        "Transactions that cannot be fully validated due to failures in other transactions will not contain an 'allowed' result.\n",
 126              {
 127                  {RPCResult::Type::OBJ, "", "",
 128                  {
 129                      {RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
 130                      {RPCResult::Type::STR_HEX, "wtxid", "The transaction witness hash in hex"},
 131                      {RPCResult::Type::STR, "package-error", /*optional=*/true, "Package validation error, if any (only possible if rawtxs had more than 1 transaction)."},
 132                      {RPCResult::Type::BOOL, "allowed", /*optional=*/true, "Whether this tx would be accepted to the mempool and pass client-specified maxfeerate. "
 133                                                         "If not present, the tx was not fully validated due to a failure in another tx in the list."},
 134                      {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)"},
 135                      {RPCResult::Type::OBJ, "fees", /*optional=*/true, "Transaction fees (only present if 'allowed' is true)",
 136                      {
 137                          {RPCResult::Type::STR_AMOUNT, "base", "transaction fee in " + CURRENCY_UNIT},
 138                          {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."},
 139                          {RPCResult::Type::ARR, "effective-includes", /*optional=*/false, "transactions whose fees and vsizes are included in effective-feerate.",
 140                              {RPCResult{RPCResult::Type::STR_HEX, "", "transaction wtxid in hex"},
 141                          }},
 142                      }},
 143                      {RPCResult::Type::STR, "reject-reason", /*optional=*/true, "Rejection string (only present when 'allowed' is false)"},
 144                  }},
 145              }
 146          },
 147          RPCExamples{
 148              "\nCreate a transaction\n"
 149              + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") +
 150              "Sign the transaction, and get back the hex\n"
 151              + HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") +
 152              "\nTest acceptance of the transaction (signed hex)\n"
 153              + HelpExampleCli("testmempoolaccept", R"('["signedhex"]')") +
 154              "\nAs a JSON-RPC call\n"
 155              + HelpExampleRpc("testmempoolaccept", "[\"signedhex\"]")
 156                  },
 157          [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
 158          {
 159              const UniValue raw_transactions = request.params[0].get_array();
 160              if (raw_transactions.size() < 1 || raw_transactions.size() > MAX_PACKAGE_COUNT) {
 161                  throw JSONRPCError(RPC_INVALID_PARAMETER,
 162                                     "Array must contain between 1 and " + ToString(MAX_PACKAGE_COUNT) + " transactions.");
 163              }
 164  
 165              const CFeeRate max_raw_tx_fee_rate{ParseFeeRate(self.Arg<UniValue>(1))};
 166  
 167              std::vector<CTransactionRef> txns;
 168              txns.reserve(raw_transactions.size());
 169              for (const auto& rawtx : raw_transactions.getValues()) {
 170                  CMutableTransaction mtx;
 171                  if (!DecodeHexTx(mtx, rawtx.get_str())) {
 172                      throw JSONRPCError(RPC_DESERIALIZATION_ERROR,
 173                                         "TX decode failed: " + rawtx.get_str() + " Make sure the tx has at least one input.");
 174                  }
 175                  txns.emplace_back(MakeTransactionRef(std::move(mtx)));
 176              }
 177  
 178              NodeContext& node = EnsureAnyNodeContext(request.context);
 179              CTxMemPool& mempool = EnsureMemPool(node);
 180              ChainstateManager& chainman = EnsureChainman(node);
 181              Chainstate& chainstate = chainman.ActiveChainstate();
 182              const PackageMempoolAcceptResult package_result = [&] {
 183                  LOCK(::cs_main);
 184                  if (txns.size() > 1) return ProcessNewPackage(chainstate, mempool, txns, /*test_accept=*/true, /*client_maxfeerate=*/{});
 185                  return PackageMempoolAcceptResult(txns[0]->GetWitnessHash(),
 186                                                    chainman.ProcessTransaction(txns[0], /*test_accept=*/true));
 187              }();
 188  
 189              UniValue rpc_result(UniValue::VARR);
 190              // We will check transaction fees while we iterate through txns in order. If any transaction fee
 191              // exceeds maxfeerate, we will leave the rest of the validation results blank, because it
 192              // doesn't make sense to return a validation result for a transaction if its ancestor(s) would
 193              // not be submitted.
 194              bool exit_early{false};
 195              for (const auto& tx : txns) {
 196                  UniValue result_inner(UniValue::VOBJ);
 197                  result_inner.pushKV("txid", tx->GetHash().GetHex());
 198                  result_inner.pushKV("wtxid", tx->GetWitnessHash().GetHex());
 199                  if (package_result.m_state.GetResult() == PackageValidationResult::PCKG_POLICY) {
 200                      result_inner.pushKV("package-error", package_result.m_state.ToString());
 201                  }
 202                  auto it = package_result.m_tx_results.find(tx->GetWitnessHash());
 203                  if (exit_early || it == package_result.m_tx_results.end()) {
 204                      // Validation unfinished. Just return the txid and wtxid.
 205                      rpc_result.push_back(result_inner);
 206                      continue;
 207                  }
 208                  const auto& tx_result = it->second;
 209                  // Package testmempoolaccept doesn't allow transactions to already be in the mempool.
 210                  CHECK_NONFATAL(tx_result.m_result_type != MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
 211                  if (tx_result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
 212                      const CAmount fee = tx_result.m_base_fees.value();
 213                      // Check that fee does not exceed maximum fee
 214                      const int64_t virtual_size = tx_result.m_vsize.value();
 215                      const CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size);
 216                      if (max_raw_tx_fee && fee > max_raw_tx_fee) {
 217                          result_inner.pushKV("allowed", false);
 218                          result_inner.pushKV("reject-reason", "max-fee-exceeded");
 219                          exit_early = true;
 220                      } else {
 221                          // Only return the fee and vsize if the transaction would pass ATMP.
 222                          // These can be used to calculate the feerate.
 223                          result_inner.pushKV("allowed", true);
 224                          result_inner.pushKV("vsize", virtual_size);
 225                          UniValue fees(UniValue::VOBJ);
 226                          fees.pushKV("base", ValueFromAmount(fee));
 227                          fees.pushKV("effective-feerate", ValueFromAmount(tx_result.m_effective_feerate.value().GetFeePerK()));
 228                          UniValue effective_includes_res(UniValue::VARR);
 229                          for (const auto& wtxid : tx_result.m_wtxids_fee_calculations.value()) {
 230                              effective_includes_res.push_back(wtxid.ToString());
 231                          }
 232                          fees.pushKV("effective-includes", effective_includes_res);
 233                          result_inner.pushKV("fees", fees);
 234                      }
 235                  } else {
 236                      result_inner.pushKV("allowed", false);
 237                      const TxValidationState state = tx_result.m_state;
 238                      if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
 239                          result_inner.pushKV("reject-reason", "missing-inputs");
 240                      } else {
 241                          result_inner.pushKV("reject-reason", state.GetRejectReason());
 242                      }
 243                  }
 244                  rpc_result.push_back(result_inner);
 245              }
 246              return rpc_result;
 247          },
 248      };
 249  }
 250  
 251  static std::vector<RPCResult> MempoolEntryDescription()
 252  {
 253      return {
 254          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."},
 255          RPCResult{RPCResult::Type::NUM, "weight", "transaction weight as defined in BIP 141."},
 256          RPCResult{RPCResult::Type::NUM_TIME, "time", "local time transaction entered pool in seconds since 1 Jan 1970 GMT"},
 257          RPCResult{RPCResult::Type::NUM, "height", "block height when transaction entered pool"},
 258          RPCResult{RPCResult::Type::NUM, "descendantcount", "number of in-mempool descendant transactions (including this one)"},
 259          RPCResult{RPCResult::Type::NUM, "descendantsize", "virtual transaction size of in-mempool descendants (including this one)"},
 260          RPCResult{RPCResult::Type::NUM, "ancestorcount", "number of in-mempool ancestor transactions (including this one)"},
 261          RPCResult{RPCResult::Type::NUM, "ancestorsize", "virtual transaction size of in-mempool ancestors (including this one)"},
 262          RPCResult{RPCResult::Type::STR_HEX, "wtxid", "hash of serialized transaction, including witness data"},
 263          RPCResult{RPCResult::Type::OBJ, "fees", "",
 264              {
 265                  RPCResult{RPCResult::Type::STR_AMOUNT, "base", "transaction fee, denominated in " + CURRENCY_UNIT},
 266                  RPCResult{RPCResult::Type::STR_AMOUNT, "modified", "transaction fee with fee deltas used for mining priority, denominated in " + CURRENCY_UNIT},
 267                  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},
 268                  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},
 269              }},
 270          RPCResult{RPCResult::Type::ARR, "depends", "unconfirmed transactions used as inputs for this transaction",
 271              {RPCResult{RPCResult::Type::STR_HEX, "transactionid", "parent transaction id"}}},
 272          RPCResult{RPCResult::Type::ARR, "spentby", "unconfirmed transactions spending outputs from this transaction",
 273              {RPCResult{RPCResult::Type::STR_HEX, "transactionid", "child transaction id"}}},
 274          RPCResult{RPCResult::Type::BOOL, "bip125-replaceable", "Whether this transaction signals BIP125 replaceability or has an unconfirmed ancestor signaling BIP125 replaceability.\n"},
 275          RPCResult{RPCResult::Type::BOOL, "unbroadcast", "Whether this transaction is currently unbroadcast (initial broadcast not yet acknowledged by any peers)"},
 276      };
 277  }
 278  
 279  static void entryToJSON(const CTxMemPool& pool, UniValue& info, const CTxMemPoolEntry& e) EXCLUSIVE_LOCKS_REQUIRED(pool.cs)
 280  {
 281      AssertLockHeld(pool.cs);
 282  
 283      info.pushKV("vsize", (int)e.GetTxSize());
 284      info.pushKV("weight", (int)e.GetTxWeight());
 285      info.pushKV("time", count_seconds(e.GetTime()));
 286      info.pushKV("height", (int)e.GetHeight());
 287      info.pushKV("descendantcount", e.GetCountWithDescendants());
 288      info.pushKV("descendantsize", e.GetSizeWithDescendants());
 289      info.pushKV("ancestorcount", e.GetCountWithAncestors());
 290      info.pushKV("ancestorsize", e.GetSizeWithAncestors());
 291      info.pushKV("wtxid", e.GetTx().GetWitnessHash().ToString());
 292  
 293      UniValue fees(UniValue::VOBJ);
 294      fees.pushKV("base", ValueFromAmount(e.GetFee()));
 295      fees.pushKV("modified", ValueFromAmount(e.GetModifiedFee()));
 296      fees.pushKV("ancestor", ValueFromAmount(e.GetModFeesWithAncestors()));
 297      fees.pushKV("descendant", ValueFromAmount(e.GetModFeesWithDescendants()));
 298      info.pushKV("fees", fees);
 299  
 300      const CTransaction& tx = e.GetTx();
 301      std::set<std::string> setDepends;
 302      for (const CTxIn& txin : tx.vin)
 303      {
 304          if (pool.exists(GenTxid::Txid(txin.prevout.hash)))
 305              setDepends.insert(txin.prevout.hash.ToString());
 306      }
 307  
 308      UniValue depends(UniValue::VARR);
 309      for (const std::string& dep : setDepends)
 310      {
 311          depends.push_back(dep);
 312      }
 313  
 314      info.pushKV("depends", depends);
 315  
 316      UniValue spent(UniValue::VARR);
 317      for (const CTxMemPoolEntry& child : e.GetMemPoolChildrenConst()) {
 318          spent.push_back(child.GetTx().GetHash().ToString());
 319      }
 320  
 321      info.pushKV("spentby", spent);
 322  
 323      // Add opt-in RBF status
 324      bool rbfStatus = false;
 325      RBFTransactionState rbfState = IsRBFOptIn(tx, pool);
 326      if (rbfState == RBFTransactionState::UNKNOWN) {
 327          throw JSONRPCError(RPC_MISC_ERROR, "Transaction is not in mempool");
 328      } else if (rbfState == RBFTransactionState::REPLACEABLE_BIP125) {
 329          rbfStatus = true;
 330      }
 331  
 332      info.pushKV("bip125-replaceable", rbfStatus);
 333      info.pushKV("unbroadcast", pool.IsUnbroadcastTx(tx.GetHash()));
 334  }
 335  
 336  UniValue MempoolToJSON(const CTxMemPool& pool, bool verbose, bool include_mempool_sequence)
 337  {
 338      if (verbose) {
 339          if (include_mempool_sequence) {
 340              throw JSONRPCError(RPC_INVALID_PARAMETER, "Verbose results cannot contain mempool sequence values.");
 341          }
 342          LOCK(pool.cs);
 343          UniValue o(UniValue::VOBJ);
 344          for (const CTxMemPoolEntry& e : pool.entryAll()) {
 345              UniValue info(UniValue::VOBJ);
 346              entryToJSON(pool, info, e);
 347              // Mempool has unique entries so there is no advantage in using
 348              // UniValue::pushKV, which checks if the key already exists in O(N).
 349              // UniValue::pushKVEnd is used instead which currently is O(1).
 350              o.pushKVEnd(e.GetTx().GetHash().ToString(), info);
 351          }
 352          return o;
 353      } else {
 354          UniValue a(UniValue::VARR);
 355          uint64_t mempool_sequence;
 356          {
 357              LOCK(pool.cs);
 358              for (const CTxMemPoolEntry& e : pool.entryAll()) {
 359                  a.push_back(e.GetTx().GetHash().ToString());
 360              }
 361              mempool_sequence = pool.GetSequence();
 362          }
 363          if (!include_mempool_sequence) {
 364              return a;
 365          } else {
 366              UniValue o(UniValue::VOBJ);
 367              o.pushKV("txids", a);
 368              o.pushKV("mempool_sequence", mempool_sequence);
 369              return o;
 370          }
 371      }
 372  }
 373  
 374  static RPCHelpMan getrawmempool()
 375  {
 376      return RPCHelpMan{"getrawmempool",
 377          "\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n"
 378          "\nHint: use getmempoolentry to fetch a specific transaction from the mempool.\n",
 379          {
 380              {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"},
 381              {"mempool_sequence", RPCArg::Type::BOOL, RPCArg::Default{false}, "If verbose=false, returns a json object with transaction list and mempool sequence number attached."},
 382          },
 383          {
 384              RPCResult{"for verbose = false",
 385                  RPCResult::Type::ARR, "", "",
 386                  {
 387                      {RPCResult::Type::STR_HEX, "", "The transaction id"},
 388                  }},
 389              RPCResult{"for verbose = true",
 390                  RPCResult::Type::OBJ_DYN, "", "",
 391                  {
 392                      {RPCResult::Type::OBJ, "transactionid", "", MempoolEntryDescription()},
 393                  }},
 394              RPCResult{"for verbose = false and mempool_sequence = true",
 395                  RPCResult::Type::OBJ, "", "",
 396                  {
 397                      {RPCResult::Type::ARR, "txids", "",
 398                      {
 399                          {RPCResult::Type::STR_HEX, "", "The transaction id"},
 400                      }},
 401                      {RPCResult::Type::NUM, "mempool_sequence", "The mempool sequence value."},
 402                  }},
 403          },
 404          RPCExamples{
 405              HelpExampleCli("getrawmempool", "true")
 406              + HelpExampleRpc("getrawmempool", "true")
 407          },
 408          [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
 409  {
 410      bool fVerbose = false;
 411      if (!request.params[0].isNull())
 412          fVerbose = request.params[0].get_bool();
 413  
 414      bool include_mempool_sequence = false;
 415      if (!request.params[1].isNull()) {
 416          include_mempool_sequence = request.params[1].get_bool();
 417      }
 418  
 419      return MempoolToJSON(EnsureAnyMemPool(request.context), fVerbose, include_mempool_sequence);
 420  },
 421      };
 422  }
 423  
 424  static RPCHelpMan getmempoolancestors()
 425  {
 426      return RPCHelpMan{"getmempoolancestors",
 427          "\nIf txid is in the mempool, returns all in-mempool ancestors.\n",
 428          {
 429              {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
 430              {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"},
 431          },
 432          {
 433              RPCResult{"for verbose = false",
 434                  RPCResult::Type::ARR, "", "",
 435                  {{RPCResult::Type::STR_HEX, "", "The transaction id of an in-mempool ancestor transaction"}}},
 436              RPCResult{"for verbose = true",
 437                  RPCResult::Type::OBJ_DYN, "", "",
 438                  {
 439                      {RPCResult::Type::OBJ, "transactionid", "", MempoolEntryDescription()},
 440                  }},
 441          },
 442          RPCExamples{
 443              HelpExampleCli("getmempoolancestors", "\"mytxid\"")
 444              + HelpExampleRpc("getmempoolancestors", "\"mytxid\"")
 445          },
 446          [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
 447  {
 448      bool fVerbose = false;
 449      if (!request.params[1].isNull())
 450          fVerbose = request.params[1].get_bool();
 451  
 452      uint256 hash = ParseHashV(request.params[0], "parameter 1");
 453  
 454      const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
 455      LOCK(mempool.cs);
 456  
 457      const auto entry{mempool.GetEntry(Txid::FromUint256(hash))};
 458      if (entry == nullptr) {
 459          throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool");
 460      }
 461  
 462      auto ancestors{mempool.AssumeCalculateMemPoolAncestors(self.m_name, *entry, CTxMemPool::Limits::NoLimits(), /*fSearchForParents=*/false)};
 463  
 464      if (!fVerbose) {
 465          UniValue o(UniValue::VARR);
 466          for (CTxMemPool::txiter ancestorIt : ancestors) {
 467              o.push_back(ancestorIt->GetTx().GetHash().ToString());
 468          }
 469          return o;
 470      } else {
 471          UniValue o(UniValue::VOBJ);
 472          for (CTxMemPool::txiter ancestorIt : ancestors) {
 473              const CTxMemPoolEntry &e = *ancestorIt;
 474              const uint256& _hash = e.GetTx().GetHash();
 475              UniValue info(UniValue::VOBJ);
 476              entryToJSON(mempool, info, e);
 477              o.pushKV(_hash.ToString(), info);
 478          }
 479          return o;
 480      }
 481  },
 482      };
 483  }
 484  
 485  static RPCHelpMan getmempooldescendants()
 486  {
 487      return RPCHelpMan{"getmempooldescendants",
 488          "\nIf txid is in the mempool, returns all in-mempool descendants.\n",
 489          {
 490              {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
 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::ARR, "", "",
 496                  {{RPCResult::Type::STR_HEX, "", "The transaction id of an in-mempool descendant transaction"}}},
 497              RPCResult{"for verbose = true",
 498                  RPCResult::Type::OBJ_DYN, "", "",
 499                  {
 500                      {RPCResult::Type::OBJ, "transactionid", "", MempoolEntryDescription()},
 501                  }},
 502          },
 503          RPCExamples{
 504              HelpExampleCli("getmempooldescendants", "\"mytxid\"")
 505              + HelpExampleRpc("getmempooldescendants", "\"mytxid\"")
 506          },
 507          [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
 508  {
 509      bool fVerbose = false;
 510      if (!request.params[1].isNull())
 511          fVerbose = request.params[1].get_bool();
 512  
 513      uint256 hash = ParseHashV(request.params[0], "parameter 1");
 514  
 515      const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
 516      LOCK(mempool.cs);
 517  
 518      const auto it{mempool.GetIter(hash)};
 519      if (!it) {
 520          throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool");
 521      }
 522  
 523      CTxMemPool::setEntries setDescendants;
 524      mempool.CalculateDescendants(*it, setDescendants);
 525      // CTxMemPool::CalculateDescendants will include the given tx
 526      setDescendants.erase(*it);
 527  
 528      if (!fVerbose) {
 529          UniValue o(UniValue::VARR);
 530          for (CTxMemPool::txiter descendantIt : setDescendants) {
 531              o.push_back(descendantIt->GetTx().GetHash().ToString());
 532          }
 533  
 534          return o;
 535      } else {
 536          UniValue o(UniValue::VOBJ);
 537          for (CTxMemPool::txiter descendantIt : setDescendants) {
 538              const CTxMemPoolEntry &e = *descendantIt;
 539              const uint256& _hash = e.GetTx().GetHash();
 540              UniValue info(UniValue::VOBJ);
 541              entryToJSON(mempool, info, e);
 542              o.pushKV(_hash.ToString(), info);
 543          }
 544          return o;
 545      }
 546  },
 547      };
 548  }
 549  
 550  static RPCHelpMan getmempoolentry()
 551  {
 552      return RPCHelpMan{"getmempoolentry",
 553          "\nReturns mempool data for given transaction\n",
 554          {
 555              {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
 556          },
 557          RPCResult{
 558              RPCResult::Type::OBJ, "", "", MempoolEntryDescription()},
 559          RPCExamples{
 560              HelpExampleCli("getmempoolentry", "\"mytxid\"")
 561              + HelpExampleRpc("getmempoolentry", "\"mytxid\"")
 562          },
 563          [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
 564  {
 565      uint256 hash = ParseHashV(request.params[0], "parameter 1");
 566  
 567      const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
 568      LOCK(mempool.cs);
 569  
 570      const auto entry{mempool.GetEntry(Txid::FromUint256(hash))};
 571      if (entry == nullptr) {
 572          throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool");
 573      }
 574  
 575      UniValue info(UniValue::VOBJ);
 576      entryToJSON(mempool, info, *entry);
 577      return info;
 578  },
 579      };
 580  }
 581  
 582  static RPCHelpMan gettxspendingprevout()
 583  {
 584      return RPCHelpMan{"gettxspendingprevout",
 585          "Scans the mempool to find transactions spending any of the given outputs",
 586          {
 587              {"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The transaction outputs that we want to check, and within each, the txid (string) vout (numeric).",
 588                  {
 589                      {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
 590                          {
 591                              {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
 592                              {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
 593                          },
 594                      },
 595                  },
 596              },
 597          },
 598          RPCResult{
 599              RPCResult::Type::ARR, "", "",
 600              {
 601                  {RPCResult::Type::OBJ, "", "",
 602                  {
 603                      {RPCResult::Type::STR_HEX, "txid", "the transaction id of the checked output"},
 604                      {RPCResult::Type::NUM, "vout", "the vout value of the checked output"},
 605                      {RPCResult::Type::STR_HEX, "spendingtxid", /*optional=*/true, "the transaction id of the mempool transaction spending this output (omitted if unspent)"},
 606                  }},
 607              }
 608          },
 609          RPCExamples{
 610              HelpExampleCli("gettxspendingprevout", "\"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":3}]\"")
 611              + HelpExampleRpc("gettxspendingprevout", "\"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":3}]\"")
 612          },
 613          [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
 614          {
 615              const UniValue& output_params = request.params[0].get_array();
 616              if (output_params.empty()) {
 617                  throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, outputs are missing");
 618              }
 619  
 620              std::vector<COutPoint> prevouts;
 621              prevouts.reserve(output_params.size());
 622  
 623              for (unsigned int idx = 0; idx < output_params.size(); idx++) {
 624                  const UniValue& o = output_params[idx].get_obj();
 625  
 626                  RPCTypeCheckObj(o,
 627                                  {
 628                                      {"txid", UniValueType(UniValue::VSTR)},
 629                                      {"vout", UniValueType(UniValue::VNUM)},
 630                                  }, /*fAllowNull=*/false, /*fStrict=*/true);
 631  
 632                  const Txid txid = Txid::FromUint256(ParseHashO(o, "txid"));
 633                  const int nOutput{o.find_value("vout").getInt<int>()};
 634                  if (nOutput < 0) {
 635                      throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative");
 636                  }
 637  
 638                  prevouts.emplace_back(txid, nOutput);
 639              }
 640  
 641              const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
 642              LOCK(mempool.cs);
 643  
 644              UniValue result{UniValue::VARR};
 645  
 646              for (const COutPoint& prevout : prevouts) {
 647                  UniValue o(UniValue::VOBJ);
 648                  o.pushKV("txid", prevout.hash.ToString());
 649                  o.pushKV("vout", (uint64_t)prevout.n);
 650  
 651                  const CTransaction* spendingTx = mempool.GetConflictTx(prevout);
 652                  if (spendingTx != nullptr) {
 653                      o.pushKV("spendingtxid", spendingTx->GetHash().ToString());
 654                  }
 655  
 656                  result.push_back(o);
 657              }
 658  
 659              return result;
 660          },
 661      };
 662  }
 663  
 664  UniValue MempoolInfoToJSON(const CTxMemPool& pool)
 665  {
 666      // Make sure this call is atomic in the pool.
 667      LOCK(pool.cs);
 668      UniValue ret(UniValue::VOBJ);
 669      ret.pushKV("loaded", pool.GetLoadTried());
 670      ret.pushKV("size", (int64_t)pool.size());
 671      ret.pushKV("bytes", (int64_t)pool.GetTotalTxSize());
 672      ret.pushKV("usage", (int64_t)pool.DynamicMemoryUsage());
 673      ret.pushKV("total_fee", ValueFromAmount(pool.GetTotalFee()));
 674      ret.pushKV("maxmempool", pool.m_max_size_bytes);
 675      ret.pushKV("mempoolminfee", ValueFromAmount(std::max(pool.GetMinFee(), pool.m_min_relay_feerate).GetFeePerK()));
 676      ret.pushKV("minrelaytxfee", ValueFromAmount(pool.m_min_relay_feerate.GetFeePerK()));
 677      ret.pushKV("incrementalrelayfee", ValueFromAmount(pool.m_incremental_relay_feerate.GetFeePerK()));
 678      ret.pushKV("unbroadcastcount", uint64_t{pool.GetUnbroadcastTxs().size()});
 679      ret.pushKV("fullrbf", pool.m_full_rbf);
 680      return ret;
 681  }
 682  
 683  static RPCHelpMan getmempoolinfo()
 684  {
 685      return RPCHelpMan{"getmempoolinfo",
 686          "Returns details on the active state of the TX memory pool.",
 687          {},
 688          RPCResult{
 689              RPCResult::Type::OBJ, "", "",
 690              {
 691                  {RPCResult::Type::BOOL, "loaded", "True if the initial load attempt of the persisted mempool finished"},
 692                  {RPCResult::Type::NUM, "size", "Current tx count"},
 693                  {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"},
 694                  {RPCResult::Type::NUM, "usage", "Total memory usage for the mempool"},
 695                  {RPCResult::Type::STR_AMOUNT, "total_fee", "Total fees for the mempool in " + CURRENCY_UNIT + ", ignoring modified fees through prioritisetransaction"},
 696                  {RPCResult::Type::NUM, "maxmempool", "Maximum memory usage for the mempool"},
 697                  {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"},
 698                  {RPCResult::Type::STR_AMOUNT, "minrelaytxfee", "Current minimum relay fee for transactions"},
 699                  {RPCResult::Type::NUM, "incrementalrelayfee", "minimum fee rate increment for mempool limiting or replacement in " + CURRENCY_UNIT + "/kvB"},
 700                  {RPCResult::Type::NUM, "unbroadcastcount", "Current number of transactions that haven't passed initial broadcast yet"},
 701                  {RPCResult::Type::BOOL, "fullrbf", "True if the mempool accepts RBF without replaceability signaling inspection"},
 702              }},
 703          RPCExamples{
 704              HelpExampleCli("getmempoolinfo", "")
 705              + HelpExampleRpc("getmempoolinfo", "")
 706          },
 707          [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
 708  {
 709      return MempoolInfoToJSON(EnsureAnyMemPool(request.context));
 710  },
 711      };
 712  }
 713  
 714  static RPCHelpMan importmempool()
 715  {
 716      return RPCHelpMan{
 717          "importmempool",
 718          "Import a mempool.dat file and attempt to add its contents to the mempool.\n"
 719          "Warning: Importing untrusted files is dangerous, especially if metadata from the file is taken over.",
 720          {
 721              {"filepath", RPCArg::Type::STR, RPCArg::Optional::NO, "The mempool file"},
 722              {"options",
 723               RPCArg::Type::OBJ_NAMED_PARAMS,
 724               RPCArg::Optional::OMITTED,
 725               "",
 726               {
 727                   {"use_current_time", RPCArg::Type::BOOL, RPCArg::Default{true},
 728                    "Whether to use the current system time or use the entry time metadata from the mempool file.\n"
 729                    "Warning: Importing untrusted metadata may lead to unexpected issues and undesirable behavior."},
 730                   {"apply_fee_delta_priority", RPCArg::Type::BOOL, RPCArg::Default{false},
 731                    "Whether to apply the fee delta metadata from the mempool file.\n"
 732                    "It will be added to any existing fee deltas.\n"
 733                    "The fee delta can be set by the prioritisetransaction RPC.\n"
 734                    "Warning: Importing untrusted metadata may lead to unexpected issues and undesirable behavior.\n"
 735                    "Only set this bool if you understand what it does."},
 736                   {"apply_unbroadcast_set", RPCArg::Type::BOOL, RPCArg::Default{false},
 737                    "Whether to apply the unbroadcast set metadata from the mempool file.\n"
 738                    "Warning: Importing untrusted metadata may lead to unexpected issues and undesirable behavior."},
 739               },
 740               RPCArgOptions{.oneline_description = "options"}},
 741          },
 742          RPCResult{RPCResult::Type::OBJ, "", "", std::vector<RPCResult>{}},
 743          RPCExamples{HelpExampleCli("importmempool", "/path/to/mempool.dat") + HelpExampleRpc("importmempool", "/path/to/mempool.dat")},
 744          [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue {
 745              const NodeContext& node{EnsureAnyNodeContext(request.context)};
 746  
 747              CTxMemPool& mempool{EnsureMemPool(node)};
 748              ChainstateManager& chainman = EnsureChainman(node);
 749              Chainstate& chainstate = chainman.ActiveChainstate();
 750  
 751              if (chainman.IsInitialBlockDownload()) {
 752                  throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Can only import the mempool after the block download and sync is done.");
 753              }
 754  
 755              const fs::path load_path{fs::u8path(request.params[0].get_str())};
 756              const UniValue& use_current_time{request.params[1]["use_current_time"]};
 757              const UniValue& apply_fee_delta{request.params[1]["apply_fee_delta_priority"]};
 758              const UniValue& apply_unbroadcast{request.params[1]["apply_unbroadcast_set"]};
 759              kernel::ImportMempoolOptions opts{
 760                  .use_current_time = use_current_time.isNull() ? true : use_current_time.get_bool(),
 761                  .apply_fee_delta_priority = apply_fee_delta.isNull() ? false : apply_fee_delta.get_bool(),
 762                  .apply_unbroadcast_set = apply_unbroadcast.isNull() ? false : apply_unbroadcast.get_bool(),
 763              };
 764  
 765              if (!kernel::LoadMempool(mempool, load_path, chainstate, std::move(opts))) {
 766                  throw JSONRPCError(RPC_MISC_ERROR, "Unable to import mempool file, see debug.log for details.");
 767              }
 768  
 769              UniValue ret{UniValue::VOBJ};
 770              return ret;
 771          },
 772      };
 773  }
 774  
 775  static RPCHelpMan savemempool()
 776  {
 777      return RPCHelpMan{"savemempool",
 778          "\nDumps the mempool to disk. It will fail until the previous dump is fully loaded.\n",
 779          {},
 780          RPCResult{
 781              RPCResult::Type::OBJ, "", "",
 782              {
 783                  {RPCResult::Type::STR, "filename", "the directory and file where the mempool was saved"},
 784              }},
 785          RPCExamples{
 786              HelpExampleCli("savemempool", "")
 787              + HelpExampleRpc("savemempool", "")
 788          },
 789          [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
 790  {
 791      const ArgsManager& args{EnsureAnyArgsman(request.context)};
 792      const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
 793  
 794      if (!mempool.GetLoadTried()) {
 795          throw JSONRPCError(RPC_MISC_ERROR, "The mempool was not loaded yet");
 796      }
 797  
 798      const fs::path& dump_path = MempoolPath(args);
 799  
 800      if (!DumpMempool(mempool, dump_path)) {
 801          throw JSONRPCError(RPC_MISC_ERROR, "Unable to dump mempool to disk");
 802      }
 803  
 804      UniValue ret(UniValue::VOBJ);
 805      ret.pushKV("filename", dump_path.utf8string());
 806  
 807      return ret;
 808  },
 809      };
 810  }
 811  
 812  static RPCHelpMan submitpackage()
 813  {
 814      return RPCHelpMan{"submitpackage",
 815          "Submit a package of raw transactions (serialized, hex-encoded) to local node.\n"
 816          "The package must consist of a child with its parents, and none of the parents may depend on one another.\n"
 817          "The package will be validated according to consensus and mempool policy rules. If any transaction passes, it will be accepted to mempool.\n"
 818          "This RPC is experimental and the interface may be unstable. Refer to doc/policy/packages.md for documentation on package policies.\n"
 819          "Warning: successful submission does not mean the transactions will propagate throughout the network.\n"
 820          ,
 821          {
 822              {"package", RPCArg::Type::ARR, RPCArg::Optional::NO, "An array of raw transactions.",
 823                  {
 824                      {"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
 825                  },
 826              },
 827              {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())},
 828               "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT +
 829                   "/kvB.\nFee rates larger than 1BTC/kvB are rejected.\nSet to 0 to accept any fee rate."},
 830              {"maxburnamount", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_BURN_AMOUNT)},
 831               "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"
 832               "If burning funds through unspendable outputs is desired, increase this value.\n"
 833               "This check is based on heuristics and does not guarantee spendability of outputs.\n"
 834              },
 835          },
 836          RPCResult{
 837              RPCResult::Type::OBJ, "", "",
 838              {
 839                  {RPCResult::Type::STR, "package_msg", "The transaction package result message. \"success\" indicates all transactions were accepted into or are already in the mempool."},
 840                  {RPCResult::Type::OBJ_DYN, "tx-results", "transaction results keyed by wtxid",
 841                  {
 842                      {RPCResult::Type::OBJ, "wtxid", "transaction wtxid", {
 843                          {RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
 844                          {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."},
 845                          {RPCResult::Type::NUM, "vsize", /*optional=*/true, "Sigops-adjusted virtual transaction size."},
 846                          {RPCResult::Type::OBJ, "fees", /*optional=*/true, "Transaction fees", {
 847                              {RPCResult::Type::STR_AMOUNT, "base", "transaction fee in " + CURRENCY_UNIT},
 848                              {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."},
 849                              {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.",
 850                                  {{RPCResult::Type::STR_HEX, "", "transaction wtxid in hex"},
 851                              }},
 852                          }},
 853                          {RPCResult::Type::STR, "error", /*optional=*/true, "The transaction error string, if it was rejected by the mempool"},
 854                      }}
 855                  }},
 856                  {RPCResult::Type::ARR, "replaced-transactions", /*optional=*/true, "List of txids of replaced transactions",
 857                  {
 858                      {RPCResult::Type::STR_HEX, "", "The transaction id"},
 859                  }},
 860              },
 861          },
 862          RPCExamples{
 863              HelpExampleCli("testmempoolaccept", "[rawtx1, rawtx2]") +
 864              HelpExampleCli("submitpackage", "[rawtx1, rawtx2]")
 865          },
 866          [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
 867          {
 868              const UniValue raw_transactions = request.params[0].get_array();
 869              if (raw_transactions.size() < 1 || raw_transactions.size() > MAX_PACKAGE_COUNT) {
 870                  throw JSONRPCError(RPC_INVALID_PARAMETER,
 871                                     "Array must contain between 1 and " + ToString(MAX_PACKAGE_COUNT) + " transactions.");
 872              }
 873  
 874              // Fee check needs to be run with chainstate and package context
 875              const CFeeRate max_raw_tx_fee_rate = ParseFeeRate(self.Arg<UniValue>(1));
 876              std::optional<CFeeRate> client_maxfeerate{max_raw_tx_fee_rate};
 877              // 0-value is special; it's mapped to no sanity check
 878              if (max_raw_tx_fee_rate == CFeeRate(0)) {
 879                  client_maxfeerate = std::nullopt;
 880              }
 881  
 882              // Burn sanity check is run with no context
 883              const CAmount max_burn_amount = request.params[2].isNull() ? 0 : AmountFromValue(request.params[2]);
 884  
 885              std::vector<CTransactionRef> txns;
 886              txns.reserve(raw_transactions.size());
 887              for (const auto& rawtx : raw_transactions.getValues()) {
 888                  CMutableTransaction mtx;
 889                  if (!DecodeHexTx(mtx, rawtx.get_str())) {
 890                      throw JSONRPCError(RPC_DESERIALIZATION_ERROR,
 891                                         "TX decode failed: " + rawtx.get_str() + " Make sure the tx has at least one input.");
 892                  }
 893  
 894                  for (const auto& out : mtx.vout) {
 895                      if((out.scriptPubKey.IsUnspendable() || !out.scriptPubKey.HasValidOps()) && out.nValue > max_burn_amount) {
 896                          throw JSONRPCTransactionError(TransactionError::MAX_BURN_EXCEEDED);
 897                      }
 898                  }
 899  
 900                  txns.emplace_back(MakeTransactionRef(std::move(mtx)));
 901              }
 902              if (!IsChildWithParentsTree(txns)) {
 903                  throw JSONRPCTransactionError(TransactionError::INVALID_PACKAGE, "package topology disallowed. not child-with-parents or parents depend on each other.");
 904              }
 905  
 906              NodeContext& node = EnsureAnyNodeContext(request.context);
 907              CTxMemPool& mempool = EnsureMemPool(node);
 908              Chainstate& chainstate = EnsureChainman(node).ActiveChainstate();
 909              const auto package_result = WITH_LOCK(::cs_main, return ProcessNewPackage(chainstate, mempool, txns, /*test_accept=*/ false, client_maxfeerate));
 910  
 911              std::string package_msg = "success";
 912  
 913              // First catch package-wide errors, continue if we can
 914              switch(package_result.m_state.GetResult()) {
 915                  case PackageValidationResult::PCKG_RESULT_UNSET:
 916                  {
 917                      // Belt-and-suspenders check; everything should be successful here
 918                      CHECK_NONFATAL(package_result.m_tx_results.size() == txns.size());
 919                      for (const auto& tx : txns) {
 920                          CHECK_NONFATAL(mempool.exists(GenTxid::Txid(tx->GetHash())));
 921                      }
 922                      break;
 923                  }
 924                  case PackageValidationResult::PCKG_MEMPOOL_ERROR:
 925                  {
 926                      // This only happens with internal bug; user should stop and report
 927                      throw JSONRPCTransactionError(TransactionError::MEMPOOL_ERROR,
 928                          package_result.m_state.GetRejectReason());
 929                  }
 930                  case PackageValidationResult::PCKG_POLICY:
 931                  case PackageValidationResult::PCKG_TX:
 932                  {
 933                      // Package-wide error we want to return, but we also want to return individual responses
 934                      package_msg = package_result.m_state.ToString();
 935                      CHECK_NONFATAL(package_result.m_tx_results.size() == txns.size() ||
 936                              package_result.m_tx_results.empty());
 937                      break;
 938                  }
 939              }
 940  
 941              size_t num_broadcast{0};
 942              for (const auto& tx : txns) {
 943                  // We don't want to re-submit the txn for validation in BroadcastTransaction
 944                  if (!mempool.exists(GenTxid::Txid(tx->GetHash()))) {
 945                      continue;
 946                  }
 947  
 948                  // We do not expect an error here; we are only broadcasting things already/still in mempool
 949                  std::string err_string;
 950                  const auto err = BroadcastTransaction(node, tx, err_string, /*max_tx_fee=*/0, /*relay=*/true, /*wait_callback=*/true);
 951                  if (err != TransactionError::OK) {
 952                      throw JSONRPCTransactionError(err,
 953                          strprintf("transaction broadcast failed: %s (%d transactions were broadcast successfully)",
 954                              err_string, num_broadcast));
 955                  }
 956                  num_broadcast++;
 957              }
 958  
 959              UniValue rpc_result{UniValue::VOBJ};
 960              rpc_result.pushKV("package_msg", package_msg);
 961              UniValue tx_result_map{UniValue::VOBJ};
 962              std::set<uint256> replaced_txids;
 963              for (const auto& tx : txns) {
 964                  UniValue result_inner{UniValue::VOBJ};
 965                  result_inner.pushKV("txid", tx->GetHash().GetHex());
 966                  auto it = package_result.m_tx_results.find(tx->GetWitnessHash());
 967                  if (it == package_result.m_tx_results.end()) {
 968                      // No results, report error and continue
 969                      result_inner.pushKV("error", "unevaluated");
 970                      continue;
 971                  }
 972                  const auto& tx_result = it->second;
 973                  switch(it->second.m_result_type) {
 974                  case MempoolAcceptResult::ResultType::DIFFERENT_WITNESS:
 975                      result_inner.pushKV("other-wtxid", it->second.m_other_wtxid.value().GetHex());
 976                      break;
 977                  case MempoolAcceptResult::ResultType::INVALID:
 978                      result_inner.pushKV("error", it->second.m_state.ToString());
 979                      break;
 980                  case MempoolAcceptResult::ResultType::VALID:
 981                  case MempoolAcceptResult::ResultType::MEMPOOL_ENTRY:
 982                      result_inner.pushKV("vsize", int64_t{it->second.m_vsize.value()});
 983                      UniValue fees(UniValue::VOBJ);
 984                      fees.pushKV("base", ValueFromAmount(it->second.m_base_fees.value()));
 985                      if (tx_result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
 986                          // Effective feerate is not provided for MEMPOOL_ENTRY transactions even
 987                          // though modified fees is known, because it is unknown whether package
 988                          // feerate was used when it was originally submitted.
 989                          fees.pushKV("effective-feerate", ValueFromAmount(tx_result.m_effective_feerate.value().GetFeePerK()));
 990                          UniValue effective_includes_res(UniValue::VARR);
 991                          for (const auto& wtxid : tx_result.m_wtxids_fee_calculations.value()) {
 992                              effective_includes_res.push_back(wtxid.ToString());
 993                          }
 994                          fees.pushKV("effective-includes", effective_includes_res);
 995                      }
 996                      result_inner.pushKV("fees", fees);
 997                      if (it->second.m_replaced_transactions.has_value()) {
 998                          for (const auto& ptx : it->second.m_replaced_transactions.value()) {
 999                              replaced_txids.insert(ptx->GetHash());
1000                          }
1001                      }
1002                      break;
1003                  }
1004                  tx_result_map.pushKV(tx->GetWitnessHash().GetHex(), result_inner);
1005              }
1006              rpc_result.pushKV("tx-results", tx_result_map);
1007              UniValue replaced_list(UniValue::VARR);
1008              for (const uint256& hash : replaced_txids) replaced_list.push_back(hash.ToString());
1009              rpc_result.pushKV("replaced-transactions", replaced_list);
1010              return rpc_result;
1011          },
1012      };
1013  }
1014  
1015  void RegisterMempoolRPCCommands(CRPCTable& t)
1016  {
1017      static const CRPCCommand commands[]{
1018          {"rawtransactions", &sendrawtransaction},
1019          {"rawtransactions", &testmempoolaccept},
1020          {"blockchain", &getmempoolancestors},
1021          {"blockchain", &getmempooldescendants},
1022          {"blockchain", &getmempoolentry},
1023          {"blockchain", &gettxspendingprevout},
1024          {"blockchain", &getmempoolinfo},
1025          {"blockchain", &getrawmempool},
1026          {"blockchain", &importmempool},
1027          {"blockchain", &savemempool},
1028          {"rawtransactions", &submitpackage},
1029      };
1030      for (const auto& c : commands) {
1031          t.appendCommand(c.name, &c);
1032      }
1033  }