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