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