Bitcoin ABC  0.29.9
P2P Digital Currency
mempool.cpp
Go to the documentation of this file.
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 <kernel/mempool_entry.h>
8 
9 #include <chainparams.h>
10 #include <core_io.h>
11 #include <node/context.h>
13 #include <policy/settings.h>
14 #include <primitives/transaction.h>
15 #include <rpc/server.h>
16 #include <rpc/server_util.h>
17 #include <rpc/util.h>
18 #include <txmempool.h>
19 #include <univalue.h>
20 #include <util/fs.h>
21 #include <util/moneystr.h>
22 #include <validation.h>
23 #include <validationinterface.h>
24 
26 
28 using node::MempoolPath;
29 using node::NodeContext;
31 
33  return RPCHelpMan{
34  "sendrawtransaction",
35  "Submits raw transaction (serialized, hex-encoded) to local node and "
36  "network.\n"
37  "\nAlso see createrawtransaction and "
38  "signrawtransactionwithkey calls.\n",
39  {
41  "The hex string of the raw transaction"},
42  {"maxfeerate", RPCArg::Type::AMOUNT,
45  "Reject transactions whose fee rate is higher than the specified "
46  "value, expressed in " +
48  "/kB\nSet to 0 to accept any fee rate.\n"},
49  },
50  RPCResult{RPCResult::Type::STR_HEX, "", "The transaction hash in hex"},
52  "\nCreate a transaction\n" +
54  "createrawtransaction",
55  "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" "
56  "\"{\\\"myaddress\\\":10000}\"") +
57  "Sign the transaction, and get back the hex\n" +
58  HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") +
59  "\nSend the transaction (signed hex)\n" +
60  HelpExampleCli("sendrawtransaction", "\"signedhex\"") +
61  "\nAs a JSON-RPC call\n" +
62  HelpExampleRpc("sendrawtransaction", "\"signedhex\"")},
63  [&](const RPCHelpMan &self, const Config &config,
64  const JSONRPCRequest &request) -> UniValue {
65  // parse hex string from parameter
67  if (!DecodeHexTx(mtx, request.params[0].get_str())) {
69  "TX decode failed");
70  }
71 
72  CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
73 
74  const CFeeRate max_raw_tx_fee_rate =
75  request.params[1].isNull()
77  : CFeeRate(AmountFromValue(request.params[1]));
78 
79  int64_t virtual_size = GetVirtualTransactionSize(*tx);
80  Amount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size);
81 
82  std::string err_string;
84  NodeContext &node = EnsureAnyNodeContext(request.context);
86  node, tx, err_string, max_raw_tx_fee, /*relay*/ true,
87  /*wait_callback*/ true);
88  if (err != TransactionError::OK) {
89  throw JSONRPCTransactionError(err, err_string);
90  }
91 
92  // Block to make sure wallet/indexers sync before returning
94 
95  return tx->GetHash().GetHex();
96  },
97  };
98 }
99 
101  const auto ticker = Currency::get().ticker;
102  return RPCHelpMan{
103  "testmempoolaccept",
104  "\nReturns result of mempool acceptance tests indicating if raw "
105  "transaction(s) (serialized, hex-encoded) would be accepted by "
106  "mempool.\n"
107  "\nIf multiple transactions are passed in, parents must come before "
108  "children and package policies apply: the transactions cannot conflict "
109  "with any mempool transactions or each other.\n"
110  "\nIf one transaction fails, other transactions may not be fully "
111  "validated (the 'allowed' key will be blank).\n"
112  "\nThe maximum number of transactions allowed is " +
114  ".\n"
115  "\nThis checks if transactions violate the consensus or policy "
116  "rules.\n"
117  "\nSee sendrawtransaction call.\n",
118  {
119  {
120  "rawtxs",
123  "An array of hex strings of raw transactions.",
124  {
126  ""},
127  },
128  },
129  {"maxfeerate", RPCArg::Type::AMOUNT,
132  "Reject transactions whose fee rate is higher than the specified "
133  "value, expressed in " +
134  ticker + "/kB\n"},
135  },
136  RPCResult{
138  "",
139  "The result of the mempool acceptance test for each raw "
140  "transaction in the input array.\n"
141  "Returns results for each transaction in the same order they were "
142  "passed in.\n"
143  "Transactions that cannot be fully validated due to failures in "
144  "other transactions will not contain an 'allowed' result.\n",
145  {
147  "",
148  "",
149  {
150  {RPCResult::Type::STR_HEX, "txid",
151  "The transaction hash in hex"},
152  {RPCResult::Type::STR, "package-error",
153  "Package validation error, if any (only possible if "
154  "rawtxs had more than 1 transaction)."},
155  {RPCResult::Type::BOOL, "allowed",
156  "Whether this tx would be accepted to the mempool and "
157  "pass client-specified maxfeerate. "
158  "If not present, the tx was not fully validated due to a "
159  "failure in another tx in the list."},
160  {RPCResult::Type::NUM, "size", "The transaction size"},
162  "fees",
163  "Transaction fees (only present if 'allowed' is true)",
164  {
166  "transaction fee in " + ticker},
167  {RPCResult::Type::STR_AMOUNT, "effective-feerate",
168  "the effective feerate in " + ticker +
169  " per KvB. May differ from the base feerate if, "
170  "for example, there are modified fees from "
171  "prioritisetransaction or a package feerate was "
172  "used."},
174  "effective-includes",
175  "transactions whose fees and vsizes are included in "
176  "effective-feerate.",
177  {
179  "transaction txid in hex"},
180  }},
181  }},
182  {RPCResult::Type::STR, "reject-reason",
183  "Rejection string (only present when 'allowed' is "
184  "false)"},
185  }},
186  }},
187  RPCExamples{
188  "\nCreate a transaction\n" +
190  "createrawtransaction",
191  "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" "
192  "\"{\\\"myaddress\\\":10000}\"") +
193  "Sign the transaction, and get back the hex\n" +
194  HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") +
195  "\nTest acceptance of the transaction (signed hex)\n" +
196  HelpExampleCli("testmempoolaccept", R"('["signedhex"]')") +
197  "\nAs a JSON-RPC call\n" +
198  HelpExampleRpc("testmempoolaccept", "[\"signedhex\"]")},
199  [&](const RPCHelpMan &self, const Config &config,
200  const JSONRPCRequest &request) -> UniValue {
201  const UniValue raw_transactions = request.params[0].get_array();
202  if (raw_transactions.size() < 1 ||
203  raw_transactions.size() > MAX_PACKAGE_COUNT) {
205  "Array must contain between 1 and " +
207  " transactions.");
208  }
209 
210  const CFeeRate max_raw_tx_fee_rate =
211  request.params[1].isNull()
213  : CFeeRate(AmountFromValue(request.params[1]));
214 
215  std::vector<CTransactionRef> txns;
216  txns.reserve(raw_transactions.size());
217  for (const auto &rawtx : raw_transactions.getValues()) {
219  if (!DecodeHexTx(mtx, rawtx.get_str())) {
221  "TX decode failed: " + rawtx.get_str());
222  }
223  txns.emplace_back(MakeTransactionRef(std::move(mtx)));
224  }
225 
226  NodeContext &node = EnsureAnyNodeContext(request.context);
227  CTxMemPool &mempool = EnsureMemPool(node);
229  Chainstate &chainstate = chainman.ActiveChainstate();
230  const PackageMempoolAcceptResult package_result = [&] {
231  LOCK(::cs_main);
232  if (txns.size() > 1) {
233  return ProcessNewPackage(chainstate, mempool, txns,
234  /* test_accept */ true);
235  }
237  txns[0]->GetId(),
238  chainman.ProcessTransaction(txns[0],
239  /* test_accept*/ true));
240  }();
241 
242  UniValue rpc_result(UniValue::VARR);
243  // We will check transaction fees while we iterate through txns in
244  // order. If any transaction fee exceeds maxfeerate, we will leave
245  // the rest of the validation results blank, because it doesn't make
246  // sense to return a validation result for a transaction if its
247  // ancestor(s) would not be submitted.
248  bool exit_early{false};
249  for (const auto &tx : txns) {
250  UniValue result_inner(UniValue::VOBJ);
251  result_inner.pushKV("txid", tx->GetId().GetHex());
252  if (package_result.m_state.GetResult() ==
254  result_inner.pushKV(
255  "package-error",
256  package_result.m_state.GetRejectReason());
257  }
258  auto it = package_result.m_tx_results.find(tx->GetId());
259  if (exit_early || it == package_result.m_tx_results.end()) {
260  // Validation unfinished. Just return the txid.
261  rpc_result.push_back(result_inner);
262  continue;
263  }
264  const auto &tx_result = it->second;
265  // Package testmempoolaccept doesn't allow transactions to
266  // already be in the mempool.
267  CHECK_NONFATAL(tx_result.m_result_type !=
269  if (tx_result.m_result_type ==
271  const Amount fee = tx_result.m_base_fees.value();
272  // Check that fee does not exceed maximum fee
273  const int64_t virtual_size = tx_result.m_vsize.value();
274  const Amount max_raw_tx_fee =
275  max_raw_tx_fee_rate.GetFee(virtual_size);
276  if (max_raw_tx_fee != Amount::zero() &&
277  fee > max_raw_tx_fee) {
278  result_inner.pushKV("allowed", false);
279  result_inner.pushKV("reject-reason",
280  "max-fee-exceeded");
281  exit_early = true;
282  } else {
283  // Only return the fee and size if the transaction
284  // would pass ATMP.
285  // These can be used to calculate the feerate.
286  result_inner.pushKV("allowed", true);
287  result_inner.pushKV("size", virtual_size);
288  UniValue fees(UniValue::VOBJ);
289  fees.pushKV("base", fee);
290  fees.pushKV(
291  "effective-feerate",
292  tx_result.m_effective_feerate.value().GetFeePerK());
293  UniValue effective_includes_res(UniValue::VARR);
294  for (const auto &txid :
295  tx_result.m_txids_fee_calculations.value()) {
296  effective_includes_res.push_back(txid.ToString());
297  }
298  fees.pushKV("effective-includes",
299  effective_includes_res);
300  result_inner.pushKV("fees", fees);
301  }
302  } else {
303  result_inner.pushKV("allowed", false);
304  const TxValidationState state = tx_result.m_state;
305  if (state.GetResult() ==
307  result_inner.pushKV("reject-reason", "missing-inputs");
308  } else {
309  result_inner.pushKV("reject-reason",
310  state.GetRejectReason());
311  }
312  }
313  rpc_result.push_back(result_inner);
314  }
315  return rpc_result;
316  },
317  };
318 }
319 
320 static std::vector<RPCResult> MempoolEntryDescription() {
321  const auto &ticker = Currency::get().ticker;
322  return {
323  RPCResult{RPCResult::Type::NUM, "size", "transaction size."},
325  "local time transaction entered pool in seconds since 1 Jan "
326  "1970 GMT"},
328  "block height when transaction entered pool"},
330  "fees",
331  "",
332  {{
334  "transaction fee in " + ticker},
336  "transaction fee with fee deltas used for "
337  "mining priority in " +
338  ticker},
339  }}},
340  RPCResult{
342  "depends",
343  "unconfirmed transactions used as inputs for this transaction",
344  {RPCResult{RPCResult::Type::STR_HEX, "transactionid",
345  "parent transaction id"}}},
346  RPCResult{
348  "spentby",
349  "unconfirmed transactions spending outputs from this transaction",
350  {RPCResult{RPCResult::Type::STR_HEX, "transactionid",
351  "child transaction id"}}},
352  RPCResult{RPCResult::Type::BOOL, "unbroadcast",
353  "Whether this transaction is currently unbroadcast (initial "
354  "broadcast not yet acknowledged by any peers)"},
355  };
356 }
357 
358 static void entryToJSON(const CTxMemPool &pool, UniValue &info,
359  const CTxMemPoolEntryRef &e)
360  EXCLUSIVE_LOCKS_REQUIRED(pool.cs) {
361  AssertLockHeld(pool.cs);
362 
363  UniValue fees(UniValue::VOBJ);
364  fees.pushKV("base", e->GetFee());
365  fees.pushKV("modified", e->GetModifiedFee());
366  info.pushKV("fees", fees);
367 
368  info.pushKV("size", (int)e->GetTxSize());
369  info.pushKV("time", count_seconds(e->GetTime()));
370  info.pushKV("height", (int)e->GetHeight());
371  const CTransaction &tx = e->GetTx();
372  std::set<std::string> setDepends;
373  for (const CTxIn &txin : tx.vin) {
374  if (pool.exists(txin.prevout.GetTxId())) {
375  setDepends.insert(txin.prevout.GetTxId().ToString());
376  }
377  }
378 
379  UniValue depends(UniValue::VARR);
380  for (const std::string &dep : setDepends) {
381  depends.push_back(dep);
382  }
383 
384  info.pushKV("depends", depends);
385 
386  UniValue spent(UniValue::VARR);
387  for (const auto &child : e->GetMemPoolChildrenConst()) {
388  spent.push_back(child.get()->GetTx().GetId().ToString());
389  }
390 
391  info.pushKV("spentby", spent);
392  info.pushKV("unbroadcast", pool.IsUnbroadcastTx(tx.GetId()));
393 }
394 
395 UniValue MempoolToJSON(const CTxMemPool &pool, bool verbose,
396  bool include_mempool_sequence) {
397  if (verbose) {
398  if (include_mempool_sequence) {
399  throw JSONRPCError(
401  "Verbose results cannot contain mempool sequence values.");
402  }
403  LOCK(pool.cs);
405  for (const CTxMemPoolEntryRef &e : pool.mapTx) {
406  const TxId &txid = e->GetTx().GetId();
407  UniValue info(UniValue::VOBJ);
408  entryToJSON(pool, info, e);
409  // Mempool has unique entries so there is no advantage in using
410  // UniValue::pushKV, which checks if the key already exists in O(N).
411  // UniValue::pushKVEnd is used instead which currently is O(1).
412  o.pushKVEnd(txid.ToString(), info);
413  }
414  return o;
415  } else {
416  uint64_t mempool_sequence;
417  std::vector<TxId> vtxids;
418  {
419  LOCK(pool.cs);
420  pool.getAllTxIds(vtxids);
421  mempool_sequence = pool.GetSequence();
422  }
424  for (const TxId &txid : vtxids) {
425  a.push_back(txid.ToString());
426  }
427 
428  if (!include_mempool_sequence) {
429  return a;
430  } else {
432  o.pushKV("txids", a);
433  o.pushKV("mempool_sequence", mempool_sequence);
434  return o;
435  }
436  }
437 }
438 
440  return RPCHelpMan{
441  "getrawmempool",
442  "Returns all transaction ids in memory pool as a json array of "
443  "string transaction ids.\n"
444  "\nHint: use getmempoolentry to fetch a specific transaction from the "
445  "mempool.\n",
446  {
447  {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false},
448  "True for a json object, false for array of transaction ids"},
449  {"mempool_sequence", RPCArg::Type::BOOL, RPCArg::Default{false},
450  "If verbose=false, returns a json object with transaction list "
451  "and mempool sequence number attached."},
452  },
453  {
454  RPCResult{"for verbose = false",
456  "",
457  "",
458  {
459  {RPCResult::Type::STR_HEX, "", "The transaction id"},
460  }},
461  RPCResult{"for verbose = true",
463  "",
464  "",
465  {
466  {RPCResult::Type::OBJ, "transactionid", "",
468  }},
469  RPCResult{
470  "for verbose = false and mempool_sequence = true",
472  "",
473  "",
474  {
476  "txids",
477  "",
478  {
479  {RPCResult::Type::STR_HEX, "", "The transaction id"},
480  }},
481  {RPCResult::Type::NUM, "mempool_sequence",
482  "The mempool sequence value."},
483  }},
484  },
485  RPCExamples{HelpExampleCli("getrawmempool", "true") +
486  HelpExampleRpc("getrawmempool", "true")},
487  [&](const RPCHelpMan &self, const Config &config,
488  const JSONRPCRequest &request) -> UniValue {
489  bool fVerbose = false;
490  if (!request.params[0].isNull()) {
491  fVerbose = request.params[0].get_bool();
492  }
493 
494  bool include_mempool_sequence = false;
495  if (!request.params[1].isNull()) {
496  include_mempool_sequence = request.params[1].get_bool();
497  }
498 
499  return MempoolToJSON(EnsureAnyMemPool(request.context), fVerbose,
500  include_mempool_sequence);
501  },
502  };
503 }
504 
506  return RPCHelpMan{
507  "getmempoolancestors",
508  "If txid is in the mempool, returns all in-mempool ancestors.\n",
509  {
511  "The transaction id (must be in mempool)"},
512  {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false},
513  "True for a json object, false for array of transaction ids"},
514  },
515  {
516  RPCResult{
517  "for verbose = false",
519  "",
520  "",
522  "The transaction id of an in-mempool ancestor transaction"}}},
523  RPCResult{"for verbose = true",
525  "",
526  "",
527  {
528  {RPCResult::Type::OBJ, "transactionid", "",
530  }},
531  },
532  RPCExamples{HelpExampleCli("getmempoolancestors", "\"mytxid\"") +
533  HelpExampleRpc("getmempoolancestors", "\"mytxid\"")},
534  [&](const RPCHelpMan &self, const Config &config,
535  const JSONRPCRequest &request) -> UniValue {
536  bool fVerbose = false;
537  if (!request.params[1].isNull()) {
538  fVerbose = request.params[1].get_bool();
539  }
540 
541  TxId txid(ParseHashV(request.params[0], "parameter 1"));
542 
543  const CTxMemPool &mempool = EnsureAnyMemPool(request.context);
544  LOCK(mempool.cs);
545 
546  CTxMemPool::txiter it = mempool.mapTx.find(txid);
547  if (it == mempool.mapTx.end()) {
549  "Transaction not in mempool");
550  }
551 
552  CTxMemPool::setEntries setAncestors;
553  mempool.CalculateMemPoolAncestors(*it, setAncestors, false);
554 
555  if (!fVerbose) {
557  for (CTxMemPool::txiter ancestorIt : setAncestors) {
558  o.push_back((*ancestorIt)->GetTx().GetId().ToString());
559  }
560  return o;
561  } else {
563  for (CTxMemPool::txiter ancestorIt : setAncestors) {
564  const CTxMemPoolEntryRef &e = *ancestorIt;
565  const TxId &_txid = e->GetTx().GetId();
566  UniValue info(UniValue::VOBJ);
567  entryToJSON(mempool, info, e);
568  o.pushKV(_txid.ToString(), info);
569  }
570  return o;
571  }
572  },
573  };
574 }
575 
577  return RPCHelpMan{
578  "getmempooldescendants",
579  "If txid is in the mempool, returns all in-mempool descendants.\n",
580  {
582  "The transaction id (must be in mempool)"},
583  {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false},
584  "True for a json object, false for array of transaction ids"},
585  },
586  {
587  RPCResult{"for verbose = false",
589  "",
590  "",
592  "The transaction id of an in-mempool descendant "
593  "transaction"}}},
594  RPCResult{"for verbose = true",
596  "",
597  "",
598  {
599  {RPCResult::Type::OBJ, "transactionid", "",
601  }},
602  },
603  RPCExamples{HelpExampleCli("getmempooldescendants", "\"mytxid\"") +
604  HelpExampleRpc("getmempooldescendants", "\"mytxid\"")},
605  [&](const RPCHelpMan &self, const Config &config,
606  const JSONRPCRequest &request) -> UniValue {
607  bool fVerbose = false;
608  if (!request.params[1].isNull()) {
609  fVerbose = request.params[1].get_bool();
610  }
611 
612  TxId txid(ParseHashV(request.params[0], "parameter 1"));
613 
614  const CTxMemPool &mempool = EnsureAnyMemPool(request.context);
615  LOCK(mempool.cs);
616 
617  CTxMemPool::txiter it = mempool.mapTx.find(txid);
618  if (it == mempool.mapTx.end()) {
620  "Transaction not in mempool");
621  }
622 
623  CTxMemPool::setEntries setDescendants;
624  mempool.CalculateDescendants(it, setDescendants);
625  // CTxMemPool::CalculateDescendants will include the given tx
626  setDescendants.erase(it);
627 
628  if (!fVerbose) {
630  for (CTxMemPool::txiter descendantIt : setDescendants) {
631  o.push_back((*descendantIt)->GetTx().GetId().ToString());
632  }
633 
634  return o;
635  } else {
637  for (CTxMemPool::txiter descendantIt : setDescendants) {
638  const CTxMemPoolEntryRef &e = *descendantIt;
639  const TxId &_txid = e->GetTx().GetId();
640  UniValue info(UniValue::VOBJ);
641  entryToJSON(mempool, info, e);
642  o.pushKV(_txid.ToString(), info);
643  }
644  return o;
645  }
646  },
647  };
648 }
649 
651  return RPCHelpMan{
652  "getmempoolentry",
653  "Returns mempool data for given transaction\n",
654  {
656  "The transaction id (must be in mempool)"},
657  },
659  RPCExamples{HelpExampleCli("getmempoolentry", "\"mytxid\"") +
660  HelpExampleRpc("getmempoolentry", "\"mytxid\"")},
661  [&](const RPCHelpMan &self, const Config &config,
662  const JSONRPCRequest &request) -> UniValue {
663  TxId txid(ParseHashV(request.params[0], "parameter 1"));
664 
665  const CTxMemPool &mempool = EnsureAnyMemPool(request.context);
666  LOCK(mempool.cs);
667 
668  CTxMemPool::txiter it = mempool.mapTx.find(txid);
669  if (it == mempool.mapTx.end()) {
671  "Transaction not in mempool");
672  }
673 
674  UniValue info(UniValue::VOBJ);
675  entryToJSON(mempool, info, *it);
676  return info;
677  },
678  };
679 }
680 
682  // Make sure this call is atomic in the pool.
683  LOCK(pool.cs);
685  ret.pushKV("loaded", pool.GetLoadTried());
686  ret.pushKV("size", (int64_t)pool.size());
687  ret.pushKV("bytes", (int64_t)pool.GetTotalTxSize());
688  ret.pushKV("usage", (int64_t)pool.DynamicMemoryUsage());
689  ret.pushKV("total_fee", pool.GetTotalFee());
690  ret.pushKV("maxmempool", pool.m_max_size_bytes);
691  ret.pushKV(
692  "mempoolminfee",
693  std::max(pool.GetMinFee(), pool.m_min_relay_feerate).GetFeePerK());
694  ret.pushKV("minrelaytxfee", pool.m_min_relay_feerate.GetFeePerK());
695  ret.pushKV("unbroadcastcount", uint64_t{pool.GetUnbroadcastTxs().size()});
696  return ret;
697 }
698 
700  const auto &ticker = Currency::get().ticker;
701  return RPCHelpMan{
702  "getmempoolinfo",
703  "Returns details on the active state of the TX memory pool.\n",
704  {},
705  RPCResult{
707  "",
708  "",
709  {
710  {RPCResult::Type::BOOL, "loaded",
711  "True if the mempool is fully loaded"},
712  {RPCResult::Type::NUM, "size", "Current tx count"},
713  {RPCResult::Type::NUM, "bytes", "Sum of all transaction sizes"},
714  {RPCResult::Type::NUM, "usage",
715  "Total memory usage for the mempool"},
716  {RPCResult::Type::NUM, "maxmempool",
717  "Maximum memory usage for the mempool"},
718  {RPCResult::Type::STR_AMOUNT, "total_fee",
719  "Total fees for the mempool in " + ticker +
720  ", ignoring modified fees through prioritizetransaction"},
721  {RPCResult::Type::STR_AMOUNT, "mempoolminfee",
722  "Minimum fee rate in " + ticker +
723  "/kB for tx to be accepted. Is the maximum of "
724  "minrelaytxfee and minimum mempool fee"},
725  {RPCResult::Type::STR_AMOUNT, "minrelaytxfee",
726  "Current minimum relay fee for transactions"},
727  {RPCResult::Type::NUM, "unbroadcastcount",
728  "Current number of transactions that haven't passed initial "
729  "broadcast yet"},
730  }},
731  RPCExamples{HelpExampleCli("getmempoolinfo", "") +
732  HelpExampleRpc("getmempoolinfo", "")},
733  [&](const RPCHelpMan &self, const Config &config,
734  const JSONRPCRequest &request) -> UniValue {
735  return MempoolInfoToJSON(EnsureAnyMemPool(request.context));
736  },
737  };
738 }
739 
741  return RPCHelpMan{
742  "savemempool",
743  "Dumps the mempool to disk. It will fail until the previous dump is "
744  "fully loaded.\n",
745  {},
747  "",
748  "",
749  {
750  {RPCResult::Type::STR, "filename",
751  "the directory and file where the mempool was saved"},
752  }},
753  RPCExamples{HelpExampleCli("savemempool", "") +
754  HelpExampleRpc("savemempool", "")},
755  [&](const RPCHelpMan &self, const Config &config,
756  const JSONRPCRequest &request) -> UniValue {
757  const ArgsManager &args{EnsureAnyArgsman(request.context)};
758  const CTxMemPool &mempool = EnsureAnyMemPool(request.context);
759 
760  if (!mempool.GetLoadTried()) {
762  "The mempool was not loaded yet");
763  }
764 
765  const fs::path &dump_path = MempoolPath(args);
766 
767  if (!DumpMempool(mempool, dump_path)) {
769  "Unable to dump mempool to disk");
770  }
771 
773  ret.pushKV("filename", dump_path.u8string());
774 
775  return ret;
776  },
777  };
778 }
779 
781  const auto &ticker = Currency::get().ticker;
782  return RPCHelpMan{
783  "submitpackage",
784  "Submit a package of raw transactions (serialized, hex-encoded) to "
785  "local node.\n"
786  "The package must consist of a child with its parents, and none of the "
787  "parents may depend on one another.\n"
788  "The package will be validated according to consensus and mempool "
789  "policy rules. If any transaction passes, it will be accepted to "
790  "mempool.\n"
791  "This RPC is experimental and the interface may be unstable. Refer to "
792  "doc/policy/packages.md for documentation on package policies.\n"
793  "Warning: successful submission does not mean the transactions will "
794  "propagate throughout the network.\n",
795  {
796  {
797  "package",
800  "An array of raw transactions.",
801  {
803  ""},
804  },
805  },
806  },
807  RPCResult{
809  "",
810  "",
811  {
812  {RPCResult::Type::STR, "package_msg",
813  "The transaction package result message. \"success\" "
814  "indicates all transactions were accepted into or are already "
815  "in the mempool."},
817  "tx-results",
818  "transaction results keyed by txid",
820  "txid",
821  "transaction txid",
822  {
823  {RPCResult::Type::NUM, "vsize", /*optional=*/true,
824  "Virtual transaction size."},
826  "fees",
827  /*optional=*/true,
828  "Transaction fees",
829  {
831  "transaction fee in " + ticker},
832  {RPCResult::Type::STR_AMOUNT, "effective-feerate",
833  "the effective feerate in " + ticker +
834  " per KvB. May differ from the base feerate "
835  "if, for example, there are modified fees "
836  "from prioritisetransaction or a package "
837  "feerate was used."},
839  "effective-includes",
840  "transactions whose fees and vsizes are included "
841  "in effective-feerate.",
842  {
844  "transaction txid in hex"},
845  }},
846  }},
847  {RPCResult::Type::STR, "error", /*optional=*/true,
848  "The transaction error string, if it was rejected by "
849  "the mempool"},
850  }}}},
851  },
852  },
853  RPCExamples{HelpExampleCli("testmempoolaccept", "[rawtx1, rawtx2]") +
854  HelpExampleCli("submitpackage", "[rawtx1, rawtx2]")},
855  [&](const RPCHelpMan &self, const Config &config,
856  const JSONRPCRequest &request) -> UniValue {
857  const UniValue raw_transactions = request.params[0].get_array();
858  if (raw_transactions.size() < 1 ||
859  raw_transactions.size() > MAX_PACKAGE_COUNT) {
861  "Array must contain between 1 and " +
863  " transactions.");
864  }
865 
866  std::vector<CTransactionRef> txns;
867  txns.reserve(raw_transactions.size());
868  for (const auto &rawtx : raw_transactions.getValues()) {
870  if (!DecodeHexTx(mtx, rawtx.get_str())) {
871  throw JSONRPCError(
873  "TX decode failed: " + rawtx.get_str() +
874  " Make sure the tx has at least one input.");
875  }
876  txns.emplace_back(MakeTransactionRef(std::move(mtx)));
877  }
878  if (!IsChildWithParentsTree(txns)) {
881  "package topology disallowed. not child-with-parents or "
882  "parents depend on each other.");
883  }
884 
885  NodeContext &node = EnsureAnyNodeContext(request.context);
886  CTxMemPool &mempool = EnsureMemPool(node);
887  Chainstate &chainstate = EnsureChainman(node).ActiveChainstate();
888  const auto package_result = WITH_LOCK(
889  ::cs_main, return ProcessNewPackage(chainstate, mempool, txns,
890  /*test_accept=*/false));
891 
892  std::string package_msg = "success";
893 
894  // First catch package-wide errors, continue if we can
895  switch (package_result.m_state.GetResult()) {
897  // Belt-and-suspenders check; everything should be
898  // successful here
899  CHECK_NONFATAL(package_result.m_tx_results.size() ==
900  txns.size());
901  for (const auto &tx : txns) {
902  CHECK_NONFATAL(mempool.exists(tx->GetId()));
903  }
904  break;
905  }
907  // This only happens with internal bug; user should stop and
908  // report
911  package_result.m_state.GetRejectReason());
912  }
915  // Package-wide error we want to return, but we also want to
916  // return individual responses
917  package_msg = package_result.m_state.GetRejectReason();
918  CHECK_NONFATAL(package_result.m_tx_results.size() ==
919  txns.size() ||
920  package_result.m_tx_results.empty());
921  break;
922  }
923  }
924  size_t num_broadcast{0};
925  for (const auto &tx : txns) {
926  // We don't want to re-submit the txn for validation in
927  // BroadcastTransaction
928  if (!mempool.exists(tx->GetId())) {
929  continue;
930  }
931 
932  // We do not expect an error here; we are only broadcasting
933  // things already/still in mempool
934  std::string err_string;
935  const auto err = BroadcastTransaction(
936  node, tx, err_string, /*max_tx_fee=*/Amount::zero(),
937  /*relay=*/true, /*wait_callback=*/true);
938  if (err != TransactionError::OK) {
940  err,
941  strprintf("transaction broadcast failed: %s (%d "
942  "transactions were broadcast successfully)",
943  err_string, num_broadcast));
944  }
945  num_broadcast++;
946  }
947 
948  UniValue rpc_result{UniValue::VOBJ};
949  rpc_result.pushKV("package_msg", package_msg);
950  UniValue tx_result_map{UniValue::VOBJ};
951  for (const auto &tx : txns) {
952  UniValue result_inner{UniValue::VOBJ};
953  auto it = package_result.m_tx_results.find(tx->GetId());
954  if (it == package_result.m_tx_results.end()) {
955  // No results, report error and continue
956  result_inner.pushKV("error", "unevaluated");
957  continue;
958  }
959  const auto &tx_result = it->second;
960  switch (it->second.m_result_type) {
962  result_inner.pushKV("error",
963  it->second.m_state.ToString());
964  break;
967  result_inner.pushKV(
968  "vsize", int64_t{it->second.m_vsize.value()});
969  UniValue fees(UniValue::VOBJ);
970  fees.pushKV("base", it->second.m_base_fees.value());
971  if (tx_result.m_result_type ==
973  // Effective feerate is not provided for
974  // MEMPOOL_ENTRY (already in mempool) transactions
975  // even though modified fees is known, because it is
976  // unknown whether package feerate was used when it
977  // was originally submitted.
978  fees.pushKV("effective-feerate",
979  tx_result.m_effective_feerate.value()
980  .GetFeePerK());
981  UniValue effective_includes_res(UniValue::VARR);
982  for (const auto &txid :
983  tx_result.m_txids_fee_calculations.value()) {
984  effective_includes_res.push_back(
985  txid.ToString());
986  }
987  fees.pushKV("effective-includes",
988  effective_includes_res);
989  }
990  result_inner.pushKV("fees", fees);
991  break;
992  }
993  tx_result_map.pushKV(tx->GetId().GetHex(), result_inner);
994  }
995  rpc_result.pushKV("tx-results", tx_result_map);
996 
997  return rpc_result;
998  },
999  };
1000 }
1001 
1003  static const CRPCCommand commands[]{
1004  // category actor (function)
1005  // -------- ----------------
1006  {"rawtransactions", sendrawtransaction},
1007  {"rawtransactions", testmempoolaccept},
1008  {"blockchain", getmempoolancestors},
1009  {"blockchain", getmempooldescendants},
1010  {"blockchain", getmempoolentry},
1011  {"blockchain", getmempoolinfo},
1012  {"blockchain", getrawmempool},
1013  {"blockchain", savemempool},
1014  {"rawtransactions", submitpackage},
1015  };
1016  for (const auto &c : commands) {
1017  t.appendCommand(c.name, &c);
1018  }
1019 }
#define CHECK_NONFATAL(condition)
Identity function.
Definition: check.h:53
Fee rate in satoshis per kilobyte: Amount / kB.
Definition: feerate.h:21
Amount GetFeePerK() const
Return the fee in satoshis for a size of 1000 bytes.
Definition: feerate.h:54
Amount GetFee(size_t nBytes) const
Return the fee in satoshis for the given size in bytes.
Definition: feerate.cpp:49
A mutable version of CTransaction.
Definition: transaction.h:274
const TxId & GetTxId() const
Definition: transaction.h:35
RPC command dispatcher.
Definition: server.h:194
void appendCommand(const std::string &name, const CRPCCommand *pcmd)
Appends a CRPCCommand to the dispatch table.
Definition: server.cpp:327
The basic transaction that is broadcasted on the network and contained in blocks.
Definition: transaction.h:192
const std::vector< CTxIn > vin
Definition: transaction.h:206
const TxId GetId() const
Definition: transaction.h:240
An input of a transaction.
Definition: transaction.h:59
COutPoint prevout
Definition: transaction.h:61
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition: txmempool.h:209
std::set< txiter, CompareIteratorById > setEntries
Definition: txmempool.h:300
bool GetLoadTried() const
Definition: txmempool.cpp:808
CFeeRate GetMinFee() const
The minimum fee to get into the mempool, which may itself not be enough for larger-sized transactions...
Definition: txmempool.h:440
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it.
Definition: txmempool.h:296
Amount GetTotalFee() const EXCLUSIVE_LOCKS_REQUIRED(cs)
Definition: txmempool.h:487
const int64_t m_max_size_bytes
Definition: txmempool.h:333
void getAllTxIds(std::vector< TxId > &vtxid) const
Definition: txmempool.cpp:473
size_t DynamicMemoryUsage() const
Definition: txmempool.cpp:643
bool exists(const TxId &txid) const
Definition: txmempool.h:492
const CFeeRate m_min_relay_feerate
Definition: txmempool.h:335
uint64_t GetSequence() const EXCLUSIVE_LOCKS_REQUIRED(cs)
Definition: txmempool.h:545
indexed_transaction_set::nth_index< 0 >::type::const_iterator txiter
Definition: txmempool.h:299
bool CalculateMemPoolAncestors(const CTxMemPoolEntryRef &entry, setEntries &setAncestors, bool fSearchForParents=true) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Try to calculate all in-mempool ancestors of entry.
Definition: txmempool.cpp:56
std::set< TxId > GetUnbroadcastTxs() const
Returns transactions in unbroadcast set.
Definition: txmempool.h:529
void CalculateDescendants(txiter it, setEntries &setDescendants) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Populate setDescendants with all in-mempool descendants of hash.
Definition: txmempool.cpp:232
unsigned long size() const
Definition: txmempool.h:477
uint64_t GetTotalTxSize() const EXCLUSIVE_LOCKS_REQUIRED(cs)
Definition: txmempool.h:482
Chainstate stores and provides an API to update our local knowledge of the current best chain.
Definition: validation.h:695
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
Definition: validation.h:1218
MempoolAcceptResult ProcessTransaction(const CTransactionRef &tx, bool test_accept=false) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Try to add a transaction to the memory pool.
Definition: config.h:19
Definition: rcu.h:85
void push_back(UniValue val)
Definition: univalue.cpp:96
@ VOBJ
Definition: univalue.h:31
@ VARR
Definition: univalue.h:32
size_t size() const
Definition: univalue.h:92
const std::vector< UniValue > & getValues() const
void pushKVEnd(std::string key, UniValue val)
Definition: univalue.cpp:108
const UniValue & get_array() const
void pushKV(std::string key, UniValue val)
Definition: univalue.cpp:115
bool get_bool() const
std::string GetRejectReason() const
Definition: validation.h:121
Result GetResult() const
Definition: validation.h:120
std::string ToString() const
Definition: uint256.h:80
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:30
std::string u8string() const
Definition: fs.h:72
@ TX_MISSING_INPUTS
transaction was missing some of its inputs
bool DecodeHexTx(CMutableTransaction &tx, const std::string &strHexTx)
Definition: core_read.cpp:197
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: cs_main.cpp:7
TransactionError
Definition: error.h:22
static RPCHelpMan getmempoolinfo()
Definition: mempool.cpp:699
static RPCHelpMan sendrawtransaction()
Definition: mempool.cpp:32
static std::vector< RPCResult > MempoolEntryDescription()
Definition: mempool.cpp:320
void RegisterMempoolRPCCommands(CRPCTable &t)
Register mempool RPC commands.
Definition: mempool.cpp:1002
static RPCHelpMan getrawmempool()
Definition: mempool.cpp:439
static RPCHelpMan getmempoolentry()
Definition: mempool.cpp:650
UniValue MempoolInfoToJSON(const CTxMemPool &pool)
Mempool information to JSON.
Definition: mempool.cpp:681
static RPCHelpMan submitpackage()
Definition: mempool.cpp:780
UniValue MempoolToJSON(const CTxMemPool &pool, bool verbose, bool include_mempool_sequence)
Mempool to JSON.
Definition: mempool.cpp:395
static void entryToJSON(const CTxMemPool &pool, UniValue &info, const CTxMemPoolEntryRef &e) EXCLUSIVE_LOCKS_REQUIRED(pool.cs)
Definition: mempool.cpp:358
static RPCHelpMan testmempoolaccept()
Definition: mempool.cpp:100
static RPCHelpMan getmempooldescendants()
Definition: mempool.cpp:576
static RPCHelpMan getmempoolancestors()
Definition: mempool.cpp:505
static RPCHelpMan savemempool()
Definition: mempool.cpp:740
std::string FormatMoney(const Amount amt)
Do not use these functions to represent or parse monetary amounts to or from JSON but use AmountFromV...
Definition: moneystr.cpp:13
bool DumpMempool(const CTxMemPool &pool, const fs::path &dump_path, FopenFn mockable_fopen_function, bool skip_file_commit)
Definition: init.h:28
TransactionError BroadcastTransaction(const NodeContext &node, const CTransactionRef tx, std::string &err_string, const Amount max_tx_fee, bool relay, bool wait_callback)
Submit a transaction to the mempool and (optionally) relay it to all P2P peers.
Definition: transaction.cpp:37
fs::path MempoolPath(const ArgsManager &argsman)
bool ShouldPersistMempool(const ArgsManager &argsman)
static const CFeeRate DEFAULT_MAX_RAW_TX_FEE_RATE
Maximum fee rate for sendrawtransaction and testmempoolaccept RPC calls.
Definition: transaction.h:33
bool IsChildWithParentsTree(const Package &package)
Context-free check that a package IsChildWithParents() and none of the parents depend on each other (...
Definition: packages.cpp:109
static constexpr uint32_t MAX_PACKAGE_COUNT
Default maximum number of transactions in a package.
Definition: packages.h:15
@ PCKG_POLICY
The package itself is invalid (e.g. too many transactions).
@ PCKG_RESULT_UNSET
Initial value. The package has not yet been rejected.
@ PCKG_MEMPOOL_ERROR
Mempool logic error.
@ PCKG_TX
At least one tx is invalid.
int64_t GetVirtualTransactionSize(int64_t nSize, int64_t nSigChecks, unsigned int bytes_per_sigCheck)
Compute the virtual transaction size (size, or more if sigChecks are too dense).
Definition: policy.cpp:165
static CTransactionRef MakeTransactionRef()
Definition: transaction.h:316
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:315
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:58
@ RPC_MISC_ERROR
General application defined errors std::exception thrown in command handling.
Definition: protocol.h:38
@ RPC_INVALID_PARAMETER
Invalid, missing or duplicate parameter.
Definition: protocol.h:46
@ RPC_DESERIALIZATION_ERROR
Error parsing or validating structure in raw format.
Definition: protocol.h:50
@ RPC_INVALID_ADDRESS_OR_KEY
Invalid address or key.
Definition: protocol.h:42
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition: util.cpp:150
UniValue JSONRPCTransactionError(TransactionError terr, const std::string &err_string)
Definition: util.cpp:333
Amount AmountFromValue(const UniValue &value)
Definition: util.cpp:55
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:167
uint256 ParseHashV(const UniValue &v, std::string strName)
Utilities: convert hex-encoded values (throws error if not hex).
Definition: util.cpp:73
ArgsManager & EnsureAnyArgsman(const std::any &context)
Definition: server_util.cpp:48
CTxMemPool & EnsureAnyMemPool(const std::any &context)
Definition: server_util.cpp:37
NodeContext & EnsureAnyNodeContext(const std::any &context)
Definition: server_util.cpp:21
CTxMemPool & EnsureMemPool(const NodeContext &node)
Definition: server_util.cpp:29
ChainstateManager & EnsureChainman(const NodeContext &node)
Definition: server_util.cpp:52
std::string ToString(const T &t)
Locale-independent version of std::to_string.
Definition: string.h:86
Definition: amount.h:19
static constexpr Amount zero() noexcept
Definition: amount.h:32
static const Currency & get()
Definition: amount.cpp:18
std::string ticker
Definition: amount.h:150
@ MEMPOOL_ENTRY
Valid, transaction was already in the mempool.
@ VALID
Fully validated, valid.
Validation result for package mempool acceptance.
Definition: validation.h:309
PackageValidationState m_state
Definition: validation.h:310
std::map< TxId, MempoolAcceptResult > m_tx_results
Map from txid to finished MempoolAcceptResults.
Definition: validation.h:318
@ STR_HEX
Special type that is a STR with only hex chars.
@ AMOUNT
Special type representing a floating point amount (can be either NUM or STR)
@ OMITTED
The arg is optional for one of two reasons:
@ NO
Required arg.
@ NUM_TIME
Special numeric to denote unix epoch time.
@ OBJ_DYN
Special dictionary with keys that are not literals.
@ STR_HEX
Special string with only hex chars.
@ STR_AMOUNT
Special string to represent a floating point amount.
A TxId is the identifier of a transaction.
Definition: txid.h:14
NodeContext struct containing references to chain state and connection state.
Definition: context.h:43
#define AssertLockNotHeld(cs)
Definition: sync.h:163
#define LOCK(cs)
Definition: sync.h:306
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:357
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:56
constexpr int64_t count_seconds(std::chrono::seconds t)
Definition: time.h:55
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1202
PackageMempoolAcceptResult ProcessNewPackage(Chainstate &active_chainstate, CTxMemPool &pool, const Package &package, bool test_accept)
Validate (and maybe submit) a package to the mempool.
AssertLockHeld(pool.cs)
void SyncWithValidationInterfaceQueue()
This is a synonym for the following, which asserts certain locks are not held: std::promise<void> pro...