Bitcoin ABC  0.29.4
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 <core_io.h>
10 #include <node/context.h>
12 #include <policy/settings.h>
13 #include <primitives/transaction.h>
14 #include <rpc/server.h>
15 #include <rpc/server_util.h>
16 #include <rpc/util.h>
17 #include <txmempool.h>
18 #include <univalue.h>
19 #include <util/fs.h>
20 #include <validation.h>
21 
23 
24 using node::MempoolPath;
25 using node::NodeContext;
27 
28 static std::vector<RPCResult> MempoolEntryDescription() {
29  const auto &ticker = Currency::get().ticker;
30  return {
31  RPCResult{RPCResult::Type::NUM, "size", "transaction size."},
33  "local time transaction entered pool in seconds since 1 Jan "
34  "1970 GMT"},
36  "block height when transaction entered pool"},
38  "fees",
39  "",
40  {{
42  "transaction fee in " + ticker},
44  "transaction fee with fee deltas used for "
45  "mining priority in " +
46  ticker},
47  }}},
48  RPCResult{
50  "depends",
51  "unconfirmed transactions used as inputs for this transaction",
52  {RPCResult{RPCResult::Type::STR_HEX, "transactionid",
53  "parent transaction id"}}},
54  RPCResult{
56  "spentby",
57  "unconfirmed transactions spending outputs from this transaction",
58  {RPCResult{RPCResult::Type::STR_HEX, "transactionid",
59  "child transaction id"}}},
60  RPCResult{RPCResult::Type::BOOL, "unbroadcast",
61  "Whether this transaction is currently unbroadcast (initial "
62  "broadcast not yet acknowledged by any peers)"},
63  };
64 }
65 
66 static void entryToJSON(const CTxMemPool &pool, UniValue &info,
67  const CTxMemPoolEntryRef &e)
68  EXCLUSIVE_LOCKS_REQUIRED(pool.cs) {
69  AssertLockHeld(pool.cs);
70 
72  fees.pushKV("base", e->GetFee());
73  fees.pushKV("modified", e->GetModifiedFee());
74  info.pushKV("fees", fees);
75 
76  info.pushKV("size", (int)e->GetTxSize());
77  info.pushKV("time", count_seconds(e->GetTime()));
78  info.pushKV("height", (int)e->GetHeight());
79  const CTransaction &tx = e->GetTx();
80  std::set<std::string> setDepends;
81  for (const CTxIn &txin : tx.vin) {
82  if (pool.exists(txin.prevout.GetTxId())) {
83  setDepends.insert(txin.prevout.GetTxId().ToString());
84  }
85  }
86 
87  UniValue depends(UniValue::VARR);
88  for (const std::string &dep : setDepends) {
89  depends.push_back(dep);
90  }
91 
92  info.pushKV("depends", depends);
93 
94  UniValue spent(UniValue::VARR);
95  for (const auto &child : e->GetMemPoolChildrenConst()) {
96  spent.push_back(child.get()->GetTx().GetId().ToString());
97  }
98 
99  info.pushKV("spentby", spent);
100  info.pushKV("unbroadcast", pool.IsUnbroadcastTx(tx.GetId()));
101 }
102 
103 UniValue MempoolToJSON(const CTxMemPool &pool, bool verbose,
104  bool include_mempool_sequence) {
105  if (verbose) {
106  if (include_mempool_sequence) {
107  throw JSONRPCError(
109  "Verbose results cannot contain mempool sequence values.");
110  }
111  LOCK(pool.cs);
113  for (const CTxMemPoolEntryRef &e : pool.mapTx) {
114  const TxId &txid = e->GetTx().GetId();
115  UniValue info(UniValue::VOBJ);
116  entryToJSON(pool, info, e);
117  // Mempool has unique entries so there is no advantage in using
118  // UniValue::pushKV, which checks if the key already exists in O(N).
119  // UniValue::__pushKV is used instead which currently is O(1).
120  o.__pushKV(txid.ToString(), info);
121  }
122  return o;
123  } else {
124  uint64_t mempool_sequence;
125  std::vector<TxId> vtxids;
126  {
127  LOCK(pool.cs);
128  pool.getAllTxIds(vtxids);
129  mempool_sequence = pool.GetSequence();
130  }
132  for (const TxId &txid : vtxids) {
133  a.push_back(txid.ToString());
134  }
135 
136  if (!include_mempool_sequence) {
137  return a;
138  } else {
140  o.pushKV("txids", a);
141  o.pushKV("mempool_sequence", mempool_sequence);
142  return o;
143  }
144  }
145 }
146 
148  return RPCHelpMan{
149  "getrawmempool",
150  "Returns all transaction ids in memory pool as a json array of "
151  "string transaction ids.\n"
152  "\nHint: use getmempoolentry to fetch a specific transaction from the "
153  "mempool.\n",
154  {
155  {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false},
156  "True for a json object, false for array of transaction ids"},
157  {"mempool_sequence", RPCArg::Type::BOOL, RPCArg::Default{false},
158  "If verbose=false, returns a json object with transaction list "
159  "and mempool sequence number attached."},
160  },
161  {
162  RPCResult{"for verbose = false",
164  "",
165  "",
166  {
167  {RPCResult::Type::STR_HEX, "", "The transaction id"},
168  }},
169  RPCResult{"for verbose = true",
171  "",
172  "",
173  {
174  {RPCResult::Type::OBJ, "transactionid", "",
176  }},
177  RPCResult{
178  "for verbose = false and mempool_sequence = true",
180  "",
181  "",
182  {
184  "txids",
185  "",
186  {
187  {RPCResult::Type::STR_HEX, "", "The transaction id"},
188  }},
189  {RPCResult::Type::NUM, "mempool_sequence",
190  "The mempool sequence value."},
191  }},
192  },
193  RPCExamples{HelpExampleCli("getrawmempool", "true") +
194  HelpExampleRpc("getrawmempool", "true")},
195  [&](const RPCHelpMan &self, const Config &config,
196  const JSONRPCRequest &request) -> UniValue {
197  bool fVerbose = false;
198  if (!request.params[0].isNull()) {
199  fVerbose = request.params[0].get_bool();
200  }
201 
202  bool include_mempool_sequence = false;
203  if (!request.params[1].isNull()) {
204  include_mempool_sequence = request.params[1].get_bool();
205  }
206 
207  return MempoolToJSON(EnsureAnyMemPool(request.context), fVerbose,
208  include_mempool_sequence);
209  },
210  };
211 }
212 
214  return RPCHelpMan{
215  "getmempoolancestors",
216  "If txid is in the mempool, returns all in-mempool ancestors.\n",
217  {
219  "The transaction id (must be in mempool)"},
220  {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false},
221  "True for a json object, false for array of transaction ids"},
222  },
223  {
224  RPCResult{
225  "for verbose = false",
227  "",
228  "",
230  "The transaction id of an in-mempool ancestor transaction"}}},
231  RPCResult{"for verbose = true",
233  "",
234  "",
235  {
236  {RPCResult::Type::OBJ, "transactionid", "",
238  }},
239  },
240  RPCExamples{HelpExampleCli("getmempoolancestors", "\"mytxid\"") +
241  HelpExampleRpc("getmempoolancestors", "\"mytxid\"")},
242  [&](const RPCHelpMan &self, const Config &config,
243  const JSONRPCRequest &request) -> UniValue {
244  bool fVerbose = false;
245  if (!request.params[1].isNull()) {
246  fVerbose = request.params[1].get_bool();
247  }
248 
249  TxId txid(ParseHashV(request.params[0], "parameter 1"));
250 
251  const CTxMemPool &mempool = EnsureAnyMemPool(request.context);
252  LOCK(mempool.cs);
253 
254  CTxMemPool::txiter it = mempool.mapTx.find(txid);
255  if (it == mempool.mapTx.end()) {
257  "Transaction not in mempool");
258  }
259 
260  CTxMemPool::setEntries setAncestors;
261  mempool.CalculateMemPoolAncestors(*it, setAncestors, false);
262 
263  if (!fVerbose) {
265  for (CTxMemPool::txiter ancestorIt : setAncestors) {
266  o.push_back((*ancestorIt)->GetTx().GetId().ToString());
267  }
268  return o;
269  } else {
271  for (CTxMemPool::txiter ancestorIt : setAncestors) {
272  const CTxMemPoolEntryRef &e = *ancestorIt;
273  const TxId &_txid = e->GetTx().GetId();
274  UniValue info(UniValue::VOBJ);
275  entryToJSON(mempool, info, e);
276  o.pushKV(_txid.ToString(), info);
277  }
278  return o;
279  }
280  },
281  };
282 }
283 
285  return RPCHelpMan{
286  "getmempooldescendants",
287  "If txid is in the mempool, returns all in-mempool descendants.\n",
288  {
290  "The transaction id (must be in mempool)"},
291  {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false},
292  "True for a json object, false for array of transaction ids"},
293  },
294  {
295  RPCResult{"for verbose = false",
297  "",
298  "",
300  "The transaction id of an in-mempool descendant "
301  "transaction"}}},
302  RPCResult{"for verbose = true",
304  "",
305  "",
306  {
307  {RPCResult::Type::OBJ, "transactionid", "",
309  }},
310  },
311  RPCExamples{HelpExampleCli("getmempooldescendants", "\"mytxid\"") +
312  HelpExampleRpc("getmempooldescendants", "\"mytxid\"")},
313  [&](const RPCHelpMan &self, const Config &config,
314  const JSONRPCRequest &request) -> UniValue {
315  bool fVerbose = false;
316  if (!request.params[1].isNull()) {
317  fVerbose = request.params[1].get_bool();
318  }
319 
320  TxId txid(ParseHashV(request.params[0], "parameter 1"));
321 
322  const CTxMemPool &mempool = EnsureAnyMemPool(request.context);
323  LOCK(mempool.cs);
324 
325  CTxMemPool::txiter it = mempool.mapTx.find(txid);
326  if (it == mempool.mapTx.end()) {
328  "Transaction not in mempool");
329  }
330 
331  CTxMemPool::setEntries setDescendants;
332  mempool.CalculateDescendants(it, setDescendants);
333  // CTxMemPool::CalculateDescendants will include the given tx
334  setDescendants.erase(it);
335 
336  if (!fVerbose) {
338  for (CTxMemPool::txiter descendantIt : setDescendants) {
339  o.push_back((*descendantIt)->GetTx().GetId().ToString());
340  }
341 
342  return o;
343  } else {
345  for (CTxMemPool::txiter descendantIt : setDescendants) {
346  const CTxMemPoolEntryRef &e = *descendantIt;
347  const TxId &_txid = e->GetTx().GetId();
348  UniValue info(UniValue::VOBJ);
349  entryToJSON(mempool, info, e);
350  o.pushKV(_txid.ToString(), info);
351  }
352  return o;
353  }
354  },
355  };
356 }
357 
359  return RPCHelpMan{
360  "getmempoolentry",
361  "Returns mempool data for given transaction\n",
362  {
364  "The transaction id (must be in mempool)"},
365  },
367  RPCExamples{HelpExampleCli("getmempoolentry", "\"mytxid\"") +
368  HelpExampleRpc("getmempoolentry", "\"mytxid\"")},
369  [&](const RPCHelpMan &self, const Config &config,
370  const JSONRPCRequest &request) -> UniValue {
371  TxId txid(ParseHashV(request.params[0], "parameter 1"));
372 
373  const CTxMemPool &mempool = EnsureAnyMemPool(request.context);
374  LOCK(mempool.cs);
375 
376  CTxMemPool::txiter it = mempool.mapTx.find(txid);
377  if (it == mempool.mapTx.end()) {
379  "Transaction not in mempool");
380  }
381 
382  UniValue info(UniValue::VOBJ);
383  entryToJSON(mempool, info, *it);
384  return info;
385  },
386  };
387 }
388 
390  // Make sure this call is atomic in the pool.
391  LOCK(pool.cs);
393  ret.pushKV("loaded", pool.GetLoadTried());
394  ret.pushKV("size", (int64_t)pool.size());
395  ret.pushKV("bytes", (int64_t)pool.GetTotalTxSize());
396  ret.pushKV("usage", (int64_t)pool.DynamicMemoryUsage());
397  ret.pushKV("total_fee", pool.GetTotalFee());
398  ret.pushKV("maxmempool", pool.m_max_size_bytes);
399  ret.pushKV(
400  "mempoolminfee",
401  std::max(pool.GetMinFee(), pool.m_min_relay_feerate).GetFeePerK());
402  ret.pushKV("minrelaytxfee", pool.m_min_relay_feerate.GetFeePerK());
403  ret.pushKV("unbroadcastcount", uint64_t{pool.GetUnbroadcastTxs().size()});
404  return ret;
405 }
406 
408  const auto &ticker = Currency::get().ticker;
409  return RPCHelpMan{
410  "getmempoolinfo",
411  "Returns details on the active state of the TX memory pool.\n",
412  {},
413  RPCResult{
415  "",
416  "",
417  {
418  {RPCResult::Type::BOOL, "loaded",
419  "True if the mempool is fully loaded"},
420  {RPCResult::Type::NUM, "size", "Current tx count"},
421  {RPCResult::Type::NUM, "bytes", "Sum of all transaction sizes"},
422  {RPCResult::Type::NUM, "usage",
423  "Total memory usage for the mempool"},
424  {RPCResult::Type::NUM, "maxmempool",
425  "Maximum memory usage for the mempool"},
426  {RPCResult::Type::STR_AMOUNT, "total_fee",
427  "Total fees for the mempool in " + ticker +
428  ", ignoring modified fees through prioritizetransaction"},
429  {RPCResult::Type::STR_AMOUNT, "mempoolminfee",
430  "Minimum fee rate in " + ticker +
431  "/kB for tx to be accepted. Is the maximum of "
432  "minrelaytxfee and minimum mempool fee"},
433  {RPCResult::Type::STR_AMOUNT, "minrelaytxfee",
434  "Current minimum relay fee for transactions"},
435  {RPCResult::Type::NUM, "unbroadcastcount",
436  "Current number of transactions that haven't passed initial "
437  "broadcast yet"},
438  }},
439  RPCExamples{HelpExampleCli("getmempoolinfo", "") +
440  HelpExampleRpc("getmempoolinfo", "")},
441  [&](const RPCHelpMan &self, const Config &config,
442  const JSONRPCRequest &request) -> UniValue {
443  return MempoolInfoToJSON(EnsureAnyMemPool(request.context));
444  },
445  };
446 }
447 
449  return RPCHelpMan{
450  "savemempool",
451  "Dumps the mempool to disk. It will fail until the previous dump is "
452  "fully loaded.\n",
453  {},
455  "",
456  "",
457  {
458  {RPCResult::Type::STR, "filename",
459  "the directory and file where the mempool was saved"},
460  }},
461  RPCExamples{HelpExampleCli("savemempool", "") +
462  HelpExampleRpc("savemempool", "")},
463  [&](const RPCHelpMan &self, const Config &config,
464  const JSONRPCRequest &request) -> UniValue {
465  const ArgsManager &args{EnsureAnyArgsman(request.context)};
466  const CTxMemPool &mempool = EnsureAnyMemPool(request.context);
467 
468  if (!mempool.GetLoadTried()) {
470  "The mempool was not loaded yet");
471  }
472 
473  const fs::path &dump_path = MempoolPath(args);
474 
475  if (!DumpMempool(mempool, dump_path)) {
477  "Unable to dump mempool to disk");
478  }
479 
481  ret.pushKV("filename", dump_path.u8string());
482 
483  return ret;
484  },
485  };
486 }
487 
489  static const CRPCCommand commands[]{
490  // category actor (function)
491  // -------- ----------------
492  {"blockchain", getmempoolancestors},
493  {"blockchain", getmempooldescendants},
494  {"blockchain", getmempoolentry},
495  {"blockchain", getmempoolinfo},
496  {"blockchain", getrawmempool},
497  {"blockchain", savemempool},
498  };
499  for (const auto &c : commands) {
500  t.appendCommand(c.name, &c);
501  }
502 }
Amount GetFeePerK() const
Return the fee in satoshis for a size of 1000 bytes.
Definition: feerate.h:54
const TxId & GetTxId() const
Definition: transaction.h:35
RPC command dispatcher.
Definition: server.h:184
void appendCommand(const std::string &name, const CRPCCommand *pcmd)
Appends a CRPCCommand to the dispatch table.
Definition: server.cpp:332
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:802
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:637
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
Definition: config.h:19
Definition: rcu.h:85
@ VOBJ
Definition: univalue.h:27
@ VARR
Definition: univalue.h:27
void __pushKV(const std::string &key, const UniValue &val)
Definition: univalue.cpp:127
bool push_back(const UniValue &val)
Definition: univalue.cpp:108
bool pushKV(const std::string &key, const UniValue &val)
Definition: univalue.cpp:133
bool get_bool() const
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
static std::vector< RPCResult > MempoolEntryDescription()
Definition: mempool.cpp:28
RPCHelpMan getmempoolinfo()
Definition: mempool.cpp:407
void RegisterMempoolRPCCommands(CRPCTable &t)
Register mempool RPC commands.
Definition: mempool.cpp:488
RPCHelpMan savemempool()
Definition: mempool.cpp:448
UniValue MempoolInfoToJSON(const CTxMemPool &pool)
Mempool information to JSON.
Definition: mempool.cpp:389
RPCHelpMan getmempooldescendants()
Definition: mempool.cpp:284
UniValue MempoolToJSON(const CTxMemPool &pool, bool verbose, bool include_mempool_sequence)
Mempool to JSON.
Definition: mempool.cpp:103
static void entryToJSON(const CTxMemPool &pool, UniValue &info, const CTxMemPoolEntryRef &e) EXCLUSIVE_LOCKS_REQUIRED(pool.cs)
Definition: mempool.cpp:66
RPCHelpMan getmempoolancestors()
Definition: mempool.cpp:213
RPCHelpMan getmempoolentry()
Definition: mempool.cpp:358
RPCHelpMan getrawmempool()
Definition: mempool.cpp:147
bool DumpMempool(const CTxMemPool &pool, const fs::path &dump_path, FopenFn mockable_fopen_function, bool skip_file_commit)
fs::path MempoolPath(const ArgsManager &argsman)
bool ShouldPersistMempool(const ArgsManager &argsman)
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_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:176
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:193
uint256 ParseHashV(const UniValue &v, std::string strName)
Utilities: convert hex-encoded values (throws error if not hex).
Definition: util.cpp:99
ArgsManager & EnsureAnyArgsman(const std::any &context)
Definition: server_util.cpp:47
CTxMemPool & EnsureAnyMemPool(const std::any &context)
Definition: server_util.cpp:36
static const Currency & get()
Definition: amount.cpp:18
std::string ticker
Definition: amount.h:150
@ STR_HEX
Special type that is a STR with only hex chars.
@ 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:40
#define LOCK(cs)
Definition: sync.h:306
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:56
constexpr int64_t count_seconds(std::chrono::seconds t)
Definition: time.h:55
AssertLockHeld(pool.cs)