Branch data Line data Source code
1 : : // Copyright (c) 2010 Satoshi Nakamoto
2 : : // Copyright (c) 2009-2022 The Bitcoin Core developers
3 : : // Distributed under the MIT software license, see the accompanying
4 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 : :
6 : : #include <rpc/blockchain.h>
7 : :
8 : : #include <node/mempool_persist.h>
9 : :
10 : : #include <chainparams.h>
11 : : #include <consensus/validation.h>
12 : : #include <core_io.h>
13 : : #include <kernel/mempool_entry.h>
14 : : #include <net_processing.h>
15 : : #include <node/mempool_persist_args.h>
16 : : #include <node/types.h>
17 : : #include <policy/rbf.h>
18 : : #include <policy/settings.h>
19 : : #include <primitives/transaction.h>
20 : : #include <rpc/server.h>
21 : : #include <rpc/server_util.h>
22 : : #include <rpc/util.h>
23 : : #include <txmempool.h>
24 : : #include <univalue.h>
25 : : #include <util/fs.h>
26 : : #include <util/moneystr.h>
27 : : #include <util/strencodings.h>
28 : : #include <util/time.h>
29 : : #include <util/vector.h>
30 : :
31 : : #include <string_view>
32 : : #include <utility>
33 : :
34 : : using node::DumpMempool;
35 : :
36 : : using node::DEFAULT_MAX_BURN_AMOUNT;
37 : : using node::DEFAULT_MAX_RAW_TX_FEE_RATE;
38 : : using node::MempoolPath;
39 : : using node::NodeContext;
40 : : using node::TransactionError;
41 : : using util::ToString;
42 : :
43 : 24617 : static RPCHelpMan sendrawtransaction()
44 : : {
45 : 24617 : return RPCHelpMan{
46 : 24617 : "sendrawtransaction",
47 [ + - ]: 49234 : "Submit a raw transaction (serialized, hex-encoded) to local node and network.\n"
48 : : "\nThe transaction will be sent unconditionally to all peers, so using sendrawtransaction\n"
49 : : "for manual rebroadcast may degrade privacy by leaking the transaction's origin, as\n"
50 : : "nodes will normally not rebroadcast non-wallet transactions already in their mempool.\n"
51 : : "\nA specific exception, RPC_TRANSACTION_ALREADY_IN_UTXO_SET, may throw if the transaction cannot be added to the mempool.\n"
52 : : "\nRelated RPCs: createrawtransaction, signrawtransactionwithkey\n",
53 : : {
54 [ + - + - ]: 49234 : {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"},
55 [ + - + - : 49234 : {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())},
+ - ]
56 [ + - ]: 49234 : "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT +
57 : 24617 : "/kvB.\nFee rates larger than 1BTC/kvB are rejected.\nSet to 0 to accept any fee rate."},
58 [ + - + - : 49234 : {"maxburnamount", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_BURN_AMOUNT)},
+ - ]
59 [ + - ]: 49234 : "Reject transactions with provably unspendable outputs (e.g. 'datacarrier' outputs that use the OP_RETURN opcode) greater than the specified value, expressed in " + CURRENCY_UNIT + ".\n"
60 : : "If burning funds through unspendable outputs is desired, increase this value.\n"
61 : 24617 : "This check is based on heuristics and does not guarantee spendability of outputs.\n"},
62 : : },
63 [ + - ]: 49234 : RPCResult{
64 [ + - + - ]: 49234 : RPCResult::Type::STR_HEX, "", "The transaction hash in hex"
65 [ + - ]: 49234 : },
66 : 24617 : RPCExamples{
67 : : "\nCreate a transaction\n"
68 [ + - + - : 49234 : + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") +
+ - + - ]
69 : 24617 : "Sign the transaction, and get back the hex\n"
70 [ + - + - : 98468 : + HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") +
+ - + - ]
71 : 24617 : "\nSend the transaction (signed hex)\n"
72 [ + - + - : 98468 : + HelpExampleCli("sendrawtransaction", "\"signedhex\"") +
+ - + - ]
73 : 24617 : "\nAs a JSON-RPC call\n"
74 [ + - + - : 98468 : + HelpExampleRpc("sendrawtransaction", "\"signedhex\"")
+ - + - ]
75 [ + - ]: 24617 : },
76 : 24617 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
77 : : {
78 [ + + ]: 22272 : const CAmount max_burn_amount = request.params[2].isNull() ? 0 : AmountFromValue(request.params[2]);
79 : :
80 : 22272 : CMutableTransaction mtx;
81 [ + - + - : 22272 : if (!DecodeHexTx(mtx, request.params[0].get_str())) {
+ - + + ]
82 [ + - + - ]: 4 : throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input.");
83 : : }
84 : :
85 [ + + ]: 84391 : for (const auto& out : mtx.vout) {
86 [ + + + - : 62125 : if((out.scriptPubKey.IsUnspendable() || !out.scriptPubKey.HasValidOps()) && out.nValue > max_burn_amount) {
+ + + + ]
87 [ + - + - ]: 8 : throw JSONRPCTransactionError(TransactionError::MAX_BURN_EXCEEDED);
88 : : }
89 : : }
90 : :
91 [ + - ]: 22266 : CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
92 : :
93 [ + - + - ]: 22266 : const CFeeRate max_raw_tx_fee_rate{ParseFeeRate(self.Arg<UniValue>("maxfeerate"))};
94 : :
95 [ + - ]: 22266 : int64_t virtual_size = GetVirtualTransactionSize(*tx);
96 [ + - ]: 22266 : CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size);
97 : :
98 [ + - ]: 22266 : std::string err_string;
99 : 22266 : AssertLockNotHeld(cs_main);
100 [ + - ]: 22266 : NodeContext& node = EnsureAnyNodeContext(request.context);
101 [ + - + - : 44532 : const TransactionError err = BroadcastTransaction(node,
+ - ]
102 : : tx,
103 : : err_string,
104 : : max_raw_tx_fee,
105 : : node::TxBroadcast::MEMPOOL_AND_BROADCAST_TO_ALL,
106 : : /*wait_callback=*/true);
107 [ + + ]: 22266 : if (TransactionError::OK != err) {
108 [ + - ]: 4277 : throw JSONRPCTransactionError(err, err_string);
109 : : }
110 : :
111 [ + - + - ]: 35978 : return tx->GetHash().GetHex();
112 [ + - ]: 62521 : },
113 [ + - + - : 172319 : };
+ + - - ]
114 [ + - + - : 147702 : }
+ - - - ]
115 : :
116 : 3854 : static RPCHelpMan testmempoolaccept()
117 : : {
118 : 3854 : return RPCHelpMan{
119 : 3854 : "testmempoolaccept",
120 : : "Returns result of mempool acceptance tests indicating if raw transaction(s) (serialized, hex-encoded) would be accepted by mempool.\n"
121 : : "\nIf multiple transactions are passed in, parents must come before children and package policies apply: the transactions cannot conflict with any mempool transactions or each other.\n"
122 : : "\nIf one transaction fails, other transactions may not be fully validated (the 'allowed' key will be blank).\n"
123 [ + - + - ]: 7708 : "\nThe maximum number of transactions allowed is " + ToString(MAX_PACKAGE_COUNT) + ".\n"
124 : : "\nThis checks if transactions violate the consensus or policy rules.\n"
125 : 3854 : "\nSee sendrawtransaction call.\n",
126 : : {
127 [ + - + - ]: 7708 : {"rawtxs", RPCArg::Type::ARR, RPCArg::Optional::NO, "An array of hex strings of raw transactions.",
128 : : {
129 [ + - + - ]: 7708 : {"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
130 : : },
131 : : },
132 [ + - + - : 7708 : {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())},
+ - ]
133 [ + - ]: 7708 : "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT +
134 : 3854 : "/kvB.\nFee rates larger than 1BTC/kvB are rejected.\nSet to 0 to accept any fee rate."},
135 : : },
136 [ + - ]: 7708 : RPCResult{
137 [ + - + - ]: 7708 : RPCResult::Type::ARR, "", "The result of the mempool acceptance test for each raw transaction in the input array.\n"
138 : : "Returns results for each transaction in the same order they were passed in.\n"
139 : : "Transactions that cannot be fully validated due to failures in other transactions will not contain an 'allowed' result.\n",
140 : : {
141 [ + - + - ]: 7708 : {RPCResult::Type::OBJ, "", "",
142 : : {
143 [ + - + - ]: 7708 : {RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
144 [ + - + - ]: 7708 : {RPCResult::Type::STR_HEX, "wtxid", "The transaction witness hash in hex"},
145 [ + - + - ]: 7708 : {RPCResult::Type::STR, "package-error", /*optional=*/true, "Package validation error, if any (only possible if rawtxs had more than 1 transaction)."},
146 [ + - + - ]: 7708 : {RPCResult::Type::BOOL, "allowed", /*optional=*/true, "Whether this tx would be accepted to the mempool and pass client-specified maxfeerate. "
147 : : "If not present, the tx was not fully validated due to a failure in another tx in the list."},
148 [ + - + - ]: 7708 : {RPCResult::Type::NUM, "vsize", /*optional=*/true, "Virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted (only present when 'allowed' is true)"},
149 [ + - + - ]: 7708 : {RPCResult::Type::OBJ, "fees", /*optional=*/true, "Transaction fees (only present if 'allowed' is true)",
150 : : {
151 [ + - + - ]: 7708 : {RPCResult::Type::STR_AMOUNT, "base", "transaction fee in " + CURRENCY_UNIT},
152 [ + - + - ]: 7708 : {RPCResult::Type::STR_AMOUNT, "effective-feerate", /*optional=*/false, "the effective feerate in " + CURRENCY_UNIT + " per KvB. May differ from the base feerate if, for example, there are modified fees from prioritisetransaction or a package feerate was used."},
153 [ + - + - ]: 7708 : {RPCResult::Type::ARR, "effective-includes", /*optional=*/false, "transactions whose fees and vsizes are included in effective-feerate.",
154 [ + - + - ]: 7708 : {RPCResult{RPCResult::Type::STR_HEX, "", "transaction wtxid in hex"},
155 : : }},
156 : : }},
157 [ + - + - ]: 7708 : {RPCResult::Type::STR, "reject-reason", /*optional=*/true, "Rejection reason (only present when 'allowed' is false)"},
158 [ + - + - ]: 7708 : {RPCResult::Type::STR, "reject-details", /*optional=*/true, "Rejection details (only present when 'allowed' is false and rejection details exist)"},
159 : : }},
160 : : }
161 [ + - + - : 104058 : },
+ - + - +
- + + + +
+ + + + -
- - - - -
- - ]
162 : 3854 : RPCExamples{
163 : : "\nCreate a transaction\n"
164 [ + - + - : 7708 : + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") +
+ - + - ]
165 : 3854 : "Sign the transaction, and get back the hex\n"
166 [ + - + - : 15416 : + HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") +
+ - + - ]
167 : 3854 : "\nTest acceptance of the transaction (signed hex)\n"
168 [ + - + - : 15416 : + HelpExampleCli("testmempoolaccept", R"('["signedhex"]')") +
+ - + - ]
169 : 3854 : "\nAs a JSON-RPC call\n"
170 [ + - + - : 15416 : + HelpExampleRpc("testmempoolaccept", "[\"signedhex\"]")
+ - + - ]
171 [ + - ]: 3854 : },
172 : 3854 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
173 : : {
174 : 1509 : const UniValue raw_transactions = request.params[0].get_array();
175 [ - + + + : 1509 : if (raw_transactions.size() < 1 || raw_transactions.size() > MAX_PACKAGE_COUNT) {
+ + ]
176 : 2 : throw JSONRPCError(RPC_INVALID_PARAMETER,
177 [ + - + - : 6 : "Array must contain between 1 and " + ToString(MAX_PACKAGE_COUNT) + " transactions.");
+ - ]
178 : : }
179 : :
180 [ + - + + ]: 1507 : const CFeeRate max_raw_tx_fee_rate{ParseFeeRate(self.Arg<UniValue>("maxfeerate"))};
181 : :
182 : 1505 : std::vector<CTransactionRef> txns;
183 [ - + + - ]: 1505 : txns.reserve(raw_transactions.size());
184 [ + - + + ]: 3613 : for (const auto& rawtx : raw_transactions.getValues()) {
185 [ + - ]: 2109 : CMutableTransaction mtx;
186 [ + - + - : 2109 : if (!DecodeHexTx(mtx, rawtx.get_str())) {
+ + ]
187 : 1 : throw JSONRPCError(RPC_DESERIALIZATION_ERROR,
188 [ + - + - : 3 : "TX decode failed: " + rawtx.get_str() + " Make sure the tx has at least one input.");
+ - ]
189 : : }
190 [ + - + - ]: 6324 : txns.emplace_back(MakeTransactionRef(std::move(mtx)));
191 : 2109 : }
192 : :
193 [ + - ]: 1504 : NodeContext& node = EnsureAnyNodeContext(request.context);
194 [ + - ]: 1504 : CTxMemPool& mempool = EnsureMemPool(node);
195 [ + - ]: 1504 : ChainstateManager& chainman = EnsureChainman(node);
196 [ + - ]: 1504 : Chainstate& chainstate = chainman.ActiveChainstate();
197 : 3008 : const PackageMempoolAcceptResult package_result = [&] {
198 : 1504 : LOCK(::cs_main);
199 [ - + + + : 1504 : if (txns.size() > 1) return ProcessNewPackage(chainstate, mempool, txns, /*test_accept=*/true, /*client_maxfeerate=*/{});
+ - ]
200 [ + - ]: 1419 : return PackageMempoolAcceptResult(txns[0]->GetWitnessHash(),
201 [ + - + - ]: 1419 : chainman.ProcessTransaction(txns[0], /*test_accept=*/true));
202 [ + - ]: 3008 : }();
203 : :
204 : 1504 : UniValue rpc_result(UniValue::VARR);
205 : : // We will check transaction fees while we iterate through txns in order. If any transaction fee
206 : : // exceeds maxfeerate, we will leave the rest of the validation results blank, because it
207 : : // doesn't make sense to return a validation result for a transaction if its ancestor(s) would
208 : : // not be submitted.
209 : 1504 : bool exit_early{false};
210 [ + + ]: 3612 : for (const auto& tx : txns) {
211 : 2108 : UniValue result_inner(UniValue::VOBJ);
212 [ + - + - : 4216 : result_inner.pushKV("txid", tx->GetHash().GetHex());
+ - + - ]
213 [ + - + - : 4216 : result_inner.pushKV("wtxid", tx->GetWitnessHash().GetHex());
+ - + - ]
214 [ + + ]: 2108 : if (package_result.m_state.GetResult() == PackageValidationResult::PCKG_POLICY) {
215 [ + - + - : 224 : result_inner.pushKV("package-error", package_result.m_state.ToString());
+ - + - ]
216 : : }
217 : 2108 : auto it = package_result.m_tx_results.find(tx->GetWitnessHash());
218 [ + + + + ]: 2108 : if (exit_early || it == package_result.m_tx_results.end()) {
219 : : // Validation unfinished. Just return the txid and wtxid.
220 [ + - ]: 152 : rpc_result.push_back(std::move(result_inner));
221 : 152 : continue;
222 : : }
223 [ + - ]: 1956 : const auto& tx_result = it->second;
224 : : // Package testmempoolaccept doesn't allow transactions to already be in the mempool.
225 [ + - ]: 1956 : CHECK_NONFATAL(tx_result.m_result_type != MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
226 [ + + ]: 1956 : if (tx_result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
227 [ + - ]: 1706 : const CAmount fee = tx_result.m_base_fees.value();
228 : : // Check that fee does not exceed maximum fee
229 [ + - ]: 1706 : const int64_t virtual_size = tx_result.m_vsize.value();
230 [ + - ]: 1706 : const CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size);
231 [ + + ]: 1706 : if (max_raw_tx_fee && fee > max_raw_tx_fee) {
232 [ + - + - : 8 : result_inner.pushKV("allowed", false);
+ - ]
233 [ + - + - : 4 : result_inner.pushKV("reject-reason", "max-fee-exceeded");
+ - ]
234 : 4 : exit_early = true;
235 : : } else {
236 : : // Only return the fee and vsize if the transaction would pass ATMP.
237 : : // These can be used to calculate the feerate.
238 [ + - + - : 3404 : result_inner.pushKV("allowed", true);
+ - ]
239 [ + - + - : 3404 : result_inner.pushKV("vsize", virtual_size);
+ - ]
240 : 1702 : UniValue fees(UniValue::VOBJ);
241 [ + - + - : 3404 : fees.pushKV("base", ValueFromAmount(fee));
+ - ]
242 [ + - + - : 3404 : fees.pushKV("effective-feerate", ValueFromAmount(tx_result.m_effective_feerate.value().GetFeePerK()));
+ - + - ]
243 : 1702 : UniValue effective_includes_res(UniValue::VARR);
244 [ + - + + ]: 3404 : for (const auto& wtxid : tx_result.m_wtxids_fee_calculations.value()) {
245 [ + - + - : 1702 : effective_includes_res.push_back(wtxid.ToString());
+ - ]
246 : : }
247 [ + - + - ]: 3404 : fees.pushKV("effective-includes", std::move(effective_includes_res));
248 [ + - + - ]: 3404 : result_inner.pushKV("fees", std::move(fees));
249 : 1702 : }
250 : : } else {
251 [ + - + - : 500 : result_inner.pushKV("allowed", false);
+ - ]
252 [ + - ]: 250 : const TxValidationState state = tx_result.m_state;
253 [ + + ]: 250 : if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
254 [ + - + - : 232 : result_inner.pushKV("reject-reason", "missing-inputs");
+ - ]
255 : : } else {
256 [ - + + - : 402 : result_inner.pushKV("reject-reason", state.GetRejectReason());
+ - + - ]
257 [ + - + - : 268 : result_inner.pushKV("reject-details", state.ToString());
+ - + - ]
258 : : }
259 : 250 : }
260 [ + - ]: 1956 : rpc_result.push_back(std::move(result_inner));
261 : 2108 : }
262 : 1504 : return rpc_result;
263 : 1510 : },
264 [ + - + - : 34686 : };
+ - + + +
+ - - -
- ]
265 [ + - + - : 73226 : }
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - - -
- - - - ]
266 : :
267 : 16948 : static std::vector<RPCResult> MempoolEntryDescription()
268 : : {
269 : 16948 : return {
270 [ + - + - ]: 33896 : RPCResult{RPCResult::Type::NUM, "vsize", "virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted."},
271 [ + - + - ]: 33896 : RPCResult{RPCResult::Type::NUM, "weight", "transaction weight as defined in BIP 141."},
272 [ + - + - ]: 33896 : RPCResult{RPCResult::Type::NUM_TIME, "time", "local time transaction entered pool in seconds since 1 Jan 1970 GMT"},
273 [ + - + - ]: 33896 : RPCResult{RPCResult::Type::NUM, "height", "block height when transaction entered pool"},
274 [ + - + - ]: 33896 : RPCResult{RPCResult::Type::NUM, "descendantcount", "number of in-mempool descendant transactions (including this one)"},
275 [ + - + - ]: 33896 : RPCResult{RPCResult::Type::NUM, "descendantsize", "virtual transaction size of in-mempool descendants (including this one)"},
276 [ + - + - ]: 33896 : RPCResult{RPCResult::Type::NUM, "ancestorcount", "number of in-mempool ancestor transactions (including this one)"},
277 [ + - + - ]: 33896 : RPCResult{RPCResult::Type::NUM, "ancestorsize", "virtual transaction size of in-mempool ancestors (including this one)"},
278 [ + - + - ]: 33896 : RPCResult{RPCResult::Type::STR_HEX, "wtxid", "hash of serialized transaction, including witness data"},
279 [ + - + - ]: 33896 : RPCResult{RPCResult::Type::OBJ, "fees", "",
280 : : {
281 [ + - + - ]: 33896 : RPCResult{RPCResult::Type::STR_AMOUNT, "base", "transaction fee, denominated in " + CURRENCY_UNIT},
282 [ + - + - ]: 33896 : RPCResult{RPCResult::Type::STR_AMOUNT, "modified", "transaction fee with fee deltas used for mining priority, denominated in " + CURRENCY_UNIT},
283 [ + - + - ]: 33896 : RPCResult{RPCResult::Type::STR_AMOUNT, "ancestor", "transaction fees of in-mempool ancestors (including this one) with fee deltas used for mining priority, denominated in " + CURRENCY_UNIT},
284 [ + - + - ]: 33896 : RPCResult{RPCResult::Type::STR_AMOUNT, "descendant", "transaction fees of in-mempool descendants (including this one) with fee deltas used for mining priority, denominated in " + CURRENCY_UNIT},
285 [ + - + + : 101688 : }},
- - ]
286 [ + - + - ]: 33896 : RPCResult{RPCResult::Type::ARR, "depends", "unconfirmed transactions used as inputs for this transaction",
287 [ + - + - : 67792 : {RPCResult{RPCResult::Type::STR_HEX, "transactionid", "parent transaction id"}}},
+ - + + -
- ]
288 [ + - + - ]: 33896 : RPCResult{RPCResult::Type::ARR, "spentby", "unconfirmed transactions spending outputs from this transaction",
289 [ + - + - : 67792 : {RPCResult{RPCResult::Type::STR_HEX, "transactionid", "child transaction id"}}},
+ - + + -
- ]
290 [ + - + - ]: 33896 : RPCResult{RPCResult::Type::BOOL, "bip125-replaceable", "Whether this transaction signals BIP125 replaceability or has an unconfirmed ancestor signaling BIP125 replaceability. (DEPRECATED)\n"},
291 [ + - + - ]: 33896 : RPCResult{RPCResult::Type::BOOL, "unbroadcast", "Whether this transaction is currently unbroadcast (initial broadcast not yet acknowledged by any peers)"},
292 [ + - + + : 288116 : };
- - ]
293 [ + - + - : 338960 : }
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- - - -
- ]
294 : :
295 : 4948 : static void entryToJSON(const CTxMemPool& pool, UniValue& info, const CTxMemPoolEntry& e) EXCLUSIVE_LOCKS_REQUIRED(pool.cs)
296 : : {
297 : 4948 : AssertLockHeld(pool.cs);
298 : :
299 [ + - + - ]: 9896 : info.pushKV("vsize", (int)e.GetTxSize());
300 [ + - + - ]: 9896 : info.pushKV("weight", (int)e.GetTxWeight());
301 [ + - + - ]: 9896 : info.pushKV("time", count_seconds(e.GetTime()));
302 [ + - + - ]: 9896 : info.pushKV("height", (int)e.GetHeight());
303 [ + - + - ]: 9896 : info.pushKV("descendantcount", e.GetCountWithDescendants());
304 [ + - + - ]: 9896 : info.pushKV("descendantsize", e.GetSizeWithDescendants());
305 [ + - + - ]: 9896 : info.pushKV("ancestorcount", e.GetCountWithAncestors());
306 [ + - + - ]: 9896 : info.pushKV("ancestorsize", e.GetSizeWithAncestors());
307 [ + - + - : 9896 : info.pushKV("wtxid", e.GetTx().GetWitnessHash().ToString());
+ - ]
308 : :
309 : 4948 : UniValue fees(UniValue::VOBJ);
310 [ + - + - : 9896 : fees.pushKV("base", ValueFromAmount(e.GetFee()));
+ - ]
311 [ + - + - : 9896 : fees.pushKV("modified", ValueFromAmount(e.GetModifiedFee()));
+ - ]
312 [ + - + - : 9896 : fees.pushKV("ancestor", ValueFromAmount(e.GetModFeesWithAncestors()));
+ - ]
313 [ + - + - : 9896 : fees.pushKV("descendant", ValueFromAmount(e.GetModFeesWithDescendants()));
+ - ]
314 [ + - + - ]: 9896 : info.pushKV("fees", std::move(fees));
315 : :
316 : 4948 : const CTransaction& tx = e.GetTx();
317 : 4948 : std::set<std::string> setDepends;
318 [ + + ]: 16234 : for (const CTxIn& txin : tx.vin)
319 : : {
320 [ + - + + ]: 11286 : if (pool.exists(txin.prevout.hash))
321 [ + - + - ]: 12954 : setDepends.insert(txin.prevout.hash.ToString());
322 : : }
323 : :
324 : 4948 : UniValue depends(UniValue::VARR);
325 [ + + ]: 11425 : for (const std::string& dep : setDepends)
326 : : {
327 [ + - + - ]: 6477 : depends.push_back(dep);
328 : : }
329 : :
330 [ + - + - ]: 9896 : info.pushKV("depends", std::move(depends));
331 : :
332 : 4948 : UniValue spent(UniValue::VARR);
333 [ + - + + ]: 11241 : for (const CTxMemPoolEntry& child : e.GetMemPoolChildrenConst()) {
334 [ + - + - : 6293 : spent.push_back(child.GetTx().GetHash().ToString());
+ - ]
335 : : }
336 : :
337 [ + - + - ]: 9896 : info.pushKV("spentby", std::move(spent));
338 : :
339 : : // Add opt-in RBF status
340 : 4948 : bool rbfStatus = false;
341 [ + - ]: 4948 : RBFTransactionState rbfState = IsRBFOptIn(tx, pool);
342 [ - + ]: 4948 : if (rbfState == RBFTransactionState::UNKNOWN) {
343 [ # # # # ]: 0 : throw JSONRPCError(RPC_MISC_ERROR, "Transaction is not in mempool");
344 [ + + ]: 4948 : } else if (rbfState == RBFTransactionState::REPLACEABLE_BIP125) {
345 : 4107 : rbfStatus = true;
346 : : }
347 : :
348 [ + - + - : 9896 : info.pushKV("bip125-replaceable", rbfStatus);
+ - ]
349 [ + - + - : 9896 : info.pushKV("unbroadcast", pool.IsUnbroadcastTx(tx.GetHash()));
+ - ]
350 : 4948 : }
351 : :
352 : 6617 : UniValue MempoolToJSON(const CTxMemPool& pool, bool verbose, bool include_mempool_sequence)
353 : : {
354 [ + + ]: 6617 : if (verbose) {
355 [ + + ]: 1035 : if (include_mempool_sequence) {
356 [ + - + - ]: 2 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Verbose results cannot contain mempool sequence values.");
357 : : }
358 : 1034 : LOCK(pool.cs);
359 : 1034 : UniValue o(UniValue::VOBJ);
360 [ + - + + ]: 4483 : for (const CTxMemPoolEntry& e : pool.entryAll()) {
361 : 3449 : UniValue info(UniValue::VOBJ);
362 [ + - ]: 3449 : entryToJSON(pool, info, e);
363 : : // Mempool has unique entries so there is no advantage in using
364 : : // UniValue::pushKV, which checks if the key already exists in O(N).
365 : : // UniValue::pushKVEnd is used instead which currently is O(1).
366 [ + - + - ]: 6898 : o.pushKVEnd(e.GetTx().GetHash().ToString(), std::move(info));
367 : 3449 : }
368 [ + - ]: 1034 : return o;
369 : 1034 : } else {
370 : 5582 : UniValue a(UniValue::VARR);
371 : 5582 : uint64_t mempool_sequence;
372 : 5582 : {
373 [ + - ]: 5582 : LOCK(pool.cs);
374 [ + - + - : 252335 : for (const CTxMemPoolEntry& e : pool.entryAll()) {
+ + ]
375 [ + - + - : 246753 : a.push_back(e.GetTx().GetHash().ToString());
+ - ]
376 : : }
377 [ + - ]: 5582 : mempool_sequence = pool.GetSequence();
378 : 0 : }
379 [ + + ]: 5582 : if (!include_mempool_sequence) {
380 : 5561 : return a;
381 : : } else {
382 : 21 : UniValue o(UniValue::VOBJ);
383 [ + - + - ]: 42 : o.pushKV("txids", std::move(a));
384 [ + - + - : 42 : o.pushKV("mempool_sequence", mempool_sequence);
+ - ]
385 : 21 : return o;
386 : 21 : }
387 : 5582 : }
388 : : }
389 : :
390 : 8957 : static RPCHelpMan getrawmempool()
391 : : {
392 : 8957 : return RPCHelpMan{
393 : 8957 : "getrawmempool",
394 [ + - ]: 17914 : "Returns all transaction ids in memory pool as a json array of string transaction ids.\n"
395 : : "\nHint: use getmempoolentry to fetch a specific transaction from the mempool.\n",
396 : : {
397 [ + - + - : 26871 : {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"},
+ - ]
398 [ + - + - : 26871 : {"mempool_sequence", RPCArg::Type::BOOL, RPCArg::Default{false}, "If verbose=false, returns a json object with transaction list and mempool sequence number attached."},
+ - ]
399 : : },
400 : : {
401 [ + - ]: 8957 : RPCResult{"for verbose = false",
402 [ + - + - ]: 17914 : RPCResult::Type::ARR, "", "",
403 : : {
404 [ + - + - ]: 17914 : {RPCResult::Type::STR_HEX, "", "The transaction id"},
405 [ + - + + : 26871 : }},
- - ]
406 [ + - ]: 17914 : RPCResult{"for verbose = true",
407 [ + - + - ]: 17914 : RPCResult::Type::OBJ_DYN, "", "",
408 : : {
409 [ + - + - : 17914 : {RPCResult::Type::OBJ, "transactionid", "", MempoolEntryDescription()},
+ - ]
410 [ + - + + : 26871 : }},
- - ]
411 [ + - ]: 17914 : RPCResult{"for verbose = false and mempool_sequence = true",
412 [ + - + - ]: 17914 : RPCResult::Type::OBJ, "", "",
413 : : {
414 [ + - + - ]: 17914 : {RPCResult::Type::ARR, "txids", "",
415 : : {
416 [ + - + - ]: 17914 : {RPCResult::Type::STR_HEX, "", "The transaction id"},
417 : : }},
418 [ + - + - ]: 17914 : {RPCResult::Type::NUM, "mempool_sequence", "The mempool sequence value."},
419 [ + - + - : 62699 : }},
+ + + + -
- - - ]
420 : : },
421 : 8957 : RPCExamples{
422 [ + - + - : 17914 : HelpExampleCli("getrawmempool", "true")
+ - ]
423 [ + - + - : 35828 : + HelpExampleRpc("getrawmempool", "true")
+ - ]
424 [ + - ]: 8957 : },
425 : 8957 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
426 : : {
427 : 6613 : bool fVerbose = false;
428 [ + + ]: 6613 : if (!request.params[0].isNull())
429 : 1097 : fVerbose = request.params[0].get_bool();
430 : :
431 : 6613 : bool include_mempool_sequence = false;
432 [ + + ]: 6613 : if (!request.params[1].isNull()) {
433 : 22 : include_mempool_sequence = request.params[1].get_bool();
434 : : }
435 : :
436 : 6613 : return MempoolToJSON(EnsureAnyMemPool(request.context), fVerbose, include_mempool_sequence);
437 : : },
438 [ + - + - : 107484 : };
+ - + - +
+ + + - -
- - ]
439 [ + - + - : 107484 : }
+ - + - +
- + - + -
+ - + - +
- - - - -
- - ]
440 : :
441 : 2395 : static RPCHelpMan getmempoolancestors()
442 : : {
443 : 2395 : return RPCHelpMan{
444 : 2395 : "getmempoolancestors",
445 [ + - ]: 4790 : "If txid is in the mempool, returns all in-mempool ancestors.\n",
446 : : {
447 [ + - + - ]: 4790 : {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
448 [ + - + - : 7185 : {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"},
+ - ]
449 : : },
450 : : {
451 [ + - ]: 2395 : RPCResult{"for verbose = false",
452 [ + - + - ]: 4790 : RPCResult::Type::ARR, "", "",
453 [ + - + - : 9580 : {{RPCResult::Type::STR_HEX, "", "The transaction id of an in-mempool ancestor transaction"}}},
+ - + + -
- ]
454 [ + - ]: 4790 : RPCResult{"for verbose = true",
455 [ + - + - ]: 4790 : RPCResult::Type::OBJ_DYN, "", "",
456 : : {
457 [ + - + - : 4790 : {RPCResult::Type::OBJ, "transactionid", "", MempoolEntryDescription()},
+ - ]
458 [ + - + + : 7185 : }},
- - ]
459 : : },
460 : 2395 : RPCExamples{
461 [ + - + - : 4790 : HelpExampleCli("getmempoolancestors", "\"mytxid\"")
+ - ]
462 [ + - + - : 9580 : + HelpExampleRpc("getmempoolancestors", "\"mytxid\"")
+ - ]
463 [ + - ]: 2395 : },
464 : 2395 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
465 : : {
466 : 51 : bool fVerbose = false;
467 [ + + ]: 51 : if (!request.params[1].isNull())
468 : 26 : fVerbose = request.params[1].get_bool();
469 : :
470 : 51 : auto txid{Txid::FromUint256(ParseHashV(request.params[0], "txid"))};
471 : :
472 : 51 : const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
473 : 51 : LOCK(mempool.cs);
474 : :
475 [ + - ]: 51 : const auto entry{mempool.GetEntry(txid)};
476 [ - + ]: 51 : if (entry == nullptr) {
477 [ # # # # ]: 0 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool");
478 : : }
479 : :
480 [ - + + - ]: 51 : auto ancestors{mempool.AssumeCalculateMemPoolAncestors(self.m_name, *entry, CTxMemPool::Limits::NoLimits(), /*fSearchForParents=*/false)};
481 : :
482 [ + + ]: 51 : if (!fVerbose) {
483 : 25 : UniValue o(UniValue::VARR);
484 [ + + ]: 325 : for (CTxMemPool::txiter ancestorIt : ancestors) {
485 [ + - + - : 300 : o.push_back(ancestorIt->GetTx().GetHash().ToString());
+ - ]
486 : : }
487 : : return o;
488 : 0 : } else {
489 : 26 : UniValue o(UniValue::VOBJ);
490 [ + + ]: 350 : for (CTxMemPool::txiter ancestorIt : ancestors) {
491 : 324 : const CTxMemPoolEntry &e = *ancestorIt;
492 : 324 : UniValue info(UniValue::VOBJ);
493 [ + - ]: 324 : entryToJSON(mempool, info, e);
494 [ + - + - ]: 648 : o.pushKV(e.GetTx().GetHash().ToString(), std::move(info));
495 : 324 : }
496 : 26 : return o;
497 : 26 : }
498 [ + - ]: 102 : },
499 [ + - + - : 26345 : };
+ - + - +
+ + + - -
- - ]
500 [ + - + - : 19160 : }
+ - + - +
- + - - -
- - ]
501 : :
502 : 2395 : static RPCHelpMan getmempooldescendants()
503 : : {
504 : 2395 : return RPCHelpMan{
505 : 2395 : "getmempooldescendants",
506 [ + - ]: 4790 : "If txid is in the mempool, returns all in-mempool descendants.\n",
507 : : {
508 [ + - + - ]: 4790 : {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
509 [ + - + - : 7185 : {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"},
+ - ]
510 : : },
511 : : {
512 [ + - ]: 2395 : RPCResult{"for verbose = false",
513 [ + - + - ]: 4790 : RPCResult::Type::ARR, "", "",
514 [ + - + - : 9580 : {{RPCResult::Type::STR_HEX, "", "The transaction id of an in-mempool descendant transaction"}}},
+ - + + -
- ]
515 [ + - ]: 4790 : RPCResult{"for verbose = true",
516 [ + - + - ]: 4790 : RPCResult::Type::OBJ_DYN, "", "",
517 : : {
518 [ + - + - : 4790 : {RPCResult::Type::OBJ, "transactionid", "", MempoolEntryDescription()},
+ - ]
519 [ + - + + : 7185 : }},
- - ]
520 : : },
521 : 2395 : RPCExamples{
522 [ + - + - : 4790 : HelpExampleCli("getmempooldescendants", "\"mytxid\"")
+ - ]
523 [ + - + - : 9580 : + HelpExampleRpc("getmempooldescendants", "\"mytxid\"")
+ - ]
524 [ + - ]: 2395 : },
525 : 2395 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
526 : : {
527 : 51 : bool fVerbose = false;
528 [ + + ]: 51 : if (!request.params[1].isNull())
529 : 26 : fVerbose = request.params[1].get_bool();
530 : :
531 : 51 : auto txid{Txid::FromUint256(ParseHashV(request.params[0], "txid"))};
532 : :
533 : 51 : const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
534 : 51 : LOCK(mempool.cs);
535 : :
536 [ + - ]: 51 : const auto it{mempool.GetIter(txid)};
537 [ - + ]: 51 : if (!it) {
538 [ # # # # ]: 0 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool");
539 : : }
540 : :
541 [ + - ]: 51 : CTxMemPool::setEntries setDescendants;
542 [ + - ]: 51 : mempool.CalculateDescendants(*it, setDescendants);
543 : : // CTxMemPool::CalculateDescendants will include the given tx
544 : 51 : setDescendants.erase(*it);
545 : :
546 [ + + ]: 51 : if (!fVerbose) {
547 : 25 : UniValue o(UniValue::VARR);
548 [ + + ]: 325 : for (CTxMemPool::txiter descendantIt : setDescendants) {
549 [ + - + - : 300 : o.push_back(descendantIt->GetTx().GetHash().ToString());
+ - ]
550 : : }
551 : :
552 : : return o;
553 : 0 : } else {
554 : 26 : UniValue o(UniValue::VOBJ);
555 [ + + ]: 350 : for (CTxMemPool::txiter descendantIt : setDescendants) {
556 : 324 : const CTxMemPoolEntry &e = *descendantIt;
557 : 324 : UniValue info(UniValue::VOBJ);
558 [ + - ]: 324 : entryToJSON(mempool, info, e);
559 [ + - + - ]: 648 : o.pushKV(e.GetTx().GetHash().ToString(), std::move(info));
560 : 324 : }
561 : 26 : return o;
562 : 26 : }
563 [ + - ]: 102 : },
564 [ + - + - : 26345 : };
+ - + - +
+ + + - -
- - ]
565 [ + - + - : 19160 : }
+ - + - +
- + - - -
- - ]
566 : :
567 : 3201 : static RPCHelpMan getmempoolentry()
568 : : {
569 : 3201 : return RPCHelpMan{
570 : 3201 : "getmempoolentry",
571 [ + - ]: 6402 : "Returns mempool data for given transaction\n",
572 : : {
573 [ + - + - ]: 6402 : {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
574 : : },
575 [ + - ]: 6402 : RPCResult{
576 [ + - + - : 6402 : RPCResult::Type::OBJ, "", "", MempoolEntryDescription()},
+ - + - ]
577 : 3201 : RPCExamples{
578 [ + - + - : 6402 : HelpExampleCli("getmempoolentry", "\"mytxid\"")
+ - ]
579 [ + - + - : 12804 : + HelpExampleRpc("getmempoolentry", "\"mytxid\"")
+ - + - ]
580 [ + - ]: 3201 : },
581 : 3201 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
582 : : {
583 : 857 : auto txid{Txid::FromUint256(ParseHashV(request.params[0], "txid"))};
584 : :
585 : 857 : const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
586 : 857 : LOCK(mempool.cs);
587 : :
588 [ + - ]: 857 : const auto entry{mempool.GetEntry(txid)};
589 [ + + ]: 857 : if (entry == nullptr) {
590 [ + - + - ]: 12 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool");
591 : : }
592 : :
593 : 851 : UniValue info(UniValue::VOBJ);
594 [ + - ]: 851 : entryToJSON(mempool, info, *entry);
595 [ + - ]: 851 : return info;
596 : 851 : },
597 [ + - + - : 16005 : };
+ + - - ]
598 [ + - ]: 6402 : }
599 : :
600 : 2380 : static RPCHelpMan gettxspendingprevout()
601 : : {
602 : 2380 : return RPCHelpMan{"gettxspendingprevout",
603 [ + - ]: 4760 : "Scans the mempool to find transactions spending any of the given outputs",
604 : : {
605 [ + - + - ]: 4760 : {"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The transaction outputs that we want to check, and within each, the txid (string) vout (numeric).",
606 : : {
607 [ + - + - ]: 4760 : {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
608 : : {
609 [ + - + - ]: 4760 : {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
610 [ + - + - ]: 4760 : {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
611 : : },
612 : : },
613 : : },
614 : : },
615 : : },
616 [ + - ]: 4760 : RPCResult{
617 [ + - + - ]: 4760 : RPCResult::Type::ARR, "", "",
618 : : {
619 [ + - + - ]: 4760 : {RPCResult::Type::OBJ, "", "",
620 : : {
621 [ + - + - ]: 4760 : {RPCResult::Type::STR_HEX, "txid", "the transaction id of the checked output"},
622 [ + - + - ]: 4760 : {RPCResult::Type::NUM, "vout", "the vout value of the checked output"},
623 [ + - + - ]: 4760 : {RPCResult::Type::STR_HEX, "spendingtxid", /*optional=*/true, "the transaction id of the mempool transaction spending this output (omitted if unspent)"},
624 : : }},
625 : : }
626 [ + - + - : 21420 : },
+ - + + +
+ - - -
- ]
627 : 2380 : RPCExamples{
628 [ + - + - : 4760 : HelpExampleCli("gettxspendingprevout", "\"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":3}]\"")
+ - ]
629 [ + - + - : 9520 : + HelpExampleRpc("gettxspendingprevout", "\"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":3}]\"")
+ - + - ]
630 [ + - ]: 2380 : },
631 : 2380 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
632 : : {
633 : 36 : const UniValue& output_params = request.params[0].get_array();
634 [ - + + + ]: 36 : if (output_params.empty()) {
635 [ + - + - ]: 2 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, outputs are missing");
636 : : }
637 : :
638 : 35 : std::vector<COutPoint> prevouts;
639 [ + - ]: 35 : prevouts.reserve(output_params.size());
640 : :
641 [ - + + + ]: 68 : for (unsigned int idx = 0; idx < output_params.size(); idx++) {
642 [ + - + - ]: 38 : const UniValue& o = output_params[idx].get_obj();
643 : :
644 [ + + + + : 156 : RPCTypeCheckObj(o,
+ + ]
645 : : {
646 [ + - ]: 38 : {"txid", UniValueType(UniValue::VSTR)},
647 [ + - ]: 38 : {"vout", UniValueType(UniValue::VNUM)},
648 : : }, /*fAllowNull=*/false, /*fStrict=*/true);
649 : :
650 [ + - ]: 34 : const Txid txid = Txid::FromUint256(ParseHashO(o, "txid"));
651 [ + - + - ]: 34 : const int nOutput{o.find_value("vout").getInt<int>()};
652 [ + + ]: 34 : if (nOutput < 0) {
653 [ + - + - ]: 2 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative");
654 : : }
655 : :
656 [ + - ]: 33 : prevouts.emplace_back(txid, nOutput);
657 : : }
658 : :
659 [ + - ]: 30 : const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
660 [ + - ]: 30 : LOCK(mempool.cs);
661 : :
662 : 30 : UniValue result{UniValue::VARR};
663 : :
664 [ + + ]: 63 : for (const COutPoint& prevout : prevouts) {
665 : 33 : UniValue o(UniValue::VOBJ);
666 [ + - + - : 66 : o.pushKV("txid", prevout.hash.ToString());
+ - + - ]
667 [ + - + - : 66 : o.pushKV("vout", (uint64_t)prevout.n);
+ - ]
668 : :
669 [ + - ]: 33 : const CTransaction* spendingTx = mempool.GetConflictTx(prevout);
670 [ + + ]: 33 : if (spendingTx != nullptr) {
671 [ + - + - : 60 : o.pushKV("spendingtxid", spendingTx->GetHash().ToString());
+ - + - ]
672 : : }
673 : :
674 [ + - ]: 33 : result.push_back(std::move(o));
675 : 33 : }
676 : :
677 [ + - ]: 30 : return result;
678 [ + - + - : 72 : },
+ - - + ]
679 [ + - + - : 28560 : };
+ - + - +
+ + + + +
- - - - -
- ]
680 [ + - + - : 28560 : }
+ - + - +
- + - + -
+ - - - -
- ]
681 : :
682 : 1266 : UniValue MempoolInfoToJSON(const CTxMemPool& pool)
683 : : {
684 : : // Make sure this call is atomic in the pool.
685 : 1266 : LOCK(pool.cs);
686 : 1266 : UniValue ret(UniValue::VOBJ);
687 [ + - + - : 2532 : ret.pushKV("loaded", pool.GetLoadTried());
+ - + - ]
688 [ + - + - : 2532 : ret.pushKV("size", (int64_t)pool.size());
+ - + - ]
689 [ + - + - : 2532 : ret.pushKV("bytes", (int64_t)pool.GetTotalTxSize());
+ - ]
690 [ + - + - : 2532 : ret.pushKV("usage", (int64_t)pool.DynamicMemoryUsage());
+ - + - ]
691 [ + - + - : 2532 : ret.pushKV("total_fee", ValueFromAmount(pool.GetTotalFee()));
+ - ]
692 [ + - + - : 2532 : ret.pushKV("maxmempool", pool.m_opts.max_size_bytes);
+ - ]
693 [ + - + - : 2532 : ret.pushKV("mempoolminfee", ValueFromAmount(std::max(pool.GetMinFee(), pool.m_opts.min_relay_feerate).GetFeePerK()));
+ - + - ]
694 [ + - + - : 2532 : ret.pushKV("minrelaytxfee", ValueFromAmount(pool.m_opts.min_relay_feerate.GetFeePerK()));
+ - ]
695 [ + - + - : 2532 : ret.pushKV("incrementalrelayfee", ValueFromAmount(pool.m_opts.incremental_relay_feerate.GetFeePerK()));
+ - ]
696 [ + - + - : 2532 : ret.pushKV("unbroadcastcount", uint64_t{pool.GetUnbroadcastTxs().size()});
+ - + - ]
697 [ + - + - : 2532 : ret.pushKV("fullrbf", true);
+ - ]
698 [ + - + - : 2532 : ret.pushKV("permitbaremultisig", pool.m_opts.permit_bare_multisig);
+ - ]
699 [ + + + - : 3796 : ret.pushKV("maxdatacarriersize", pool.m_opts.max_datacarrier_bytes.value_or(0));
+ - + - ]
700 [ + - ]: 1266 : return ret;
701 : 1266 : }
702 : :
703 : 3609 : static RPCHelpMan getmempoolinfo()
704 : : {
705 : 3609 : return RPCHelpMan{"getmempoolinfo",
706 [ + - ]: 7218 : "Returns details on the active state of the TX memory pool.",
707 : : {},
708 [ + - ]: 7218 : RPCResult{
709 [ + - ]: 7218 : RPCResult::Type::OBJ, "", "",
710 : : {
711 [ + - + - ]: 7218 : {RPCResult::Type::BOOL, "loaded", "True if the initial load attempt of the persisted mempool finished"},
712 [ + - + - ]: 7218 : {RPCResult::Type::NUM, "size", "Current tx count"},
713 [ + - + - ]: 7218 : {RPCResult::Type::NUM, "bytes", "Sum of all virtual transaction sizes as defined in BIP 141. Differs from actual serialized size because witness data is discounted"},
714 [ + - + - ]: 7218 : {RPCResult::Type::NUM, "usage", "Total memory usage for the mempool"},
715 [ + - + - ]: 7218 : {RPCResult::Type::STR_AMOUNT, "total_fee", "Total fees for the mempool in " + CURRENCY_UNIT + ", ignoring modified fees through prioritisetransaction"},
716 [ + - + - ]: 7218 : {RPCResult::Type::NUM, "maxmempool", "Maximum memory usage for the mempool"},
717 [ + - + - ]: 7218 : {RPCResult::Type::STR_AMOUNT, "mempoolminfee", "Minimum fee rate in " + CURRENCY_UNIT + "/kvB for tx to be accepted. Is the maximum of minrelaytxfee and minimum mempool fee"},
718 [ + - + - ]: 7218 : {RPCResult::Type::STR_AMOUNT, "minrelaytxfee", "Current minimum relay fee for transactions"},
719 [ + - + - ]: 7218 : {RPCResult::Type::NUM, "incrementalrelayfee", "minimum fee rate increment for mempool limiting or replacement in " + CURRENCY_UNIT + "/kvB"},
720 [ + - + - ]: 7218 : {RPCResult::Type::NUM, "unbroadcastcount", "Current number of transactions that haven't passed initial broadcast yet"},
721 [ + - + - ]: 7218 : {RPCResult::Type::BOOL, "fullrbf", "True if the mempool accepts RBF without replaceability signaling inspection (DEPRECATED)"},
722 [ + - + - ]: 7218 : {RPCResult::Type::BOOL, "permitbaremultisig", "True if the mempool accepts transactions with bare multisig outputs"},
723 [ + - + - ]: 7218 : {RPCResult::Type::NUM, "maxdatacarriersize", "Maximum number of bytes that can be used by OP_RETURN outputs in the mempool"},
724 [ + - + - : 97443 : }},
+ + - - ]
725 : 3609 : RPCExamples{
726 [ + - + - : 7218 : HelpExampleCli("getmempoolinfo", "")
+ - ]
727 [ + - + - : 14436 : + HelpExampleRpc("getmempoolinfo", "")
+ - + - ]
728 [ + - ]: 3609 : },
729 : 3609 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
730 : : {
731 : 1265 : return MempoolInfoToJSON(EnsureAnyMemPool(request.context));
732 : : },
733 [ + - + - ]: 14436 : };
734 [ + - + - : 46917 : }
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - - - ]
735 : :
736 : 2347 : static RPCHelpMan importmempool()
737 : : {
738 : 2347 : return RPCHelpMan{
739 : 2347 : "importmempool",
740 [ + - ]: 4694 : "Import a mempool.dat file and attempt to add its contents to the mempool.\n"
741 : : "Warning: Importing untrusted files is dangerous, especially if metadata from the file is taken over.",
742 : : {
743 [ + - + - ]: 4694 : {"filepath", RPCArg::Type::STR, RPCArg::Optional::NO, "The mempool file"},
744 [ + - ]: 4694 : {"options",
745 : : RPCArg::Type::OBJ_NAMED_PARAMS,
746 : 2347 : RPCArg::Optional::OMITTED,
747 [ + - ]: 4694 : "",
748 : : {
749 [ + - + - ]: 4694 : {"use_current_time", RPCArg::Type::BOOL, RPCArg::Default{true},
750 [ + - ]: 4694 : "Whether to use the current system time or use the entry time metadata from the mempool file.\n"
751 : : "Warning: Importing untrusted metadata may lead to unexpected issues and undesirable behavior."},
752 [ + - + - ]: 4694 : {"apply_fee_delta_priority", RPCArg::Type::BOOL, RPCArg::Default{false},
753 [ + - ]: 4694 : "Whether to apply the fee delta metadata from the mempool file.\n"
754 : : "It will be added to any existing fee deltas.\n"
755 : : "The fee delta can be set by the prioritisetransaction RPC.\n"
756 : : "Warning: Importing untrusted metadata may lead to unexpected issues and undesirable behavior.\n"
757 : : "Only set this bool if you understand what it does."},
758 [ + - + - ]: 4694 : {"apply_unbroadcast_set", RPCArg::Type::BOOL, RPCArg::Default{false},
759 [ + - ]: 4694 : "Whether to apply the unbroadcast set metadata from the mempool file.\n"
760 : : "Warning: Importing untrusted metadata may lead to unexpected issues and undesirable behavior."},
761 : : },
762 [ + - ]: 2347 : RPCArgOptions{.oneline_description = "options"}},
763 : : },
764 [ + - + - : 4694 : RPCResult{RPCResult::Type::OBJ, "", "", std::vector<RPCResult>{}},
+ - + - ]
765 [ + - + - : 7041 : RPCExamples{HelpExampleCli("importmempool", "/path/to/mempool.dat") + HelpExampleRpc("importmempool", "/path/to/mempool.dat")},
+ - + - +
- + - + -
+ - ]
766 : 2347 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue {
767 : 3 : const NodeContext& node{EnsureAnyNodeContext(request.context)};
768 : :
769 : 3 : CTxMemPool& mempool{EnsureMemPool(node)};
770 : 3 : ChainstateManager& chainman = EnsureChainman(node);
771 : 3 : Chainstate& chainstate = chainman.ActiveChainstate();
772 : :
773 [ - + ]: 3 : if (chainman.IsInitialBlockDownload()) {
774 [ # # # # ]: 0 : throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Can only import the mempool after the block download and sync is done.");
775 : : }
776 : :
777 : 3 : const fs::path load_path{fs::u8path(self.Arg<std::string_view>("filepath"))};
778 [ + - + - : 3 : const UniValue& use_current_time{request.params[1]["use_current_time"]};
+ - ]
779 [ + - + - : 3 : const UniValue& apply_fee_delta{request.params[1]["apply_fee_delta_priority"]};
+ - ]
780 [ + - + - : 3 : const UniValue& apply_unbroadcast{request.params[1]["apply_unbroadcast_set"]};
+ - ]
781 [ - + ]: 3 : node::ImportMempoolOptions opts{
782 [ - + - - ]: 3 : .use_current_time = use_current_time.isNull() ? true : use_current_time.get_bool(),
783 [ + + + - ]: 3 : .apply_fee_delta_priority = apply_fee_delta.isNull() ? false : apply_fee_delta.get_bool(),
784 [ + + + - ]: 3 : .apply_unbroadcast_set = apply_unbroadcast.isNull() ? false : apply_unbroadcast.get_bool(),
785 [ - + + + : 5 : };
+ + ]
786 : :
787 [ + - - + ]: 3 : if (!node::LoadMempool(mempool, load_path, chainstate, std::move(opts))) {
788 [ # # # # ]: 0 : throw JSONRPCError(RPC_MISC_ERROR, "Unable to import mempool file, see debug.log for details.");
789 : : }
790 : :
791 : 3 : UniValue ret{UniValue::VOBJ};
792 : 3 : return ret;
793 : 6 : },
794 [ + - + - : 25817 : };
+ - + + +
+ - - -
- ]
795 [ + - + - : 21123 : }
+ - + - +
- - - -
- ]
796 : :
797 : 2348 : static RPCHelpMan savemempool()
798 : : {
799 : 2348 : return RPCHelpMan{
800 : 2348 : "savemempool",
801 [ + - ]: 4696 : "Dumps the mempool to disk. It will fail until the previous dump is fully loaded.\n",
802 : : {},
803 [ + - ]: 4696 : RPCResult{
804 [ + - ]: 4696 : RPCResult::Type::OBJ, "", "",
805 : : {
806 [ + - + - ]: 4696 : {RPCResult::Type::STR, "filename", "the directory and file where the mempool was saved"},
807 [ + - + - : 7044 : }},
+ + - - ]
808 : 2348 : RPCExamples{
809 [ + - + - : 4696 : HelpExampleCli("savemempool", "")
+ - ]
810 [ + - + - : 9392 : + HelpExampleRpc("savemempool", "")
+ - + - ]
811 [ + - ]: 2348 : },
812 : 2348 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
813 : : {
814 : 4 : const ArgsManager& args{EnsureAnyArgsman(request.context)};
815 : 4 : const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
816 : :
817 [ - + ]: 4 : if (!mempool.GetLoadTried()) {
818 [ # # # # ]: 0 : throw JSONRPCError(RPC_MISC_ERROR, "The mempool was not loaded yet");
819 : : }
820 : :
821 : 4 : const fs::path& dump_path = MempoolPath(args);
822 : :
823 [ + - + + ]: 4 : if (!DumpMempool(mempool, dump_path)) {
824 [ + - + - ]: 2 : throw JSONRPCError(RPC_MISC_ERROR, "Unable to dump mempool to disk");
825 : : }
826 : :
827 : 3 : UniValue ret(UniValue::VOBJ);
828 [ + - + - : 6 : ret.pushKV("filename", dump_path.utf8string());
+ - + - ]
829 : :
830 : 6 : return ret;
831 : 0 : },
832 [ + - + - ]: 9392 : };
833 [ + - ]: 2348 : }
834 : :
835 : 5110 : static std::vector<RPCResult> OrphanDescription()
836 : : {
837 : 5110 : return {
838 [ + - + - ]: 10220 : RPCResult{RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
839 [ + - + - ]: 10220 : RPCResult{RPCResult::Type::STR_HEX, "wtxid", "The transaction witness hash in hex"},
840 [ + - + - ]: 10220 : RPCResult{RPCResult::Type::NUM, "bytes", "The serialized transaction size in bytes"},
841 [ + - + - ]: 10220 : RPCResult{RPCResult::Type::NUM, "vsize", "The virtual transaction size as defined in BIP 141. This is different from actual serialized size for witness transactions as witness data is discounted."},
842 [ + - + - ]: 10220 : RPCResult{RPCResult::Type::NUM, "weight", "The transaction weight as defined in BIP 141."},
843 [ + - + - ]: 10220 : RPCResult{RPCResult::Type::ARR, "from", "",
844 : : {
845 [ + - + - ]: 10220 : RPCResult{RPCResult::Type::NUM, "peer_id", "Peer ID"},
846 [ + - + + : 15330 : }},
- - ]
847 [ + - + + : 45990 : };
- - ]
848 [ + - + - : 35770 : }
+ - + - +
- + - + -
- - ]
849 : :
850 : 42 : static UniValue OrphanToJSON(const node::TxOrphanage::OrphanInfo& orphan)
851 : : {
852 : 42 : UniValue o(UniValue::VOBJ);
853 [ + - + - : 84 : o.pushKV("txid", orphan.tx->GetHash().ToString());
+ - + - ]
854 [ + - + - : 84 : o.pushKV("wtxid", orphan.tx->GetWitnessHash().ToString());
+ - + - ]
855 [ + - + - : 84 : o.pushKV("bytes", orphan.tx->GetTotalSize());
+ - + - ]
856 [ + - + - : 84 : o.pushKV("vsize", GetVirtualTransactionSize(*orphan.tx));
+ - + - ]
857 [ + - + - : 84 : o.pushKV("weight", GetTransactionWeight(*orphan.tx));
+ - ]
858 : 42 : UniValue from(UniValue::VARR);
859 [ + + ]: 90 : for (const auto fromPeer: orphan.announcers) {
860 [ + - + - ]: 48 : from.push_back(fromPeer);
861 : : }
862 [ + - + - : 84 : o.pushKV("from", from);
+ - ]
863 : 42 : return o;
864 : 42 : }
865 : :
866 : 2555 : static RPCHelpMan getorphantxs()
867 : : {
868 : 2555 : return RPCHelpMan{
869 : 2555 : "getorphantxs",
870 [ + - ]: 5110 : "Shows transactions in the tx orphanage.\n"
871 : : "\nEXPERIMENTAL warning: this call may be changed in future releases.\n",
872 : : {
873 [ + - + - : 7665 : {"verbosity", RPCArg::Type::NUM, RPCArg::Default{0}, "0 for an array of txids (may contain duplicates), 1 for an array of objects with tx details, and 2 for details from (1) and tx hex",
+ - ]
874 [ + - ]: 5110 : RPCArgOptions{.skip_type_check = true}},
875 : : },
876 : : {
877 [ + - ]: 2555 : RPCResult{"for verbose = 0",
878 [ + - + - ]: 5110 : RPCResult::Type::ARR, "", "",
879 : : {
880 [ + - + - ]: 5110 : {RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
881 [ + - + + : 7665 : }},
- - ]
882 [ + - ]: 5110 : RPCResult{"for verbose = 1",
883 [ + - + - ]: 5110 : RPCResult::Type::ARR, "", "",
884 : : {
885 [ + - + - : 5110 : {RPCResult::Type::OBJ, "", "", OrphanDescription()},
+ - ]
886 [ + - + + : 7665 : }},
- - ]
887 [ + - ]: 5110 : RPCResult{"for verbose = 2",
888 [ + - + - ]: 5110 : RPCResult::Type::ARR, "", "",
889 : : {
890 [ + - + - ]: 5110 : {RPCResult::Type::OBJ, "", "",
891 [ + - + - : 12775 : Cat<std::vector<RPCResult>>(
+ + - - ]
892 [ + - ]: 5110 : OrphanDescription(),
893 [ + - + - ]: 5110 : {{RPCResult::Type::STR_HEX, "hex", "The serialized, hex-encoded transaction data"}}
894 : : )
895 : : },
896 [ + - + + : 7665 : }},
- - ]
897 : : },
898 : 2555 : RPCExamples{
899 [ + - + - : 5110 : HelpExampleCli("getorphantxs", "2")
+ - ]
900 [ + - + - : 10220 : + HelpExampleRpc("getorphantxs", "2")
+ - ]
901 [ + - ]: 2555 : },
902 : 2555 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
903 : : {
904 : 219 : const NodeContext& node = EnsureAnyNodeContext(request.context);
905 : 219 : PeerManager& peerman = EnsurePeerman(node);
906 : 219 : std::vector<node::TxOrphanage::OrphanInfo> orphanage = peerman.GetOrphanTransactions();
907 : :
908 [ + - + + ]: 219 : int verbosity{ParseVerbosity(request.params[0], /*default_verbosity=*/0, /*allow_bool*/false)};
909 : :
910 : 217 : UniValue ret(UniValue::VARR);
911 : :
912 [ + + ]: 217 : if (verbosity == 0) {
913 [ + + ]: 18481 : for (auto const& orphan : orphanage) {
914 [ + - + - : 18298 : ret.push_back(orphan.tx->GetHash().ToString());
+ - ]
915 : : }
916 [ + + ]: 34 : } else if (verbosity == 1) {
917 [ + + ]: 55 : for (auto const& orphan : orphanage) {
918 [ + - + - ]: 32 : ret.push_back(OrphanToJSON(orphan));
919 : : }
920 [ + + ]: 11 : } else if (verbosity == 2) {
921 [ + + ]: 19 : for (auto const& orphan : orphanage) {
922 [ + - ]: 10 : UniValue o{OrphanToJSON(orphan)};
923 [ + - + - : 20 : o.pushKV("hex", EncodeHexTx(*orphan.tx));
+ - + - ]
924 [ + - + - ]: 10 : ret.push_back(o);
925 : 10 : }
926 : : } else {
927 [ + - + - : 4 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid verbosity value " + ToString(verbosity));
+ - ]
928 : : }
929 : :
930 : 215 : return ret;
931 : 221 : },
932 [ + - + - : 28105 : };
+ - + - +
+ + + - -
- - ]
933 [ + - + - : 20440 : }
+ - + - +
- + - + -
+ - - - ]
934 : :
935 : 2462 : static RPCHelpMan submitpackage()
936 : : {
937 : 2462 : return RPCHelpMan{"submitpackage",
938 [ + - ]: 4924 : "Submit a package of raw transactions (serialized, hex-encoded) to local node.\n"
939 : : "The package will be validated according to consensus and mempool policy rules. If any transaction passes, it will be accepted to mempool.\n"
940 : : "This RPC is experimental and the interface may be unstable. Refer to doc/policy/packages.md for documentation on package policies.\n"
941 : : "Warning: successful submission does not mean the transactions will propagate throughout the network.\n"
942 : : ,
943 : : {
944 [ + - + - ]: 4924 : {"package", RPCArg::Type::ARR, RPCArg::Optional::NO, "An array of raw transactions.\n"
945 : : "The package must consist of a transaction with (some, all, or none of) its unconfirmed parents. A single transaction is permitted.\n"
946 : : "None of the parents may depend on each other. Parents that are already in mempool do not need to be present in the package.\n"
947 : : "The package must be topologically sorted, with the child being the last element in the array if there are multiple elements.",
948 : : {
949 [ + - + - ]: 4924 : {"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
950 : : },
951 : : },
952 [ + - + - : 4924 : {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())},
+ - ]
953 [ + - ]: 4924 : "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT +
954 : 2462 : "/kvB.\nFee rates larger than 1BTC/kvB are rejected.\nSet to 0 to accept any fee rate."},
955 [ + - + - : 4924 : {"maxburnamount", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_BURN_AMOUNT)},
+ - ]
956 [ + - ]: 4924 : "Reject transactions with provably unspendable outputs (e.g. 'datacarrier' outputs that use the OP_RETURN opcode) greater than the specified value, expressed in " + CURRENCY_UNIT + ".\n"
957 : : "If burning funds through unspendable outputs is desired, increase this value.\n"
958 : 2462 : "This check is based on heuristics and does not guarantee spendability of outputs.\n"
959 : : },
960 : : },
961 [ + - ]: 4924 : RPCResult{
962 [ + - + - ]: 4924 : RPCResult::Type::OBJ, "", "",
963 : : {
964 [ + - + - ]: 4924 : {RPCResult::Type::STR, "package_msg", "The transaction package result message. \"success\" indicates all transactions were accepted into or are already in the mempool."},
965 [ + - + - ]: 4924 : {RPCResult::Type::OBJ_DYN, "tx-results", "The transaction results keyed by wtxid. An entry is returned for every submitted wtxid.",
966 : : {
967 [ + - + - ]: 4924 : {RPCResult::Type::OBJ, "wtxid", "transaction wtxid", {
968 [ + - + - ]: 4924 : {RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
969 [ + - + - ]: 4924 : {RPCResult::Type::STR_HEX, "other-wtxid", /*optional=*/true, "The wtxid of a different transaction with the same txid but different witness found in the mempool. This means the submitted transaction was ignored."},
970 [ + - + - ]: 4924 : {RPCResult::Type::NUM, "vsize", /*optional=*/true, "Sigops-adjusted virtual transaction size."},
971 [ + - + - ]: 4924 : {RPCResult::Type::OBJ, "fees", /*optional=*/true, "Transaction fees", {
972 [ + - + - ]: 4924 : {RPCResult::Type::STR_AMOUNT, "base", "transaction fee in " + CURRENCY_UNIT},
973 [ + - + - ]: 4924 : {RPCResult::Type::STR_AMOUNT, "effective-feerate", /*optional=*/true, "if the transaction was not already in the mempool, the effective feerate in " + CURRENCY_UNIT + " per KvB. For example, the package feerate and/or feerate with modified fees from prioritisetransaction."},
974 [ + - + - ]: 4924 : {RPCResult::Type::ARR, "effective-includes", /*optional=*/true, "if effective-feerate is provided, the wtxids of the transactions whose fees and vsizes are included in effective-feerate.",
975 [ + - + - ]: 4924 : {{RPCResult::Type::STR_HEX, "", "transaction wtxid in hex"},
976 : : }},
977 : : }},
978 [ + - + - ]: 4924 : {RPCResult::Type::STR, "error", /*optional=*/true, "Error string if rejected from mempool, or \"package-not-validated\" when the package aborts before any per-tx processing."},
979 : : }}
980 : : }},
981 [ + - + - ]: 4924 : {RPCResult::Type::ARR, "replaced-transactions", /*optional=*/true, "List of txids of replaced transactions",
982 : : {
983 [ + - + - ]: 4924 : {RPCResult::Type::STR_HEX, "", "The transaction id"},
984 : : }},
985 : : },
986 [ + - + - : 71398 : },
+ - + - +
- + - + -
+ + + + +
+ + + + +
+ + - - -
- - - - -
- - - - ]
987 : 2462 : RPCExamples{
988 [ + - + - : 4924 : HelpExampleRpc("submitpackage", R"(["raw-parent-tx-1", "raw-parent-tx-2", "raw-child-tx"])") +
+ - ]
989 [ + - + - : 7386 : HelpExampleCli("submitpackage", R"('["raw-tx-without-unconfirmed-parents"]')")
+ - + - ]
990 [ + - ]: 2462 : },
991 : 2462 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
992 : : {
993 : 118 : const UniValue raw_transactions = request.params[0].get_array();
994 [ - + + + : 118 : if (raw_transactions.empty() || raw_transactions.size() > MAX_PACKAGE_COUNT) {
+ + ]
995 : 2 : throw JSONRPCError(RPC_INVALID_PARAMETER,
996 [ + - + - : 6 : "Array must contain between 1 and " + ToString(MAX_PACKAGE_COUNT) + " transactions.");
+ - ]
997 : : }
998 : :
999 : : // Fee check needs to be run with chainstate and package context
1000 [ + - + - ]: 116 : const CFeeRate max_raw_tx_fee_rate{ParseFeeRate(self.Arg<UniValue>("maxfeerate"))};
1001 [ + + ]: 116 : std::optional<CFeeRate> client_maxfeerate{max_raw_tx_fee_rate};
1002 : : // 0-value is special; it's mapped to no sanity check
1003 [ + + ]: 116 : if (max_raw_tx_fee_rate == CFeeRate(0)) {
1004 : 23 : client_maxfeerate = std::nullopt;
1005 : : }
1006 : :
1007 : : // Burn sanity check is run with no context
1008 [ + - + + : 116 : const CAmount max_burn_amount = request.params[2].isNull() ? 0 : AmountFromValue(request.params[2]);
+ - + - ]
1009 : :
1010 : 116 : std::vector<CTransactionRef> txns;
1011 [ - + + - ]: 116 : txns.reserve(raw_transactions.size());
1012 [ + - + + ]: 495 : for (const auto& rawtx : raw_transactions.getValues()) {
1013 [ + - ]: 381 : CMutableTransaction mtx;
1014 [ + - + - : 381 : if (!DecodeHexTx(mtx, rawtx.get_str())) {
+ + ]
1015 : 1 : throw JSONRPCError(RPC_DESERIALIZATION_ERROR,
1016 [ + - + - : 3 : "TX decode failed: " + rawtx.get_str() + " Make sure the tx has at least one input.");
+ - ]
1017 : : }
1018 : :
1019 [ + + ]: 895 : for (const auto& out : mtx.vout) {
1020 [ + + + - : 516 : if((out.scriptPubKey.IsUnspendable() || !out.scriptPubKey.HasValidOps()) && out.nValue > max_burn_amount) {
- + + + ]
1021 [ + - + - ]: 2 : throw JSONRPCTransactionError(TransactionError::MAX_BURN_EXCEEDED);
1022 : : }
1023 : : }
1024 : :
1025 [ + - + - ]: 1137 : txns.emplace_back(MakeTransactionRef(std::move(mtx)));
1026 : 381 : }
1027 [ + - ]: 114 : CHECK_NONFATAL(!txns.empty());
1028 [ - + + + : 114 : if (txns.size() > 1 && !IsChildWithParentsTree(txns)) {
+ - + + ]
1029 [ + - + - ]: 4 : throw JSONRPCTransactionError(TransactionError::INVALID_PACKAGE, "package topology disallowed. not child-with-parents or parents depend on each other.");
1030 : : }
1031 : :
1032 [ + - ]: 112 : NodeContext& node = EnsureAnyNodeContext(request.context);
1033 [ + - ]: 112 : CTxMemPool& mempool = EnsureMemPool(node);
1034 [ + - + - ]: 112 : Chainstate& chainstate = EnsureChainman(node).ActiveChainstate();
1035 [ + - + - ]: 336 : const auto package_result = WITH_LOCK(::cs_main, return ProcessNewPackage(chainstate, mempool, txns, /*test_accept=*/ false, client_maxfeerate));
1036 : :
1037 [ + - ]: 112 : std::string package_msg = "success";
1038 : :
1039 : : // First catch package-wide errors, continue if we can
1040 [ + - + - ]: 112 : switch(package_result.m_state.GetResult()) {
1041 : 51 : case PackageValidationResult::PCKG_RESULT_UNSET:
1042 : 51 : {
1043 : : // Belt-and-suspenders check; everything should be successful here
1044 [ - + + - ]: 51 : CHECK_NONFATAL(package_result.m_tx_results.size() == txns.size());
1045 [ + + ]: 248 : for (const auto& tx : txns) {
1046 [ + - + - ]: 197 : CHECK_NONFATAL(mempool.exists(tx->GetHash()));
1047 : : }
1048 : : break;
1049 : : }
1050 : 0 : case PackageValidationResult::PCKG_MEMPOOL_ERROR:
1051 : 0 : {
1052 : : // This only happens with internal bug; user should stop and report
1053 : 0 : throw JSONRPCTransactionError(TransactionError::MEMPOOL_ERROR,
1054 [ # # # # ]: 0 : package_result.m_state.GetRejectReason());
1055 : : }
1056 : 61 : case PackageValidationResult::PCKG_POLICY:
1057 : 61 : case PackageValidationResult::PCKG_TX:
1058 : 61 : {
1059 : : // Package-wide error we want to return, but we also want to return individual responses
1060 [ + - ]: 61 : package_msg = package_result.m_state.ToString();
1061 [ - + + + : 63 : CHECK_NONFATAL(package_result.m_tx_results.size() == txns.size() ||
+ - + - ]
1062 : : package_result.m_tx_results.empty());
1063 : : break;
1064 : : }
1065 : : }
1066 : :
1067 : 112 : size_t num_broadcast{0};
1068 [ + + ]: 483 : for (const auto& tx : txns) {
1069 : : // We don't want to re-submit the txn for validation in BroadcastTransaction
1070 [ + - + + ]: 371 : if (!mempool.exists(tx->GetHash())) {
1071 : 116 : continue;
1072 : : }
1073 : :
1074 : : // We do not expect an error here; we are only broadcasting things already/still in mempool
1075 [ + - ]: 255 : std::string err_string;
1076 [ + - + - ]: 255 : const auto err = BroadcastTransaction(node,
1077 : : tx,
1078 : : err_string,
1079 [ + - ]: 255 : /*max_tx_fee=*/0,
1080 : : node::TxBroadcast::MEMPOOL_AND_BROADCAST_TO_ALL,
1081 : : /*wait_callback=*/true);
1082 [ - + ]: 255 : if (err != TransactionError::OK) {
1083 : 0 : throw JSONRPCTransactionError(err,
1084 [ # # ]: 0 : strprintf("transaction broadcast failed: %s (%d transactions were broadcast successfully)",
1085 [ # # ]: 0 : err_string, num_broadcast));
1086 : : }
1087 : 255 : num_broadcast++;
1088 : 255 : }
1089 : :
1090 : 112 : UniValue rpc_result{UniValue::VOBJ};
1091 [ + - + - : 224 : rpc_result.pushKV("package_msg", package_msg);
+ - ]
1092 : 224 : UniValue tx_result_map{UniValue::VOBJ};
1093 : 224 : std::set<Txid> replaced_txids;
1094 [ + + ]: 483 : for (const auto& tx : txns) {
1095 : 371 : UniValue result_inner{UniValue::VOBJ};
1096 [ + - + - : 742 : result_inner.pushKV("txid", tx->GetHash().GetHex());
+ - + - ]
1097 [ + - ]: 371 : const auto wtxid_hex = tx->GetWitnessHash().GetHex();
1098 : 371 : auto it = package_result.m_tx_results.find(tx->GetWitnessHash());
1099 [ + + ]: 371 : if (it == package_result.m_tx_results.end()) {
1100 : : // No per-tx result for this wtxid
1101 : : // Current invariant: per-tx results are all-or-none (every member or empty on package abort).
1102 : : // If any exist yet this one is missing, it's an unexpected partial map.
1103 [ + - ]: 6 : CHECK_NONFATAL(package_result.m_tx_results.empty());
1104 [ + - + - : 12 : result_inner.pushKV("error", "package-not-validated");
+ - ]
1105 [ - + + - ]: 18 : tx_result_map.pushKV(wtxid_hex, std::move(result_inner));
1106 : 6 : continue;
1107 : : }
1108 [ - + + - ]: 365 : const auto& tx_result = it->second;
1109 [ - + + - ]: 365 : switch(it->second.m_result_type) {
1110 : 0 : case MempoolAcceptResult::ResultType::DIFFERENT_WITNESS:
1111 [ # # # # : 0 : result_inner.pushKV("other-wtxid", it->second.m_other_wtxid.value().GetHex());
# # # # #
# ]
1112 : 0 : break;
1113 : 111 : case MempoolAcceptResult::ResultType::INVALID:
1114 [ + - + - : 222 : result_inner.pushKV("error", it->second.m_state.ToString());
+ - + - ]
1115 : 111 : break;
1116 : 254 : case MempoolAcceptResult::ResultType::VALID:
1117 : 254 : case MempoolAcceptResult::ResultType::MEMPOOL_ENTRY:
1118 [ + - + - : 508 : result_inner.pushKV("vsize", int64_t{it->second.m_vsize.value()});
+ - + - ]
1119 : 254 : UniValue fees(UniValue::VOBJ);
1120 [ + - + - : 508 : fees.pushKV("base", ValueFromAmount(it->second.m_base_fees.value()));
+ - + - ]
1121 [ + + ]: 254 : if (tx_result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
1122 : : // Effective feerate is not provided for MEMPOOL_ENTRY transactions even
1123 : : // though modified fees is known, because it is unknown whether package
1124 : : // feerate was used when it was originally submitted.
1125 [ + - + - : 330 : fees.pushKV("effective-feerate", ValueFromAmount(tx_result.m_effective_feerate.value().GetFeePerK()));
+ - + - ]
1126 : 165 : UniValue effective_includes_res(UniValue::VARR);
1127 [ + - + + ]: 376 : for (const auto& wtxid : tx_result.m_wtxids_fee_calculations.value()) {
1128 [ + - + - : 211 : effective_includes_res.push_back(wtxid.ToString());
+ - ]
1129 : : }
1130 [ + - + - ]: 330 : fees.pushKV("effective-includes", std::move(effective_includes_res));
1131 : 165 : }
1132 [ + - + - ]: 508 : result_inner.pushKV("fees", std::move(fees));
1133 [ + + ]: 369 : for (const auto& ptx : it->second.m_replaced_transactions) {
1134 [ + - ]: 115 : replaced_txids.insert(ptx->GetHash());
1135 : : }
1136 : 254 : break;
1137 : : }
1138 [ - + + - ]: 1095 : tx_result_map.pushKV(wtxid_hex, std::move(result_inner));
1139 : 371 : }
1140 [ + - + - ]: 224 : rpc_result.pushKV("tx-results", std::move(tx_result_map));
1141 : 224 : UniValue replaced_list(UniValue::VARR);
1142 [ + - + - : 227 : for (const auto& txid : replaced_txids) replaced_list.push_back(txid.ToString());
+ - + + ]
1143 [ + - + - ]: 224 : rpc_result.pushKV("replaced-transactions", std::move(replaced_list));
1144 : 224 : return rpc_result;
1145 : 122 : },
1146 [ + - + - : 24620 : };
+ - + + +
+ - - -
- ]
1147 [ + - + - : 54164 : }
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - - - -
- - - -
- ]
1148 : :
1149 : 1299 : void RegisterMempoolRPCCommands(CRPCTable& t)
1150 : : {
1151 : 1299 : static const CRPCCommand commands[]{
1152 [ + - ]: 2334 : {"rawtransactions", &sendrawtransaction},
1153 [ + - ]: 2334 : {"rawtransactions", &testmempoolaccept},
1154 [ + - ]: 2334 : {"blockchain", &getmempoolancestors},
1155 [ + - ]: 2334 : {"blockchain", &getmempooldescendants},
1156 [ + - ]: 2334 : {"blockchain", &getmempoolentry},
1157 [ + - ]: 2334 : {"blockchain", &gettxspendingprevout},
1158 [ + - ]: 2334 : {"blockchain", &getmempoolinfo},
1159 [ + - ]: 2334 : {"blockchain", &getrawmempool},
1160 [ + - ]: 2334 : {"blockchain", &importmempool},
1161 [ + - ]: 2334 : {"blockchain", &savemempool},
1162 [ + - ]: 2334 : {"hidden", &getorphantxs},
1163 [ + - ]: 2334 : {"rawtransactions", &submitpackage},
1164 [ + + + - : 15303 : };
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - -
- ]
1165 [ + + ]: 16887 : for (const auto& c : commands) {
1166 : 15588 : t.appendCommand(c.name, &c);
1167 : : }
1168 : 1299 : }
|