Bitcoin ABC 0.32.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
8
9#include <chainparams.h>
10#include <core_io.h>
11#include <node/context.h>
13#include <policy/settings.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
30
32 return RPCHelpMan{
33 "sendrawtransaction",
34 "Submits raw transaction (serialized, hex-encoded) to local node and "
35 "network.\n"
36 "\nAlso see createrawtransaction and "
37 "signrawtransactionwithkey calls.\n",
38 {
40 "The hex string of the raw transaction"},
41 {"maxfeerate", RPCArg::Type::AMOUNT,
44 "Reject transactions whose fee rate is higher than the specified "
45 "value, expressed in " +
47 "/kB\nSet to 0 to accept any fee rate.\n"},
48 },
49 RPCResult{RPCResult::Type::STR_HEX, "", "The transaction hash in hex"},
51 "\nCreate a transaction\n" +
53 "createrawtransaction",
54 "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" "
55 "\"{\\\"myaddress\\\":10000}\"") +
56 "Sign the transaction, and get back the hex\n" +
57 HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") +
58 "\nSend the transaction (signed hex)\n" +
59 HelpExampleCli("sendrawtransaction", "\"signedhex\"") +
60 "\nAs a JSON-RPC call\n" +
61 HelpExampleRpc("sendrawtransaction", "\"signedhex\"")},
62 [&](const RPCHelpMan &self, const Config &config,
63 const JSONRPCRequest &request) -> UniValue {
64 // parse hex string from parameter
66 if (!DecodeHexTx(mtx, request.params[0].get_str())) {
68 "TX decode failed");
69 }
70
71 CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
72
73 const CFeeRate max_raw_tx_fee_rate =
74 request.params[1].isNull()
76 : CFeeRate(AmountFromValue(request.params[1]));
77
78 int64_t virtual_size = GetVirtualTransactionSize(*tx);
79 Amount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size);
80
81 std::string err_string;
83 NodeContext &node = EnsureAnyNodeContext(request.context);
85 node, tx, err_string, max_raw_tx_fee, /*relay*/ true,
86 /*wait_callback*/ true);
87 if (err != TransactionError::OK) {
88 throw JSONRPCTransactionError(err, err_string);
89 }
90
91 // Block to make sure wallet/indexers sync before returning
93
94 return tx->GetHash().GetHex();
95 },
96 };
97}
98
100 const auto ticker = Currency::get().ticker;
101 return RPCHelpMan{
102 "testmempoolaccept",
103 "\nReturns result of mempool acceptance tests indicating if raw "
104 "transaction(s) (serialized, hex-encoded) would be accepted by "
105 "mempool.\n"
106 "\nIf multiple transactions are passed in, parents must come before "
107 "children and package policies apply: the transactions cannot conflict "
108 "with any mempool transactions or each other.\n"
109 "\nIf one transaction fails, other transactions may not be fully "
110 "validated (the 'allowed' key will be blank).\n"
111 "\nThe maximum number of transactions allowed is " +
113 ".\n"
114 "\nThis checks if transactions violate the consensus or policy "
115 "rules.\n"
116 "\nSee sendrawtransaction call.\n",
117 {
118 {
119 "rawtxs",
122 "An array of hex strings of raw transactions.",
123 {
125 ""},
126 },
127 },
128 {"maxfeerate", RPCArg::Type::AMOUNT,
131 "Reject transactions whose fee rate is higher than the specified "
132 "value, expressed in " +
133 ticker + "/kB\n"},
134 },
135 RPCResult{
137 "",
138 "The result of the mempool acceptance test for each raw "
139 "transaction in the input array.\n"
140 "Returns results for each transaction in the same order they were "
141 "passed in.\n"
142 "Transactions that cannot be fully validated due to failures in "
143 "other transactions will not contain an 'allowed' result.\n",
144 {
146 "",
147 "",
148 {
150 "The transaction hash in hex"},
151 {RPCResult::Type::STR, "package-error",
152 "Package validation error, if any (only possible if "
153 "rawtxs had more than 1 transaction)."},
154 {RPCResult::Type::BOOL, "allowed",
155 "Whether this tx would be accepted to the mempool and "
156 "pass client-specified maxfeerate. "
157 "If not present, the tx was not fully validated due to a "
158 "failure in another tx in the list."},
159 {RPCResult::Type::NUM, "size", "The transaction size"},
161 "fees",
162 "Transaction fees (only present if 'allowed' is true)",
163 {
165 "transaction fee in " + ticker},
166 {RPCResult::Type::STR_AMOUNT, "effective-feerate",
167 "the effective feerate in " + ticker +
168 " per KvB. May differ from the base feerate if, "
169 "for example, there are modified fees from "
170 "prioritisetransaction or a package feerate was "
171 "used."},
173 "effective-includes",
174 "transactions whose fees and vsizes are included in "
175 "effective-feerate.",
176 {
178 "transaction txid in hex"},
179 }},
180 }},
181 {RPCResult::Type::STR, "reject-reason", /*optional=*/true,
182 "Rejection string (only present when 'allowed' is "
183 "false)"},
184 {RPCResult::Type::STR, "reject-details", /*optional=*/true,
185 "Rejection details (only present when 'allowed' is false "
186 "and rejection details exist)"},
187
188 }},
189 }},
191 "\nCreate a transaction\n" +
193 "createrawtransaction",
194 "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" "
195 "\"{\\\"myaddress\\\":10000}\"") +
196 "Sign the transaction, and get back the hex\n" +
197 HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") +
198 "\nTest acceptance of the transaction (signed hex)\n" +
199 HelpExampleCli("testmempoolaccept", R"('["signedhex"]')") +
200 "\nAs a JSON-RPC call\n" +
201 HelpExampleRpc("testmempoolaccept", "[\"signedhex\"]")},
202 [&](const RPCHelpMan &self, const Config &config,
203 const JSONRPCRequest &request) -> UniValue {
204 const UniValue raw_transactions = request.params[0].get_array();
205 if (raw_transactions.size() < 1 ||
206 raw_transactions.size() > MAX_PACKAGE_COUNT) {
208 "Array must contain between 1 and " +
210 " transactions.");
211 }
212
213 const CFeeRate max_raw_tx_fee_rate =
214 request.params[1].isNull()
216 : CFeeRate(AmountFromValue(request.params[1]));
217
218 std::vector<CTransactionRef> txns;
219 txns.reserve(raw_transactions.size());
220 for (const auto &rawtx : raw_transactions.getValues()) {
222 if (!DecodeHexTx(mtx, rawtx.get_str())) {
224 "TX decode failed: " + rawtx.get_str());
225 }
226 txns.emplace_back(MakeTransactionRef(std::move(mtx)));
227 }
228
229 NodeContext &node = EnsureAnyNodeContext(request.context);
230 CTxMemPool &mempool = EnsureMemPool(node);
232 Chainstate &chainstate = chainman.ActiveChainstate();
233 const PackageMempoolAcceptResult package_result = [&] {
235 if (txns.size() > 1) {
236 return ProcessNewPackage(chainstate, mempool, txns,
237 /* test_accept */ true);
238 }
240 txns[0]->GetId(),
241 chainman.ProcessTransaction(txns[0],
242 /* test_accept*/ true));
243 }();
244
245 UniValue rpc_result(UniValue::VARR);
246 // We will check transaction fees while we iterate through txns in
247 // order. If any transaction fee exceeds maxfeerate, we will leave
248 // the rest of the validation results blank, because it doesn't make
249 // sense to return a validation result for a transaction if its
250 // ancestor(s) would not be submitted.
251 bool exit_early{false};
252 for (const auto &tx : txns) {
253 UniValue result_inner(UniValue::VOBJ);
254 result_inner.pushKV("txid", tx->GetId().GetHex());
255 if (package_result.m_state.GetResult() ==
257 result_inner.pushKV(
258 "package-error",
259 package_result.m_state.GetRejectReason());
260 }
261 auto it = package_result.m_tx_results.find(tx->GetId());
262 if (exit_early || it == package_result.m_tx_results.end()) {
263 // Validation unfinished. Just return the txid.
264 rpc_result.push_back(result_inner);
265 continue;
266 }
267 const auto &tx_result = it->second;
268 // Package testmempoolaccept doesn't allow transactions to
269 // already be in the mempool.
270 CHECK_NONFATAL(tx_result.m_result_type !=
272 if (tx_result.m_result_type ==
274 const Amount fee = tx_result.m_base_fees.value();
275 // Check that fee does not exceed maximum fee
276 const int64_t virtual_size = tx_result.m_vsize.value();
277 const Amount max_raw_tx_fee =
278 max_raw_tx_fee_rate.GetFee(virtual_size);
279 if (max_raw_tx_fee != Amount::zero() &&
280 fee > max_raw_tx_fee) {
281 result_inner.pushKV("allowed", false);
282 result_inner.pushKV("reject-reason",
283 "max-fee-exceeded");
284 exit_early = true;
285 } else {
286 // Only return the fee and size if the transaction
287 // would pass ATMP.
288 // These can be used to calculate the feerate.
289 result_inner.pushKV("allowed", true);
290 result_inner.pushKV("size", virtual_size);
292 fees.pushKV("base", fee);
293 fees.pushKV(
294 "effective-feerate",
295 tx_result.m_effective_feerate.value().GetFeePerK());
296 UniValue effective_includes_res(UniValue::VARR);
297 for (const auto &txid :
298 tx_result.m_txids_fee_calculations.value()) {
299 effective_includes_res.push_back(txid.ToString());
300 }
301 fees.pushKV("effective-includes",
302 effective_includes_res);
303 result_inner.pushKV("fees", fees);
304 }
305 } else {
306 result_inner.pushKV("allowed", false);
307 const TxValidationState state = tx_result.m_state;
308 if (state.GetResult() ==
310 result_inner.pushKV("reject-reason", "missing-inputs");
311 } else {
312 result_inner.pushKV("reject-reason",
313 state.GetRejectReason());
314 result_inner.pushKV("reject-details", state.ToString());
315 }
316 }
317 rpc_result.push_back(result_inner);
318 }
319 return rpc_result;
320 },
321 };
322}
323
324static std::vector<RPCResult> MempoolEntryDescription() {
325 const auto &ticker = Currency::get().ticker;
326 return {
327 RPCResult{RPCResult::Type::NUM, "size", "transaction size."},
329 "local time transaction entered pool in seconds since 1 Jan "
330 "1970 GMT"},
332 "block height when transaction entered pool"},
334 "fees",
335 "",
336 {{
338 "transaction fee in " + ticker},
340 "transaction fee with fee deltas used for "
341 "mining priority in " +
342 ticker},
343 }}},
344 RPCResult{
346 "depends",
347 "unconfirmed transactions used as inputs for this transaction",
348 {RPCResult{RPCResult::Type::STR_HEX, "transactionid",
349 "parent transaction id"}}},
350 RPCResult{
352 "spentby",
353 "unconfirmed transactions spending outputs from this transaction",
354 {RPCResult{RPCResult::Type::STR_HEX, "transactionid",
355 "child transaction id"}}},
356 RPCResult{RPCResult::Type::BOOL, "unbroadcast",
357 "Whether this transaction is currently unbroadcast (initial "
358 "broadcast not yet acknowledged by any peers)"},
359 };
360}
361
362static void entryToJSON(const CTxMemPool &pool, UniValue &info,
363 const CTxMemPoolEntryRef &e)
364 EXCLUSIVE_LOCKS_REQUIRED(pool.cs) {
365 AssertLockHeld(pool.cs);
366
368 fees.pushKV("base", e->GetFee());
369 fees.pushKV("modified", e->GetModifiedFee());
370 info.pushKV("fees", fees);
371
372 info.pushKV("size", (int)e->GetTxSize());
373 info.pushKV("time", count_seconds(e->GetTime()));
374 info.pushKV("height", (int)e->GetHeight());
375 const CTransaction &tx = e->GetTx();
376 std::set<std::string> setDepends;
377 for (const CTxIn &txin : tx.vin) {
378 if (pool.exists(txin.prevout.GetTxId())) {
379 setDepends.insert(txin.prevout.GetTxId().ToString());
380 }
381 }
382
383 UniValue depends(UniValue::VARR);
384 for (const std::string &dep : setDepends) {
385 depends.push_back(dep);
386 }
387
388 info.pushKV("depends", depends);
389
391 for (const auto &child : e->GetMemPoolChildrenConst()) {
392 spent.push_back(child.get()->GetTx().GetId().ToString());
393 }
394
395 info.pushKV("spentby", spent);
396 info.pushKV("unbroadcast", pool.IsUnbroadcastTx(tx.GetId()));
397}
398
399UniValue MempoolToJSON(const CTxMemPool &pool, bool verbose,
400 bool include_mempool_sequence) {
401 if (verbose) {
402 if (include_mempool_sequence) {
403 throw JSONRPCError(
405 "Verbose results cannot contain mempool sequence values.");
406 }
407 LOCK(pool.cs);
409 for (const CTxMemPoolEntryRef &e : pool.mapTx) {
410 const TxId &txid = e->GetTx().GetId();
412 entryToJSON(pool, info, e);
413 // Mempool has unique entries so there is no advantage in using
414 // UniValue::pushKV, which checks if the key already exists in O(N).
415 // UniValue::pushKVEnd is used instead which currently is O(1).
416 o.pushKVEnd(txid.ToString(), info);
417 }
418 return o;
419 } else {
420 uint64_t mempool_sequence;
421 std::vector<TxId> vtxids;
422 {
423 LOCK(pool.cs);
424 pool.getAllTxIds(vtxids);
425 mempool_sequence = pool.GetSequence();
426 }
428 for (const TxId &txid : vtxids) {
429 a.push_back(txid.ToString());
430 }
431
432 if (!include_mempool_sequence) {
433 return a;
434 } else {
436 o.pushKV("txids", a);
437 o.pushKV("mempool_sequence", mempool_sequence);
438 return o;
439 }
440 }
441}
442
444 return RPCHelpMan{
445 "getrawmempool",
446 "Returns all transaction ids in memory pool as a json array of "
447 "string transaction ids.\n"
448 "\nHint: use getmempoolentry to fetch a specific transaction from the "
449 "mempool.\n",
450 {
451 {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false},
452 "True for a json object, false for array of transaction ids"},
453 {"mempool_sequence", RPCArg::Type::BOOL, RPCArg::Default{false},
454 "If verbose=false, returns a json object with transaction list "
455 "and mempool sequence number attached."},
456 },
457 {
458 RPCResult{"for verbose = false",
460 "",
461 "",
462 {
463 {RPCResult::Type::STR_HEX, "", "The transaction id"},
464 }},
465 RPCResult{"for verbose = true",
467 "",
468 "",
469 {
470 {RPCResult::Type::OBJ, "transactionid", "",
472 }},
473 RPCResult{
474 "for verbose = false and mempool_sequence = true",
476 "",
477 "",
478 {
480 "txids",
481 "",
482 {
483 {RPCResult::Type::STR_HEX, "", "The transaction id"},
484 }},
485 {RPCResult::Type::NUM, "mempool_sequence",
486 "The mempool sequence value."},
487 }},
488 },
489 RPCExamples{HelpExampleCli("getrawmempool", "true") +
490 HelpExampleRpc("getrawmempool", "true")},
491 [&](const RPCHelpMan &self, const Config &config,
492 const JSONRPCRequest &request) -> UniValue {
493 bool fVerbose = false;
494 if (!request.params[0].isNull()) {
495 fVerbose = request.params[0].get_bool();
496 }
497
498 bool include_mempool_sequence = false;
499 if (!request.params[1].isNull()) {
500 include_mempool_sequence = request.params[1].get_bool();
501 }
502
503 return MempoolToJSON(EnsureAnyMemPool(request.context), fVerbose,
504 include_mempool_sequence);
505 },
506 };
507}
508
510 return RPCHelpMan{
511 "getmempoolancestors",
512 "If txid is in the mempool, returns all in-mempool ancestors.\n",
513 {
515 "The transaction id (must be in mempool)"},
516 {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false},
517 "True for a json object, false for array of transaction ids"},
518 },
519 {
520 RPCResult{
521 "for verbose = false",
523 "",
524 "",
526 "The transaction id of an in-mempool ancestor transaction"}}},
527 RPCResult{"for verbose = true",
529 "",
530 "",
531 {
532 {RPCResult::Type::OBJ, "transactionid", "",
534 }},
535 },
536 RPCExamples{HelpExampleCli("getmempoolancestors", "\"mytxid\"") +
537 HelpExampleRpc("getmempoolancestors", "\"mytxid\"")},
538 [&](const RPCHelpMan &self, const Config &config,
539 const JSONRPCRequest &request) -> UniValue {
540 bool fVerbose = false;
541 if (!request.params[1].isNull()) {
542 fVerbose = request.params[1].get_bool();
543 }
544
545 TxId txid(ParseHashV(request.params[0], "parameter 1"));
546
547 const CTxMemPool &mempool = EnsureAnyMemPool(request.context);
548 LOCK(mempool.cs);
549
550 CTxMemPool::txiter it = mempool.mapTx.find(txid);
551 if (it == mempool.mapTx.end()) {
553 "Transaction not in mempool");
554 }
555
556 CTxMemPool::setEntries setAncestors;
557 mempool.CalculateMemPoolAncestors(*it, setAncestors, false);
558
559 if (!fVerbose) {
561 for (CTxMemPool::txiter ancestorIt : setAncestors) {
562 o.push_back((*ancestorIt)->GetTx().GetId().ToString());
563 }
564 return o;
565 } else {
567 for (CTxMemPool::txiter ancestorIt : setAncestors) {
568 const CTxMemPoolEntryRef &e = *ancestorIt;
569 const TxId &_txid = e->GetTx().GetId();
571 entryToJSON(mempool, info, e);
572 o.pushKV(_txid.ToString(), info);
573 }
574 return o;
575 }
576 },
577 };
578}
579
581 return RPCHelpMan{
582 "getmempooldescendants",
583 "If txid is in the mempool, returns all in-mempool descendants.\n",
584 {
586 "The transaction id (must be in mempool)"},
587 {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false},
588 "True for a json object, false for array of transaction ids"},
589 },
590 {
591 RPCResult{"for verbose = false",
593 "",
594 "",
596 "The transaction id of an in-mempool descendant "
597 "transaction"}}},
598 RPCResult{"for verbose = true",
600 "",
601 "",
602 {
603 {RPCResult::Type::OBJ, "transactionid", "",
605 }},
606 },
607 RPCExamples{HelpExampleCli("getmempooldescendants", "\"mytxid\"") +
608 HelpExampleRpc("getmempooldescendants", "\"mytxid\"")},
609 [&](const RPCHelpMan &self, const Config &config,
610 const JSONRPCRequest &request) -> UniValue {
611 bool fVerbose = false;
612 if (!request.params[1].isNull()) {
613 fVerbose = request.params[1].get_bool();
614 }
615
616 TxId txid(ParseHashV(request.params[0], "parameter 1"));
617
618 const CTxMemPool &mempool = EnsureAnyMemPool(request.context);
619 LOCK(mempool.cs);
620
621 CTxMemPool::txiter it = mempool.mapTx.find(txid);
622 if (it == mempool.mapTx.end()) {
624 "Transaction not in mempool");
625 }
626
627 CTxMemPool::setEntries setDescendants;
628 mempool.CalculateDescendants(it, setDescendants);
629 // CTxMemPool::CalculateDescendants will include the given tx
630 setDescendants.erase(it);
631
632 if (!fVerbose) {
634 for (CTxMemPool::txiter descendantIt : setDescendants) {
635 o.push_back((*descendantIt)->GetTx().GetId().ToString());
636 }
637
638 return o;
639 } else {
641 for (CTxMemPool::txiter descendantIt : setDescendants) {
642 const CTxMemPoolEntryRef &e = *descendantIt;
643 const TxId &_txid = e->GetTx().GetId();
645 entryToJSON(mempool, info, e);
646 o.pushKV(_txid.ToString(), info);
647 }
648 return o;
649 }
650 },
651 };
652}
653
655 return RPCHelpMan{
656 "getmempoolentry",
657 "Returns mempool data for given transaction\n",
658 {
660 "The transaction id (must be in mempool)"},
661 },
663 RPCExamples{HelpExampleCli("getmempoolentry", "\"mytxid\"") +
664 HelpExampleRpc("getmempoolentry", "\"mytxid\"")},
665 [&](const RPCHelpMan &self, const Config &config,
666 const JSONRPCRequest &request) -> UniValue {
667 TxId txid(ParseHashV(request.params[0], "parameter 1"));
668
669 const CTxMemPool &mempool = EnsureAnyMemPool(request.context);
670 LOCK(mempool.cs);
671
672 CTxMemPool::txiter it = mempool.mapTx.find(txid);
673 if (it == mempool.mapTx.end()) {
675 "Transaction not in mempool");
676 }
677
679 entryToJSON(mempool, info, *it);
680 return info;
681 },
682 };
683}
684
686 // Make sure this call is atomic in the pool.
687 LOCK(pool.cs);
689 ret.pushKV("loaded", pool.GetLoadTried());
690 ret.pushKV("size", (int64_t)pool.size());
691 ret.pushKV("bytes", (int64_t)pool.GetTotalTxSize());
692 ret.pushKV("finalized_txs_bytes", (int64_t)pool.GetTotalFinalizedTxSize());
693 ret.pushKV("finalized_txs_sigchecks",
694 (int64_t)pool.GetTotalFinalizedTxSigchecks());
695 ret.pushKV("usage", (int64_t)pool.DynamicMemoryUsage());
696 ret.pushKV("total_fee", pool.GetTotalFee());
697 ret.pushKV("maxmempool", pool.m_max_size_bytes);
698 ret.pushKV(
699 "mempoolminfee",
700 std::max(pool.GetMinFee(), pool.m_min_relay_feerate).GetFeePerK());
701 ret.pushKV("minrelaytxfee", pool.m_min_relay_feerate.GetFeePerK());
702 ret.pushKV("unbroadcastcount", uint64_t{pool.GetUnbroadcastTxs().size()});
703 return ret;
704}
705
707 const auto &ticker = Currency::get().ticker;
708 return RPCHelpMan{
709 "getmempoolinfo",
710 "Returns details on the active state of the TX memory pool.\n",
711 {},
712 RPCResult{
714 "",
715 "",
716 {
717 {RPCResult::Type::BOOL, "loaded",
718 "True if the mempool is fully loaded"},
719 {RPCResult::Type::NUM, "size", "Current tx count"},
720 {RPCResult::Type::NUM, "bytes", "Sum of all transaction sizes"},
721 {RPCResult::Type::NUM, "finalized_txs_bytes",
722 "Sum of all finalized transaction sizes"},
723 {RPCResult::Type::NUM, "finalized_txs_sigchecks",
724 "Sum of all finalized transaction sigchecks"},
725 {RPCResult::Type::NUM, "usage",
726 "Total memory usage for the mempool"},
727 {RPCResult::Type::NUM, "maxmempool",
728 "Maximum memory usage for the mempool"},
729 {RPCResult::Type::STR_AMOUNT, "total_fee",
730 "Total fees for the mempool in " + ticker +
731 ", ignoring modified fees through prioritizetransaction"},
732 {RPCResult::Type::STR_AMOUNT, "mempoolminfee",
733 "Minimum fee rate in " + ticker +
734 "/kB for tx to be accepted. Is the maximum of "
735 "minrelaytxfee and minimum mempool fee"},
736 {RPCResult::Type::STR_AMOUNT, "minrelaytxfee",
737 "Current minimum relay fee for transactions"},
738 {RPCResult::Type::NUM, "unbroadcastcount",
739 "Current number of transactions that haven't passed initial "
740 "broadcast yet"},
741 }},
742 RPCExamples{HelpExampleCli("getmempoolinfo", "") +
743 HelpExampleRpc("getmempoolinfo", "")},
744 [&](const RPCHelpMan &self, const Config &config,
745 const JSONRPCRequest &request) -> UniValue {
746 return MempoolInfoToJSON(EnsureAnyMemPool(request.context));
747 },
748 };
749}
750
752 return RPCHelpMan{
753 "savemempool",
754 "Dumps the mempool to disk. It will fail until the previous dump is "
755 "fully loaded.\n",
756 {},
758 "",
759 "",
760 {
761 {RPCResult::Type::STR, "filename",
762 "the directory and file where the mempool was saved"},
763 }},
764 RPCExamples{HelpExampleCli("savemempool", "") +
765 HelpExampleRpc("savemempool", "")},
766 [&](const RPCHelpMan &self, const Config &config,
767 const JSONRPCRequest &request) -> UniValue {
768 const ArgsManager &args{EnsureAnyArgsman(request.context)};
769 const CTxMemPool &mempool = EnsureAnyMemPool(request.context);
770
771 if (!mempool.GetLoadTried()) {
773 "The mempool was not loaded yet");
774 }
775
776 const fs::path &dump_path = MempoolPath(args);
777
778 if (!DumpMempool(mempool, dump_path)) {
780 "Unable to dump mempool to disk");
781 }
782
784 ret.pushKV("filename", dump_path.u8string());
785
786 return ret;
787 },
788 };
789}
790
792 const auto &ticker = Currency::get().ticker;
793 return RPCHelpMan{
794 "submitpackage",
795 "Submit a package of raw transactions (serialized, hex-encoded) to "
796 "local node.\n"
797 "The package must consist of a child with its parents, and none of the "
798 "parents may depend on one another.\n"
799 "The package will be validated according to consensus and mempool "
800 "policy rules. If any transaction passes, it will be accepted to "
801 "mempool.\n"
802 "This RPC is experimental and the interface may be unstable. Refer to "
803 "doc/policy/packages.md for documentation on package policies.\n"
804 "Warning: successful submission does not mean the transactions will "
805 "propagate throughout the network.\n",
806 {
807 {
808 "package",
811 "An array of raw transactions.",
812 {
814 ""},
815 },
816 },
817 },
818 RPCResult{
820 "",
821 "",
822 {
823 {RPCResult::Type::STR, "package_msg",
824 "The transaction package result message. \"success\" "
825 "indicates all transactions were accepted into or are already "
826 "in the mempool."},
828 "tx-results",
829 "transaction results keyed by txid",
831 "txid",
832 "transaction txid",
833 {
834 {RPCResult::Type::NUM, "vsize", /*optional=*/true,
835 "Virtual transaction size."},
837 "fees",
838 /*optional=*/true,
839 "Transaction fees",
840 {
842 "transaction fee in " + ticker},
843 {RPCResult::Type::STR_AMOUNT, "effective-feerate",
844 "the effective feerate in " + ticker +
845 " per KvB. May differ from the base feerate "
846 "if, for example, there are modified fees "
847 "from prioritisetransaction or a package "
848 "feerate was used."},
850 "effective-includes",
851 "transactions whose fees and vsizes are included "
852 "in effective-feerate.",
853 {
855 "transaction txid in hex"},
856 }},
857 }},
858 {RPCResult::Type::STR, "error", /*optional=*/true,
859 "The transaction error string, if it was rejected by "
860 "the mempool"},
861 }}}},
862 },
863 },
864 RPCExamples{HelpExampleCli("testmempoolaccept", "[rawtx1, rawtx2]") +
865 HelpExampleCli("submitpackage", "[rawtx1, rawtx2]")},
866 [&](const RPCHelpMan &self, const Config &config,
867 const JSONRPCRequest &request) -> UniValue {
868 const UniValue raw_transactions = request.params[0].get_array();
869 if (raw_transactions.size() < 1 ||
870 raw_transactions.size() > MAX_PACKAGE_COUNT) {
872 "Array must contain between 1 and " +
874 " transactions.");
875 }
876
877 std::vector<CTransactionRef> txns;
878 txns.reserve(raw_transactions.size());
879 for (const auto &rawtx : raw_transactions.getValues()) {
881 if (!DecodeHexTx(mtx, rawtx.get_str())) {
882 throw JSONRPCError(
884 "TX decode failed: " + rawtx.get_str() +
885 " Make sure the tx has at least one input.");
886 }
887 txns.emplace_back(MakeTransactionRef(std::move(mtx)));
888 }
889 if (!IsChildWithParentsTree(txns)) {
892 "package topology disallowed. not child-with-parents or "
893 "parents depend on each other.");
894 }
895
896 NodeContext &node = EnsureAnyNodeContext(request.context);
897 CTxMemPool &mempool = EnsureMemPool(node);
899 const auto package_result = WITH_LOCK(
900 ::cs_main, return ProcessNewPackage(chainstate, mempool, txns,
901 /*test_accept=*/false));
902
903 std::string package_msg = "success";
904
905 // First catch package-wide errors, continue if we can
906 switch (package_result.m_state.GetResult()) {
908 // Belt-and-suspenders check; everything should be
909 // successful here
910 CHECK_NONFATAL(package_result.m_tx_results.size() ==
911 txns.size());
912 for (const auto &tx : txns) {
913 CHECK_NONFATAL(mempool.exists(tx->GetId()));
914 }
915 break;
916 }
918 // This only happens with internal bug; user should stop and
919 // report
922 package_result.m_state.GetRejectReason());
923 }
926 // Package-wide error we want to return, but we also want to
927 // return individual responses
928 package_msg = package_result.m_state.GetRejectReason();
929 CHECK_NONFATAL(package_result.m_tx_results.size() ==
930 txns.size() ||
931 package_result.m_tx_results.empty());
932 break;
933 }
934 }
935 size_t num_broadcast{0};
936 for (const auto &tx : txns) {
937 // We don't want to re-submit the txn for validation in
938 // BroadcastTransaction
939 if (!mempool.exists(tx->GetId())) {
940 continue;
941 }
942
943 // We do not expect an error here; we are only broadcasting
944 // things already/still in mempool
945 std::string err_string;
946 const auto err = BroadcastTransaction(
947 node, tx, err_string, /*max_tx_fee=*/Amount::zero(),
948 /*relay=*/true, /*wait_callback=*/true);
949 if (err != TransactionError::OK) {
951 err,
952 strprintf("transaction broadcast failed: %s (%d "
953 "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 for (const auto &tx : txns) {
963 UniValue result_inner{UniValue::VOBJ};
964 auto it = package_result.m_tx_results.find(tx->GetId());
965 if (it == package_result.m_tx_results.end()) {
966 // No results, report error and continue
967 result_inner.pushKV("error", "unevaluated");
968 continue;
969 }
970 const auto &tx_result = it->second;
971 switch (it->second.m_result_type) {
973 result_inner.pushKV("error",
974 it->second.m_state.ToString());
975 break;
978 result_inner.pushKV(
979 "vsize", int64_t{it->second.m_vsize.value()});
981 fees.pushKV("base", it->second.m_base_fees.value());
982 if (tx_result.m_result_type ==
984 // Effective feerate is not provided for
985 // MEMPOOL_ENTRY (already in mempool) transactions
986 // even though modified fees is known, because it is
987 // unknown whether package feerate was used when it
988 // was originally submitted.
989 fees.pushKV("effective-feerate",
990 tx_result.m_effective_feerate.value()
991 .GetFeePerK());
992 UniValue effective_includes_res(UniValue::VARR);
993 for (const auto &txid :
994 tx_result.m_txids_fee_calculations.value()) {
995 effective_includes_res.push_back(
996 txid.ToString());
997 }
998 fees.pushKV("effective-includes",
999 effective_includes_res);
1000 }
1001 result_inner.pushKV("fees", fees);
1002 break;
1003 }
1004 tx_result_map.pushKV(tx->GetId().GetHex(), result_inner);
1005 }
1006 rpc_result.pushKV("tx-results", tx_result_map);
1007
1008 return rpc_result;
1009 },
1010 };
1011}
1012
1014 static const CRPCCommand commands[]{
1015 // category actor (function)
1016 // -------- ----------------
1017 {"rawtransactions", sendrawtransaction},
1018 {"rawtransactions", testmempoolaccept},
1019 {"blockchain", getmempoolancestors},
1020 {"blockchain", getmempooldescendants},
1021 {"blockchain", getmempoolentry},
1022 {"blockchain", getmempoolinfo},
1023 {"blockchain", getrawmempool},
1024 {"blockchain", savemempool},
1025 {"rawtransactions", submitpackage},
1026 };
1027 for (const auto &c : commands) {
1028 t.appendCommand(c.name, &c);
1029 }
1030}
#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
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:328
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition: txmempool.h:221
std::set< txiter, CompareIteratorById > setEntries
Definition: txmempool.h:321
bool GetLoadTried() const
Definition: txmempool.cpp:1022
CFeeRate GetMinFee() const
The minimum fee to get into the mempool, which may itself not be enough for larger-sized transactions...
Definition: txmempool.h:463
RecursiveMutex cs
This mutex needs to be locked when accessing mapTx or other members that are guarded by it.
Definition: txmempool.h:317
Amount GetTotalFee() const EXCLUSIVE_LOCKS_REQUIRED(cs)
Definition: txmempool.h:525
uint64_t GetTotalFinalizedTxSigchecks() const EXCLUSIVE_LOCKS_REQUIRED(cs)
Definition: txmempool.h:516
const int64_t m_max_size_bytes
Definition: txmempool.h:354
void getAllTxIds(std::vector< TxId > &vtxid) const
Definition: txmempool.cpp:518
size_t DynamicMemoryUsage() const
Definition: txmempool.cpp:815
bool exists(const TxId &txid) const
Definition: txmempool.h:530
std::set< TxId > GetUnbroadcastTxs() const
Returns transactions in unbroadcast set.
Definition: txmempool.h:569
const CFeeRate m_min_relay_feerate
Definition: txmempool.h:356
uint64_t GetSequence() const EXCLUSIVE_LOCKS_REQUIRED(cs)
Definition: txmempool.h:585
indexed_transaction_set::nth_index< 0 >::type::const_iterator txiter
Definition: txmempool.h:320
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:59
uint64_t GetTotalFinalizedTxSize() const EXCLUSIVE_LOCKS_REQUIRED(cs)
Definition: txmempool.h:510
void CalculateDescendants(txiter it, setEntries &setDescendants) const EXCLUSIVE_LOCKS_REQUIRED(cs)
Populate setDescendants with all in-mempool descendants of hash.
Definition: txmempool.cpp:243
unsigned long size() const
Definition: txmempool.h:500
uint64_t GetTotalTxSize() const EXCLUSIVE_LOCKS_REQUIRED(cs)
Definition: txmempool.h:505
Chainstate stores and provides an API to update our local knowledge of the current best chain.
Definition: validation.h:734
Provides an interface for creating and interacting with one or two chainstates: an IBD chainstate gen...
Definition: validation.h:1186
SnapshotCompletionResult MaybeCompleteSnapshotValidation() EXCLUSIVE_LOCKS_REQUIRED(const CBlockIndex *GetSnapshotBaseBlock() const EXCLUSIVE_LOCKS_REQUIRED(Chainstate ActiveChainstate)() const
Once the background validation chainstate has reached the height which is the base of the UTXO snapsh...
Definition: validation.h:1437
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:123
Result GetResult() const
Definition: validation.h:122
std::string ToString() const
Definition: validation.h:125
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:199
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:706
static RPCHelpMan sendrawtransaction()
Definition: mempool.cpp:31
void RegisterMempoolRPCCommands(CRPCTable &t)
Register mempool RPC commands.
Definition: mempool.cpp:1013
static RPCHelpMan getrawmempool()
Definition: mempool.cpp:443
static RPCHelpMan getmempoolentry()
Definition: mempool.cpp:654
UniValue MempoolInfoToJSON(const CTxMemPool &pool)
Mempool information to JSON.
Definition: mempool.cpp:685
static std::vector< RPCResult > MempoolEntryDescription()
Definition: mempool.cpp:324
static RPCHelpMan submitpackage()
Definition: mempool.cpp:791
UniValue MempoolToJSON(const CTxMemPool &pool, bool verbose, bool include_mempool_sequence)
Mempool to JSON.
Definition: mempool.cpp:399
static void entryToJSON(const CTxMemPool &pool, UniValue &info, const CTxMemPoolEntryRef &e) EXCLUSIVE_LOCKS_REQUIRED(pool.cs)
Definition: mempool.cpp:362
static RPCHelpMan testmempoolaccept()
Definition: mempool.cpp:99
static RPCHelpMan getmempooldescendants()
Definition: mempool.cpp:580
static RPCHelpMan getmempoolancestors()
Definition: mempool.cpp:509
static RPCHelpMan savemempool()
Definition: mempool.cpp:751
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:31
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)
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:153
UniValue JSONRPCTransactionError(TransactionError terr, const std::string &err_string)
Definition: util.cpp:336
Amount AmountFromValue(const UniValue &value)
Definition: util.cpp:58
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:170
uint256 ParseHashV(const UniValue &v, std::string strName)
Utilities: convert hex-encoded values (throws error if not hex).
Definition: util.cpp:76
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
CTxMemPool & EnsureAnyMemPool(const std::any &context)
Definition: server_util.cpp:37
ArgsManager & EnsureAnyArgsman(const std::any &context)
Definition: server_util.cpp:48
std::string ToString(const T &t)
Locale-independent version of std::to_string.
Definition: string.h:108
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:316
PackageValidationState m_state
Definition: validation.h:317
std::map< TxId, MempoolAcceptResult > m_tx_results
Map from txid to finished MempoolAcceptResults.
Definition: validation.h:325
@ 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
Optional argument for which the default value is omitted from help text 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:48
#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:57
#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...