Branch data Line data Source code
1 : : // Copyright (c) 2010 Satoshi Nakamoto
2 : : // Copyright (c) 2009-present 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 <common/args.h>
12 : : #include <consensus/validation.h>
13 : : #include <core_io.h>
14 : : #include <kernel/mempool_entry.h>
15 : : #include <net_processing.h>
16 : : #include <netbase.h>
17 : : #include <node/mempool_persist_args.h>
18 : : #include <node/types.h>
19 : : #include <policy/rbf.h>
20 : : #include <policy/settings.h>
21 : : #include <primitives/transaction.h>
22 : : #include <rpc/server.h>
23 : : #include <rpc/server_util.h>
24 : : #include <rpc/util.h>
25 : : #include <txmempool.h>
26 : : #include <univalue.h>
27 : : #include <util/fs.h>
28 : : #include <util/moneystr.h>
29 : : #include <util/strencodings.h>
30 : : #include <util/time.h>
31 : : #include <util/vector.h>
32 : :
33 : : #include <string_view>
34 : : #include <utility>
35 : :
36 : : using node::DumpMempool;
37 : :
38 : : using node::DEFAULT_MAX_BURN_AMOUNT;
39 : : using node::DEFAULT_MAX_RAW_TX_FEE_RATE;
40 : : using node::MempoolPath;
41 : : using node::NodeContext;
42 : : using node::TransactionError;
43 : : using util::ToString;
44 : :
45 : 26304 : static RPCHelpMan sendrawtransaction()
46 : : {
47 : 26304 : return RPCHelpMan{
48 : 26304 : "sendrawtransaction",
49 [ + - ]: 52608 : "Submit a raw transaction (serialized, hex-encoded) to the network.\n"
50 : :
51 : : "\nIf -privatebroadcast is disabled, then the transaction will be put into the\n"
52 : : "local mempool of the node and will be sent unconditionally to all currently\n"
53 : : "connected peers, so using sendrawtransaction for manual rebroadcast will degrade\n"
54 : : "privacy by leaking the transaction's origin, as nodes will normally not\n"
55 : : "rebroadcast non-wallet transactions already in their mempool.\n"
56 : :
57 : : "\nIf -privatebroadcast is enabled, then the transaction will be sent only via\n"
58 : : "dedicated, short-lived connections to Tor or I2P peers or IPv4/IPv6 peers\n"
59 : : "via the Tor network. This conceals the transaction's origin. The transaction\n"
60 : : "will only enter the local mempool when it is received back from the network.\n"
61 : :
62 : : "\nA specific exception, RPC_TRANSACTION_ALREADY_IN_UTXO_SET, may throw if the transaction cannot be added to the mempool.\n"
63 : :
64 : : "\nRelated RPCs: createrawtransaction, signrawtransactionwithkey\n",
65 : : {
66 [ + - + - ]: 52608 : {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"},
67 [ + - + - : 52608 : {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())},
+ - ]
68 [ + - ]: 52608 : "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT +
69 : 26304 : "/kvB.\nFee rates larger than 1BTC/kvB are rejected.\nSet to 0 to accept any fee rate."},
70 [ + - + - : 52608 : {"maxburnamount", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_BURN_AMOUNT)},
+ - ]
71 [ + - ]: 52608 : "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"
72 : : "If burning funds through unspendable outputs is desired, increase this value.\n"
73 : 26304 : "This check is based on heuristics and does not guarantee spendability of outputs.\n"},
74 : : },
75 [ + - ]: 52608 : RPCResult{
76 [ + - + - ]: 52608 : RPCResult::Type::STR_HEX, "", "The transaction hash in hex"
77 [ + - ]: 52608 : },
78 : 26304 : RPCExamples{
79 : : "\nCreate a transaction\n"
80 [ + - + - : 52608 : + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") +
+ - + - ]
81 : 26304 : "Sign the transaction, and get back the hex\n"
82 [ + - + - : 105216 : + HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") +
+ - + - ]
83 : 26304 : "\nSend the transaction (signed hex)\n"
84 [ + - + - : 105216 : + HelpExampleCli("sendrawtransaction", "\"signedhex\"") +
+ - + - ]
85 : 26304 : "\nAs a JSON-RPC call\n"
86 [ + - + - : 105216 : + HelpExampleRpc("sendrawtransaction", "\"signedhex\"")
+ - + - ]
87 [ + - ]: 26304 : },
88 : 26304 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
89 : : {
90 [ + + ]: 23922 : const CAmount max_burn_amount = request.params[2].isNull() ? 0 : AmountFromValue(request.params[2]);
91 : :
92 : 23922 : CMutableTransaction mtx;
93 [ + - + - : 23922 : if (!DecodeHexTx(mtx, request.params[0].get_str())) {
+ - + + ]
94 [ + - + - ]: 4 : throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input.");
95 : : }
96 : :
97 [ + + ]: 84220 : for (const auto& out : mtx.vout) {
98 [ + + + - : 60304 : if((out.scriptPubKey.IsUnspendable() || !out.scriptPubKey.HasValidOps()) && out.nValue > max_burn_amount) {
+ + + + ]
99 [ + - + - ]: 8 : throw JSONRPCTransactionError(TransactionError::MAX_BURN_EXCEEDED);
100 : : }
101 : : }
102 : :
103 [ + - ]: 23916 : CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
104 : :
105 [ + - + - ]: 23916 : const CFeeRate max_raw_tx_fee_rate{ParseFeeRate(self.Arg<UniValue>("maxfeerate"))};
106 : :
107 [ + - ]: 23916 : int64_t virtual_size = GetVirtualTransactionSize(*tx);
108 [ + - ]: 23916 : CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size);
109 : :
110 [ + - ]: 23916 : std::string err_string;
111 : 23916 : AssertLockNotHeld(cs_main);
112 [ + - ]: 23916 : NodeContext& node = EnsureAnyNodeContext(request.context);
113 [ + - + - ]: 23916 : const bool private_broadcast_enabled{gArgs.GetBoolArg("-privatebroadcast", DEFAULT_PRIVATE_BROADCAST)};
114 [ + + ]: 10 : if (private_broadcast_enabled &&
115 [ + + + - : 23917 : !g_reachable_nets.Contains(NET_ONION) &&
- + ]
116 [ + - ]: 1 : !g_reachable_nets.Contains(NET_I2P)) {
117 : 1 : throw JSONRPCError(RPC_MISC_ERROR,
118 [ + - ]: 1 : "-privatebroadcast is enabled, but none of the Tor or I2P networks is "
119 : : "reachable. Maybe the location of the Tor proxy couldn't be retrieved "
120 : : "from the Tor daemon at startup. Check whether the Tor daemon is running "
121 [ + - ]: 3 : "and that -torcontrol, -torpassword and -i2psam are configured properly.");
122 : : }
123 [ + + ]: 23915 : const auto method = private_broadcast_enabled ? node::TxBroadcast::NO_MEMPOOL_PRIVATE_BROADCAST
124 : : : node::TxBroadcast::MEMPOOL_AND_BROADCAST_TO_ALL;
125 [ + - + - : 47830 : const TransactionError err = BroadcastTransaction(node,
+ - ]
126 : : tx,
127 : : err_string,
128 : : max_raw_tx_fee,
129 : : method,
130 : : /*wait_callback=*/true);
131 [ + + ]: 23915 : if (TransactionError::OK != err) {
132 [ + - ]: 4323 : throw JSONRPCTransactionError(err, err_string);
133 : : }
134 : :
135 [ + - + - ]: 39184 : return tx->GetHash().GetHex();
136 [ + - ]: 67424 : },
137 [ + - + - : 184128 : };
+ + - - ]
138 [ + - + - : 157824 : }
+ - - - ]
139 : :
140 : 3806 : static RPCHelpMan testmempoolaccept()
141 : : {
142 : 3806 : return RPCHelpMan{
143 : 3806 : "testmempoolaccept",
144 : : "Returns result of mempool acceptance tests indicating if raw transaction(s) (serialized, hex-encoded) would be accepted by mempool.\n"
145 : : "\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"
146 : : "\nIf one transaction fails, other transactions may not be fully validated (the 'allowed' key will be blank).\n"
147 [ + - + - ]: 7612 : "\nThe maximum number of transactions allowed is " + ToString(MAX_PACKAGE_COUNT) + ".\n"
148 : : "\nThis checks if transactions violate the consensus or policy rules.\n"
149 : 3806 : "\nSee sendrawtransaction call.\n",
150 : : {
151 [ + - + - ]: 7612 : {"rawtxs", RPCArg::Type::ARR, RPCArg::Optional::NO, "An array of hex strings of raw transactions.",
152 : : {
153 [ + - + - ]: 7612 : {"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
154 : : },
155 : : },
156 [ + - + - : 7612 : {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())},
+ - ]
157 [ + - ]: 7612 : "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT +
158 : 3806 : "/kvB.\nFee rates larger than 1BTC/kvB are rejected.\nSet to 0 to accept any fee rate."},
159 : : },
160 [ + - ]: 7612 : RPCResult{
161 [ + - + - ]: 7612 : RPCResult::Type::ARR, "", "The result of the mempool acceptance test for each raw transaction in the input array.\n"
162 : : "Returns results for each transaction in the same order they were passed in.\n"
163 : : "Transactions that cannot be fully validated due to failures in other transactions will not contain an 'allowed' result.\n",
164 : : {
165 [ + - + - ]: 7612 : {RPCResult::Type::OBJ, "", "",
166 : : {
167 [ + - + - ]: 7612 : {RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
168 [ + - + - ]: 7612 : {RPCResult::Type::STR_HEX, "wtxid", "The transaction witness hash in hex"},
169 [ + - + - ]: 7612 : {RPCResult::Type::STR, "package-error", /*optional=*/true, "Package validation error, if any (only possible if rawtxs had more than 1 transaction)."},
170 [ + - + - ]: 7612 : {RPCResult::Type::BOOL, "allowed", /*optional=*/true, "Whether this tx would be accepted to the mempool and pass client-specified maxfeerate. "
171 : : "If not present, the tx was not fully validated due to a failure in another tx in the list."},
172 [ + - + - ]: 7612 : {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)"},
173 [ + - + - ]: 7612 : {RPCResult::Type::OBJ, "fees", /*optional=*/true, "Transaction fees (only present if 'allowed' is true)",
174 : : {
175 [ + - + - ]: 7612 : {RPCResult::Type::STR_AMOUNT, "base", "transaction fee in " + CURRENCY_UNIT},
176 [ + - + - ]: 7612 : {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."},
177 [ + - + - ]: 7612 : {RPCResult::Type::ARR, "effective-includes", /*optional=*/false, "transactions whose fees and vsizes are included in effective-feerate.",
178 [ + - + - ]: 7612 : {RPCResult{RPCResult::Type::STR_HEX, "", "transaction wtxid in hex"},
179 : : }},
180 : : }},
181 [ + - + - ]: 7612 : {RPCResult::Type::STR, "reject-reason", /*optional=*/true, "Rejection reason (only present when 'allowed' is false)"},
182 [ + - + - ]: 7612 : {RPCResult::Type::STR, "reject-details", /*optional=*/true, "Rejection details (only present when 'allowed' is false and rejection details exist)"},
183 : : }},
184 : : }
185 [ + - + - : 102762 : },
+ - + - +
- + + + +
+ + + + -
- - - - -
- - ]
186 : 3806 : RPCExamples{
187 : : "\nCreate a transaction\n"
188 [ + - + - : 7612 : + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") +
+ - + - ]
189 : 3806 : "Sign the transaction, and get back the hex\n"
190 [ + - + - : 15224 : + HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") +
+ - + - ]
191 : 3806 : "\nTest acceptance of the transaction (signed hex)\n"
192 [ + - + - : 15224 : + HelpExampleCli("testmempoolaccept", R"('["signedhex"]')") +
+ - + - ]
193 : 3806 : "\nAs a JSON-RPC call\n"
194 [ + - + - : 15224 : + HelpExampleRpc("testmempoolaccept", "[\"signedhex\"]")
+ - + - ]
195 [ + - ]: 3806 : },
196 : 3806 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
197 : : {
198 : 1424 : const UniValue raw_transactions = request.params[0].get_array();
199 [ - + + + : 1424 : if (raw_transactions.size() < 1 || raw_transactions.size() > MAX_PACKAGE_COUNT) {
+ + ]
200 : 2 : throw JSONRPCError(RPC_INVALID_PARAMETER,
201 [ + - + - : 6 : "Array must contain between 1 and " + ToString(MAX_PACKAGE_COUNT) + " transactions.");
+ - ]
202 : : }
203 : :
204 [ + - + + ]: 1422 : const CFeeRate max_raw_tx_fee_rate{ParseFeeRate(self.Arg<UniValue>("maxfeerate"))};
205 : :
206 : 1420 : std::vector<CTransactionRef> txns;
207 [ - + + - ]: 1420 : txns.reserve(raw_transactions.size());
208 [ + - + + ]: 3424 : for (const auto& rawtx : raw_transactions.getValues()) {
209 [ + - ]: 2005 : CMutableTransaction mtx;
210 [ + - + - : 2005 : if (!DecodeHexTx(mtx, rawtx.get_str())) {
+ + ]
211 : 1 : throw JSONRPCError(RPC_DESERIALIZATION_ERROR,
212 [ + - + - : 3 : "TX decode failed: " + rawtx.get_str() + " Make sure the tx has at least one input.");
+ - ]
213 : : }
214 [ + - + - ]: 6012 : txns.emplace_back(MakeTransactionRef(std::move(mtx)));
215 : 2005 : }
216 : :
217 [ + - ]: 1419 : NodeContext& node = EnsureAnyNodeContext(request.context);
218 [ + - ]: 1419 : CTxMemPool& mempool = EnsureMemPool(node);
219 [ + - ]: 1419 : ChainstateManager& chainman = EnsureChainman(node);
220 [ + - ]: 1419 : Chainstate& chainstate = chainman.ActiveChainstate();
221 : 2838 : const PackageMempoolAcceptResult package_result = [&] {
222 : 1419 : LOCK(::cs_main);
223 [ - + + + : 1419 : if (txns.size() > 1) return ProcessNewPackage(chainstate, mempool, txns, /*test_accept=*/true, /*client_maxfeerate=*/{});
+ - ]
224 [ + - ]: 1343 : return PackageMempoolAcceptResult(txns[0]->GetWitnessHash(),
225 [ + - + - ]: 1343 : chainman.ProcessTransaction(txns[0], /*test_accept=*/true));
226 [ + - ]: 2838 : }();
227 : :
228 : 1419 : UniValue rpc_result(UniValue::VARR);
229 : : // We will check transaction fees while we iterate through txns in order. If any transaction fee
230 : : // exceeds maxfeerate, we will leave the rest of the validation results blank, because it
231 : : // doesn't make sense to return a validation result for a transaction if its ancestor(s) would
232 : : // not be submitted.
233 : 1419 : bool exit_early{false};
234 [ + + ]: 3423 : for (const auto& tx : txns) {
235 : 2004 : UniValue result_inner(UniValue::VOBJ);
236 [ + - + - : 4008 : result_inner.pushKV("txid", tx->GetHash().GetHex());
+ - + - ]
237 [ + - + - : 4008 : result_inner.pushKV("wtxid", tx->GetWitnessHash().GetHex());
+ - + - ]
238 [ + + ]: 2004 : if (package_result.m_state.GetResult() == PackageValidationResult::PCKG_POLICY) {
239 [ + - + - : 198 : result_inner.pushKV("package-error", package_result.m_state.ToString());
+ - + - ]
240 : : }
241 : 2004 : auto it = package_result.m_tx_results.find(tx->GetWitnessHash());
242 [ + + + + ]: 2004 : if (exit_early || it == package_result.m_tx_results.end()) {
243 : : // Validation unfinished. Just return the txid and wtxid.
244 [ + - ]: 137 : rpc_result.push_back(std::move(result_inner));
245 : 137 : continue;
246 : : }
247 [ + - ]: 1867 : const auto& tx_result = it->second;
248 : : // Package testmempoolaccept doesn't allow transactions to already be in the mempool.
249 [ + - ]: 1867 : CHECK_NONFATAL(tx_result.m_result_type != MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
250 [ + + ]: 1867 : if (tx_result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
251 [ + - ]: 1619 : const CAmount fee = tx_result.m_base_fees.value();
252 : : // Check that fee does not exceed maximum fee
253 [ + - ]: 1619 : const int64_t virtual_size = tx_result.m_vsize.value();
254 [ + - ]: 1619 : const CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size);
255 [ + + ]: 1619 : if (max_raw_tx_fee && fee > max_raw_tx_fee) {
256 [ + - + - : 8 : result_inner.pushKV("allowed", false);
+ - ]
257 [ + - + - : 4 : result_inner.pushKV("reject-reason", "max-fee-exceeded");
+ - ]
258 : 4 : exit_early = true;
259 : : } else {
260 : : // Only return the fee and vsize if the transaction would pass ATMP.
261 : : // These can be used to calculate the feerate.
262 [ + - + - : 3230 : result_inner.pushKV("allowed", true);
+ - ]
263 [ + - + - : 3230 : result_inner.pushKV("vsize", virtual_size);
+ - ]
264 : 1615 : UniValue fees(UniValue::VOBJ);
265 [ + - + - : 3230 : fees.pushKV("base", ValueFromAmount(fee));
+ - ]
266 [ + - + - : 3230 : fees.pushKV("effective-feerate", ValueFromAmount(tx_result.m_effective_feerate.value().GetFeePerK()));
+ - + - ]
267 : 1615 : UniValue effective_includes_res(UniValue::VARR);
268 [ + - + + ]: 3230 : for (const auto& wtxid : tx_result.m_wtxids_fee_calculations.value()) {
269 [ + - + - : 1615 : effective_includes_res.push_back(wtxid.ToString());
+ - ]
270 : : }
271 [ + - + - ]: 3230 : fees.pushKV("effective-includes", std::move(effective_includes_res));
272 [ + - + - ]: 3230 : result_inner.pushKV("fees", std::move(fees));
273 : 1615 : }
274 : : } else {
275 [ + - + - : 496 : result_inner.pushKV("allowed", false);
+ - ]
276 [ + - ]: 248 : const TxValidationState state = tx_result.m_state;
277 [ + + ]: 248 : if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
278 [ + - + - : 232 : result_inner.pushKV("reject-reason", "missing-inputs");
+ - ]
279 : : } else {
280 [ - + + - : 396 : result_inner.pushKV("reject-reason", state.GetRejectReason());
+ - + - ]
281 [ + - + - : 264 : result_inner.pushKV("reject-details", state.ToString());
+ - + - ]
282 : : }
283 : 248 : }
284 [ + - ]: 1867 : rpc_result.push_back(std::move(result_inner));
285 : 2004 : }
286 : 1419 : return rpc_result;
287 : 1425 : },
288 [ + - + - : 34254 : };
+ - + + +
+ - - -
- ]
289 [ + - + - : 72314 : }
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - - -
- - - - ]
290 : :
291 : 3524 : static std::vector<RPCResult> ClusterDescription()
292 : : {
293 : 3524 : return {
294 [ + - + - ]: 7048 : RPCResult{RPCResult::Type::NUM, "clusterweight", "total sigops-adjusted weight (as defined in BIP 141 and modified by '-bytespersigop')"},
295 [ + - + - ]: 7048 : RPCResult{RPCResult::Type::NUM, "txcount", "number of transactions"},
296 [ + - + - ]: 7048 : RPCResult{RPCResult::Type::ARR, "chunks", "chunks in this cluster (in mining order)",
297 [ + - + - ]: 7048 : {RPCResult{RPCResult::Type::OBJ, "chunk", "",
298 : : {
299 [ + - + - ]: 7048 : RPCResult{RPCResult::Type::NUM, "chunkfee", "fees of the transactions in this chunk"},
300 [ + - + - ]: 7048 : RPCResult{RPCResult::Type::NUM, "chunkweight", "sigops-adjusted weight of all transactions in this chunk"},
301 [ + - + - ]: 7048 : RPCResult{RPCResult::Type::ARR, "txs", "transactions in this chunk in mining order",
302 [ + - + - : 14096 : {RPCResult{RPCResult::Type::STR_HEX, "txid", "transaction id"}}},
+ - + + -
- ]
303 : : }
304 [ + - + + : 17620 : }}
- - ]
305 [ + - + + : 10572 : }
- - ]
306 [ + - + + : 21144 : };
- - ]
307 [ + - + - : 28192 : }
+ - + - +
- + - + -
+ - - - -
- ]
308 : :
309 : 27932 : static std::vector<RPCResult> MempoolEntryDescription()
310 : : {
311 : 27932 : return {
312 [ + - + - ]: 55864 : 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."},
313 [ + - + - ]: 55864 : RPCResult{RPCResult::Type::NUM, "weight", "transaction weight as defined in BIP 141."},
314 [ + - + - ]: 55864 : RPCResult{RPCResult::Type::NUM_TIME, "time", "local time transaction entered pool in seconds since 1 Jan 1970 GMT"},
315 [ + - + - ]: 55864 : RPCResult{RPCResult::Type::NUM, "height", "block height when transaction entered pool"},
316 [ + - + - ]: 55864 : RPCResult{RPCResult::Type::NUM, "descendantcount", "number of in-mempool descendant transactions (including this one)"},
317 [ + - + - ]: 55864 : RPCResult{RPCResult::Type::NUM, "descendantsize", "virtual transaction size of in-mempool descendants (including this one)"},
318 [ + - + - ]: 55864 : RPCResult{RPCResult::Type::NUM, "ancestorcount", "number of in-mempool ancestor transactions (including this one)"},
319 [ + - + - ]: 55864 : RPCResult{RPCResult::Type::NUM, "ancestorsize", "virtual transaction size of in-mempool ancestors (including this one)"},
320 [ + - + - ]: 55864 : RPCResult{RPCResult::Type::NUM, "chunkweight", "sigops-adjusted weight (as defined in BIP 141 and modified by '-bytespersigop') of this transaction's chunk"},
321 [ + - + - ]: 55864 : RPCResult{RPCResult::Type::STR_HEX, "wtxid", "hash of serialized transaction, including witness data"},
322 [ + - + - ]: 55864 : RPCResult{RPCResult::Type::OBJ, "fees", "",
323 : : {
324 [ + - + - ]: 55864 : RPCResult{RPCResult::Type::STR_AMOUNT, "base", "transaction fee, denominated in " + CURRENCY_UNIT},
325 [ + - + - ]: 55864 : RPCResult{RPCResult::Type::STR_AMOUNT, "modified", "transaction fee with fee deltas used for mining priority, denominated in " + CURRENCY_UNIT},
326 [ + - + - ]: 55864 : 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},
327 [ + - + - ]: 55864 : 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},
328 [ + - + - ]: 55864 : RPCResult{RPCResult::Type::STR_AMOUNT, "chunk", "transaction fees of chunk, denominated in " + CURRENCY_UNIT},
329 [ + - + + : 195524 : }},
- - ]
330 [ + - + - ]: 55864 : RPCResult{RPCResult::Type::ARR, "depends", "unconfirmed transactions used as inputs for this transaction",
331 [ + - + - : 111728 : {RPCResult{RPCResult::Type::STR_HEX, "transactionid", "parent transaction id"}}},
+ - + + -
- ]
332 [ + - + - ]: 55864 : RPCResult{RPCResult::Type::ARR, "spentby", "unconfirmed transactions spending outputs from this transaction",
333 [ + - + - : 111728 : {RPCResult{RPCResult::Type::STR_HEX, "transactionid", "child transaction id"}}},
+ - + + -
- ]
334 [ + - + - ]: 55864 : RPCResult{RPCResult::Type::BOOL, "bip125-replaceable", "Whether this transaction signals BIP125 replaceability or has an unconfirmed ancestor signaling BIP125 replaceability. (DEPRECATED)\n"},
335 [ + - + - ]: 55864 : RPCResult{RPCResult::Type::BOOL, "unbroadcast", "Whether this transaction is currently unbroadcast (initial broadcast not yet acknowledged by any peers)"},
336 [ + - + + : 502776 : };
- - ]
337 [ + - + - : 614504 : }
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
- - - - ]
338 : :
339 : 25887 : void AppendChunkInfo(UniValue& all_chunks, FeePerWeight chunk_feerate, std::vector<const CTxMemPoolEntry *> chunk_txs)
340 : : {
341 : 25887 : UniValue chunk(UniValue::VOBJ);
342 [ + - + - : 51774 : chunk.pushKV("chunkfee", ValueFromAmount(chunk_feerate.fee));
+ - ]
343 [ + - + - : 51774 : chunk.pushKV("chunkweight", chunk_feerate.size);
+ - ]
344 : 25887 : UniValue chunk_txids(UniValue::VARR);
345 [ + + ]: 51782 : for (const auto& chunk_tx : chunk_txs) {
346 [ + - + - : 25895 : chunk_txids.push_back(chunk_tx->GetTx().GetHash().ToString());
+ - ]
347 : : }
348 [ + - + - ]: 51774 : chunk.pushKV("txs", std::move(chunk_txids));
349 [ + - ]: 25887 : all_chunks.push_back(std::move(chunk));
350 : 25887 : }
351 : :
352 : 1142 : static void clusterToJSON(const CTxMemPool& pool, UniValue& info, std::vector<const CTxMemPoolEntry *> cluster) EXCLUSIVE_LOCKS_REQUIRED(pool.cs)
353 : : {
354 : 1142 : AssertLockHeld(pool.cs);
355 : 1142 : int total_weight{0};
356 [ + + ]: 27037 : for (const auto& tx : cluster) {
357 : 25895 : total_weight += tx->GetAdjustedWeight();
358 : : }
359 [ + - + - ]: 2284 : info.pushKV("clusterweight", total_weight);
360 [ - + + - : 2284 : info.pushKV("txcount", cluster.size());
+ - ]
361 : :
362 : : // Output the cluster by chunk. This isn't handed to us by the mempool, but
363 : : // we can calculate it by looking at the chunk feerates of each transaction
364 : : // in the cluster.
365 : 1142 : FeePerWeight current_chunk_feerate = pool.GetMainChunkFeerate(*cluster[0]);
366 : 1142 : std::vector<const CTxMemPoolEntry *> current_chunk;
367 [ - + + - ]: 1142 : current_chunk.reserve(cluster.size());
368 : :
369 : 1142 : UniValue all_chunks(UniValue::VARR);
370 [ + + ]: 27037 : for (const auto& tx : cluster) {
371 [ + + ]: 25895 : if (current_chunk_feerate.size == 0) {
372 : : // We've iterated all the transactions in the previous chunk; so
373 : : // append it to the output.
374 [ + - + - ]: 24745 : AppendChunkInfo(all_chunks, pool.GetMainChunkFeerate(*current_chunk[0]), current_chunk);
375 [ + - ]: 24745 : current_chunk.clear();
376 : 24745 : current_chunk_feerate = pool.GetMainChunkFeerate(*tx);
377 : : }
378 [ + - ]: 25895 : current_chunk.push_back(tx);
379 [ + - ]: 25895 : current_chunk_feerate.size -= tx->GetAdjustedWeight();
380 : : }
381 [ + - + - ]: 1142 : AppendChunkInfo(all_chunks, pool.GetMainChunkFeerate(*current_chunk[0]), current_chunk);
382 [ + - ]: 1142 : current_chunk.clear();
383 [ + - + - ]: 2284 : info.pushKV("chunks", std::move(all_chunks));
384 : 1142 : }
385 : :
386 : 8606 : static void entryToJSON(const CTxMemPool& pool, UniValue& info, const CTxMemPoolEntry& e) EXCLUSIVE_LOCKS_REQUIRED(pool.cs)
387 : : {
388 : 8606 : AssertLockHeld(pool.cs);
389 : :
390 : 8606 : auto [ancestor_count, ancestor_size, ancestor_fees] = pool.CalculateAncestorData(e);
391 : 8606 : auto [descendant_count, descendant_size, descendant_fees] = pool.CalculateDescendantData(e);
392 : :
393 [ + - + - ]: 17212 : info.pushKV("vsize", e.GetTxSize());
394 [ + - + - ]: 17212 : info.pushKV("weight", e.GetTxWeight());
395 [ + - + - ]: 17212 : info.pushKV("time", count_seconds(e.GetTime()));
396 [ + - + - ]: 17212 : info.pushKV("height", e.GetHeight());
397 [ + - + - ]: 17212 : info.pushKV("descendantcount", descendant_count);
398 [ + - + - ]: 17212 : info.pushKV("descendantsize", descendant_size);
399 [ + - + - ]: 17212 : info.pushKV("ancestorcount", ancestor_count);
400 [ + - + - ]: 17212 : info.pushKV("ancestorsize", ancestor_size);
401 [ + - + - : 17212 : info.pushKV("wtxid", e.GetTx().GetWitnessHash().ToString());
+ - ]
402 : 8606 : auto feerate = pool.GetMainChunkFeerate(e);
403 [ + - + - ]: 17212 : info.pushKV("chunkweight", feerate.size);
404 : :
405 : 8606 : UniValue fees(UniValue::VOBJ);
406 [ + - + - : 17212 : fees.pushKV("base", ValueFromAmount(e.GetFee()));
+ - ]
407 [ + - + - : 17212 : fees.pushKV("modified", ValueFromAmount(e.GetModifiedFee()));
+ - ]
408 [ + - + - : 17212 : fees.pushKV("ancestor", ValueFromAmount(ancestor_fees));
+ - ]
409 [ + - + - : 17212 : fees.pushKV("descendant", ValueFromAmount(descendant_fees));
+ - ]
410 [ + - + - : 17212 : fees.pushKV("chunk", ValueFromAmount(feerate.fee));
+ - ]
411 [ + - + - ]: 17212 : info.pushKV("fees", std::move(fees));
412 : :
413 : 8606 : const CTransaction& tx = e.GetTx();
414 : 8606 : std::set<std::string> setDepends;
415 [ + + ]: 20759 : for (const CTxIn& txin : tx.vin)
416 : : {
417 [ + - + + ]: 12153 : if (pool.exists(txin.prevout.hash))
418 [ + - + - ]: 14156 : setDepends.insert(txin.prevout.hash.ToString());
419 : : }
420 : :
421 : 8606 : UniValue depends(UniValue::VARR);
422 [ + + ]: 15684 : for (const std::string& dep : setDepends)
423 : : {
424 [ + - + - ]: 7078 : depends.push_back(dep);
425 : : }
426 : :
427 [ + - + - ]: 17212 : info.pushKV("depends", std::move(depends));
428 : :
429 : 8606 : UniValue spent(UniValue::VARR);
430 [ + - + - : 15709 : for (const CTxMemPoolEntry& child : pool.GetChildren(e)) {
+ + ]
431 [ + - + - : 7103 : spent.push_back(child.GetTx().GetHash().ToString());
+ - ]
432 : 0 : }
433 : :
434 [ + - + - ]: 17212 : info.pushKV("spentby", std::move(spent));
435 : :
436 : : // Add opt-in RBF status
437 : 8606 : bool rbfStatus = false;
438 [ + - ]: 8606 : RBFTransactionState rbfState = IsRBFOptIn(tx, pool);
439 [ - + ]: 8606 : if (rbfState == RBFTransactionState::UNKNOWN) {
440 [ # # # # ]: 0 : throw JSONRPCError(RPC_MISC_ERROR, "Transaction is not in mempool");
441 [ + + ]: 8606 : } else if (rbfState == RBFTransactionState::REPLACEABLE_BIP125) {
442 : 7452 : rbfStatus = true;
443 : : }
444 : :
445 [ + - + - : 17212 : info.pushKV("bip125-replaceable", rbfStatus);
+ - ]
446 [ + - + - : 17212 : info.pushKV("unbroadcast", pool.IsUnbroadcastTx(tx.GetHash()));
+ - ]
447 : 8606 : }
448 : :
449 : 7522 : UniValue MempoolToJSON(const CTxMemPool& pool, bool verbose, bool include_mempool_sequence)
450 : : {
451 [ + + ]: 7522 : if (verbose) {
452 [ + + ]: 1059 : if (include_mempool_sequence) {
453 [ + - + - ]: 2 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Verbose results cannot contain mempool sequence values.");
454 : : }
455 : 1058 : LOCK(pool.cs);
456 : 1058 : UniValue o(UniValue::VOBJ);
457 [ + - + + ]: 4754 : for (const CTxMemPoolEntry& e : pool.entryAll()) {
458 : 3696 : UniValue info(UniValue::VOBJ);
459 [ + - ]: 3696 : entryToJSON(pool, info, e);
460 : : // Mempool has unique entries so there is no advantage in using
461 : : // UniValue::pushKV, which checks if the key already exists in O(N).
462 : : // UniValue::pushKVEnd is used instead which currently is O(1).
463 [ + - + - ]: 7392 : o.pushKVEnd(e.GetTx().GetHash().ToString(), std::move(info));
464 : 3696 : }
465 [ + - ]: 1058 : return o;
466 : 1058 : } else {
467 : 6463 : UniValue a(UniValue::VARR);
468 : 6463 : uint64_t mempool_sequence;
469 : 6463 : {
470 [ + - ]: 6463 : LOCK(pool.cs);
471 [ + - + - : 338912 : for (const CTxMemPoolEntry& e : pool.entryAll()) {
+ + ]
472 [ + - + - : 332449 : a.push_back(e.GetTx().GetHash().ToString());
+ - ]
473 : : }
474 [ + - ]: 6463 : mempool_sequence = pool.GetSequence();
475 : 0 : }
476 [ + + ]: 6463 : if (!include_mempool_sequence) {
477 : 6442 : return a;
478 : : } else {
479 : 21 : UniValue o(UniValue::VOBJ);
480 [ + - + - ]: 42 : o.pushKV("txids", std::move(a));
481 [ + - + - : 42 : o.pushKV("mempool_sequence", mempool_sequence);
+ - ]
482 : 21 : return o;
483 : 21 : }
484 : 6463 : }
485 : : }
486 : :
487 : 2377 : static RPCHelpMan getmempoolfeeratediagram()
488 : : {
489 : 2377 : return RPCHelpMan{"getmempoolfeeratediagram",
490 [ + - ]: 4754 : "Returns the feerate diagram for the whole mempool.",
491 : : {},
492 : : {
493 : 0 : RPCResult{"mempool chunks",
494 [ + - + - ]: 4754 : RPCResult::Type::ARR, "", "",
495 : : {
496 : : {
497 [ + - + - ]: 4754 : RPCResult::Type::OBJ, "", "",
498 : : {
499 [ + - + - ]: 4754 : {RPCResult::Type::NUM, "weight", "cumulative sigops-adjusted weight"},
500 [ + - + - ]: 4754 : {RPCResult::Type::NUM, "fee", "cumulative fee"}
501 : : }
502 : : }
503 : : }
504 [ + - + - : 16639 : }
+ + + + -
- - - ]
505 : : },
506 : 2377 : RPCExamples{
507 [ + - + - : 4754 : HelpExampleCli("getmempoolfeeratediagram", "")
+ - ]
508 [ + - + - : 9508 : + HelpExampleRpc("getmempoolfeeratediagram", "")
+ - ]
509 [ + - ]: 2377 : },
510 : 2377 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
511 : : {
512 : 5 : const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
513 : 5 : LOCK(mempool.cs);
514 : :
515 : 5 : UniValue result(UniValue::VARR);
516 : :
517 [ + - ]: 5 : auto diagram = mempool.GetFeerateDiagram();
518 : :
519 [ + + ]: 136 : for (auto f : diagram) {
520 : 131 : UniValue o(UniValue::VOBJ);
521 [ + - + - : 262 : o.pushKV("weight", f.size);
+ - ]
522 [ + - + - : 262 : o.pushKV("fee", ValueFromAmount(f.fee));
+ - ]
523 [ + - + - ]: 131 : result.push_back(o);
524 : 131 : }
525 : 5 : return result;
526 [ + - ]: 10 : }
527 [ + - + - : 19016 : };
+ - + - +
+ - - ]
528 [ + - + - : 9508 : }
+ - + - -
- ]
529 : :
530 : 9899 : static RPCHelpMan getrawmempool()
531 : : {
532 : 9899 : return RPCHelpMan{
533 : 9899 : "getrawmempool",
534 [ + - ]: 19798 : "Returns all transaction ids in memory pool as a json array of string transaction ids.\n"
535 : : "\nHint: use getmempoolentry to fetch a specific transaction from the mempool.\n",
536 : : {
537 [ + - + - : 29697 : {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"},
+ - ]
538 [ + - + - : 29697 : {"mempool_sequence", RPCArg::Type::BOOL, RPCArg::Default{false}, "If verbose=false, returns a json object with transaction list and mempool sequence number attached."},
+ - ]
539 : : },
540 : : {
541 [ + - ]: 9899 : RPCResult{"for verbose = false",
542 [ + - + - ]: 19798 : RPCResult::Type::ARR, "", "",
543 : : {
544 [ + - + - ]: 19798 : {RPCResult::Type::STR_HEX, "", "The transaction id"},
545 [ + - + + : 29697 : }},
- - ]
546 [ + - ]: 19798 : RPCResult{"for verbose = true",
547 [ + - + - ]: 19798 : RPCResult::Type::OBJ_DYN, "", "",
548 : : {
549 [ + - + - : 19798 : {RPCResult::Type::OBJ, "transactionid", "", MempoolEntryDescription()},
+ - ]
550 [ + - + + : 29697 : }},
- - ]
551 [ + - ]: 19798 : RPCResult{"for verbose = false and mempool_sequence = true",
552 [ + - + - ]: 19798 : RPCResult::Type::OBJ, "", "",
553 : : {
554 [ + - + - ]: 19798 : {RPCResult::Type::ARR, "txids", "",
555 : : {
556 [ + - + - ]: 19798 : {RPCResult::Type::STR_HEX, "", "The transaction id"},
557 : : }},
558 [ + - + - ]: 19798 : {RPCResult::Type::NUM, "mempool_sequence", "The mempool sequence value."},
559 [ + - + - : 69293 : }},
+ + + + -
- - - ]
560 : : },
561 : 9899 : RPCExamples{
562 [ + - + - : 19798 : HelpExampleCli("getrawmempool", "true")
+ - ]
563 [ + - + - : 39596 : + HelpExampleRpc("getrawmempool", "true")
+ - ]
564 [ + - ]: 9899 : },
565 : 9899 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
566 : : {
567 : 7518 : bool fVerbose = false;
568 [ + + ]: 7518 : if (!request.params[0].isNull())
569 : 1115 : fVerbose = request.params[0].get_bool();
570 : :
571 : 7518 : bool include_mempool_sequence = false;
572 [ + + ]: 7518 : if (!request.params[1].isNull()) {
573 : 22 : include_mempool_sequence = request.params[1].get_bool();
574 : : }
575 : :
576 : 7518 : return MempoolToJSON(EnsureAnyMemPool(request.context), fVerbose, include_mempool_sequence);
577 : : },
578 [ + - + - : 118788 : };
+ - + - +
+ + + - -
- - ]
579 [ + - + - : 118788 : }
+ - + - +
- + - + -
+ - + - +
- - - - -
- - ]
580 : :
581 : 2994 : static RPCHelpMan getmempoolancestors()
582 : : {
583 : 2994 : return RPCHelpMan{
584 : 2994 : "getmempoolancestors",
585 [ + - ]: 5988 : "If txid is in the mempool, returns all in-mempool ancestors.\n",
586 : : {
587 [ + - + - ]: 5988 : {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
588 [ + - + - : 8982 : {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"},
+ - ]
589 : : },
590 : : {
591 [ + - ]: 2994 : RPCResult{"for verbose = false",
592 [ + - + - ]: 5988 : RPCResult::Type::ARR, "", "",
593 [ + - + - : 11976 : {{RPCResult::Type::STR_HEX, "", "The transaction id of an in-mempool ancestor transaction"}}},
+ - + + -
- ]
594 [ + - ]: 5988 : RPCResult{"for verbose = true",
595 [ + - + - ]: 5988 : RPCResult::Type::OBJ_DYN, "", "",
596 : : {
597 [ + - + - : 5988 : {RPCResult::Type::OBJ, "transactionid", "", MempoolEntryDescription()},
+ - ]
598 [ + - + + : 8982 : }},
- - ]
599 : : },
600 : 2994 : RPCExamples{
601 [ + - + - : 5988 : HelpExampleCli("getmempoolancestors", "\"mytxid\"")
+ - ]
602 [ + - + - : 11976 : + HelpExampleRpc("getmempoolancestors", "\"mytxid\"")
+ - ]
603 [ + - ]: 2994 : },
604 : 2994 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
605 : : {
606 : 613 : bool fVerbose = false;
607 [ + + ]: 613 : if (!request.params[1].isNull())
608 : 65 : fVerbose = request.params[1].get_bool();
609 : :
610 : 613 : auto txid{Txid::FromUint256(ParseHashV(request.params[0], "txid"))};
611 : :
612 : 613 : const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
613 : 613 : LOCK(mempool.cs);
614 : :
615 [ + - ]: 613 : const auto entry{mempool.GetEntry(txid)};
616 [ - + ]: 613 : if (entry == nullptr) {
617 [ # # # # ]: 0 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool");
618 : : }
619 : :
620 [ + - ]: 613 : auto ancestors{mempool.CalculateMemPoolAncestors(*entry)};
621 : :
622 [ + + ]: 613 : if (!fVerbose) {
623 : 548 : UniValue o(UniValue::VARR);
624 [ + + ]: 11954 : for (CTxMemPool::txiter ancestorIt : ancestors) {
625 [ + - + - : 11406 : o.push_back(ancestorIt->GetTx().GetHash().ToString());
+ - ]
626 : : }
627 : : return o;
628 : 0 : } else {
629 : 65 : UniValue o(UniValue::VOBJ);
630 [ + + ]: 2144 : for (CTxMemPool::txiter ancestorIt : ancestors) {
631 : 2079 : const CTxMemPoolEntry &e = *ancestorIt;
632 : 2079 : UniValue info(UniValue::VOBJ);
633 [ + - ]: 2079 : entryToJSON(mempool, info, e);
634 [ + - + - ]: 4158 : o.pushKV(e.GetTx().GetHash().ToString(), std::move(info));
635 : 2079 : }
636 : 65 : return o;
637 : 65 : }
638 [ + - ]: 1226 : },
639 [ + - + - : 32934 : };
+ - + - +
+ + + - -
- - ]
640 [ + - + - : 23952 : }
+ - + - +
- + - - -
- - ]
641 : :
642 : 11900 : static RPCHelpMan getmempooldescendants()
643 : : {
644 : 11900 : return RPCHelpMan{
645 : 11900 : "getmempooldescendants",
646 [ + - ]: 23800 : "If txid is in the mempool, returns all in-mempool descendants.\n",
647 : : {
648 [ + - + - ]: 23800 : {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
649 [ + - + - : 35700 : {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"},
+ - ]
650 : : },
651 : : {
652 [ + - ]: 11900 : RPCResult{"for verbose = false",
653 [ + - + - ]: 23800 : RPCResult::Type::ARR, "", "",
654 [ + - + - : 47600 : {{RPCResult::Type::STR_HEX, "", "The transaction id of an in-mempool descendant transaction"}}},
+ - + + -
- ]
655 [ + - ]: 23800 : RPCResult{"for verbose = true",
656 [ + - + - ]: 23800 : RPCResult::Type::OBJ_DYN, "", "",
657 : : {
658 [ + - + - : 23800 : {RPCResult::Type::OBJ, "transactionid", "", MempoolEntryDescription()},
+ - ]
659 [ + - + + : 35700 : }},
- - ]
660 : : },
661 : 11900 : RPCExamples{
662 [ + - + - : 23800 : HelpExampleCli("getmempooldescendants", "\"mytxid\"")
+ - ]
663 [ + - + - : 47600 : + HelpExampleRpc("getmempooldescendants", "\"mytxid\"")
+ - ]
664 [ + - ]: 11900 : },
665 : 11900 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
666 : : {
667 : 9519 : bool fVerbose = false;
668 [ + + ]: 9519 : if (!request.params[1].isNull())
669 : 65 : fVerbose = request.params[1].get_bool();
670 : :
671 : 9519 : auto txid{Txid::FromUint256(ParseHashV(request.params[0], "txid"))};
672 : :
673 : 9519 : const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
674 : 9519 : LOCK(mempool.cs);
675 : :
676 [ + - ]: 9519 : const auto it{mempool.GetIter(txid)};
677 [ - + ]: 9519 : if (!it) {
678 [ # # # # ]: 0 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool");
679 : : }
680 : :
681 [ + - ]: 9519 : CTxMemPool::setEntries setDescendants;
682 [ + - ]: 9519 : mempool.CalculateDescendants(*it, setDescendants);
683 : : // CTxMemPool::CalculateDescendants will include the given tx
684 : 9519 : setDescendants.erase(*it);
685 : :
686 [ + + ]: 9519 : if (!fVerbose) {
687 : 9454 : UniValue o(UniValue::VARR);
688 [ + + ]: 175782 : for (CTxMemPool::txiter descendantIt : setDescendants) {
689 [ + - + - : 166328 : o.push_back(descendantIt->GetTx().GetHash().ToString());
+ - ]
690 : : }
691 : :
692 : : return o;
693 : 0 : } else {
694 : 65 : UniValue o(UniValue::VOBJ);
695 [ + + ]: 2144 : for (CTxMemPool::txiter descendantIt : setDescendants) {
696 : 2079 : const CTxMemPoolEntry &e = *descendantIt;
697 : 2079 : UniValue info(UniValue::VOBJ);
698 [ + - ]: 2079 : entryToJSON(mempool, info, e);
699 [ + - + - ]: 4158 : o.pushKV(e.GetTx().GetHash().ToString(), std::move(info));
700 : 2079 : }
701 : 65 : return o;
702 : 65 : }
703 [ + - ]: 19038 : },
704 [ + - + - : 130900 : };
+ - + - +
+ + + - -
- - ]
705 [ + - + - : 95200 : }
+ - + - +
- + - - -
- - ]
706 : :
707 : 3524 : static RPCHelpMan getmempoolcluster()
708 : : {
709 : 3524 : return RPCHelpMan{"getmempoolcluster",
710 [ + - ]: 7048 : "Returns mempool data for given cluster\n",
711 : : {
712 [ + - + - ]: 7048 : {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The txid of a transaction in the cluster"},
713 : : },
714 [ + - ]: 7048 : RPCResult{
715 [ + - + - : 7048 : RPCResult::Type::OBJ, "", "", ClusterDescription()},
+ - + - ]
716 : 3524 : RPCExamples{
717 [ + - + - : 7048 : HelpExampleCli("getmempoolcluster", "txid")
+ - ]
718 [ + - + - : 14096 : + HelpExampleRpc("getmempoolcluster", "txid")
+ - + - ]
719 [ + - ]: 3524 : },
720 : 3524 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
721 : : {
722 : 1143 : uint256 hash = ParseHashV(request.params[0], "txid");
723 : :
724 : 1143 : const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
725 : 1143 : LOCK(mempool.cs);
726 : :
727 [ + - ]: 1143 : auto txid = Txid::FromUint256(hash);
728 [ + - ]: 1143 : const auto entry{mempool.GetEntry(txid)};
729 [ + + ]: 1143 : if (entry == nullptr) {
730 [ + - + - ]: 2 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool");
731 : : }
732 : :
733 [ + - ]: 1142 : auto cluster = mempool.GetCluster(txid);
734 : :
735 : 1142 : UniValue info(UniValue::VOBJ);
736 [ + - + - ]: 1142 : clusterToJSON(mempool, info, cluster);
737 : 1142 : return info;
738 [ + - ]: 2284 : },
739 [ + - + - : 17620 : };
+ + - - ]
740 [ + - ]: 7048 : }
741 : :
742 : 3139 : static RPCHelpMan getmempoolentry()
743 : : {
744 : 3139 : return RPCHelpMan{
745 : 3139 : "getmempoolentry",
746 [ + - ]: 6278 : "Returns mempool data for given transaction\n",
747 : : {
748 [ + - + - ]: 6278 : {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
749 : : },
750 [ + - ]: 6278 : RPCResult{
751 [ + - + - : 6278 : RPCResult::Type::OBJ, "", "", MempoolEntryDescription()},
+ - + - ]
752 : 3139 : RPCExamples{
753 [ + - + - : 6278 : HelpExampleCli("getmempoolentry", "\"mytxid\"")
+ - ]
754 [ + - + - : 12556 : + HelpExampleRpc("getmempoolentry", "\"mytxid\"")
+ - + - ]
755 [ + - ]: 3139 : },
756 : 3139 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
757 : : {
758 : 758 : auto txid{Txid::FromUint256(ParseHashV(request.params[0], "txid"))};
759 : :
760 : 758 : const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
761 : 758 : LOCK(mempool.cs);
762 : :
763 [ + - ]: 758 : const auto entry{mempool.GetEntry(txid)};
764 [ + + ]: 758 : if (entry == nullptr) {
765 [ + - + - ]: 12 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool");
766 : : }
767 : :
768 : 752 : UniValue info(UniValue::VOBJ);
769 [ + - ]: 752 : entryToJSON(mempool, info, *entry);
770 [ + - ]: 752 : return info;
771 : 752 : },
772 [ + - + - : 15695 : };
+ + - - ]
773 [ + - ]: 6278 : }
774 : :
775 : 2456 : static RPCHelpMan gettxspendingprevout()
776 : : {
777 : 2456 : return RPCHelpMan{"gettxspendingprevout",
778 [ + - ]: 4912 : "Scans the mempool to find transactions spending any of the given outputs",
779 : : {
780 [ + - + - ]: 4912 : {"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The transaction outputs that we want to check, and within each, the txid (string) vout (numeric).",
781 : : {
782 [ + - + - ]: 4912 : {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
783 : : {
784 [ + - + - ]: 4912 : {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
785 [ + - + - ]: 4912 : {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
786 : : },
787 : : },
788 : : },
789 : : },
790 : : },
791 [ + - ]: 4912 : RPCResult{
792 [ + - + - ]: 4912 : RPCResult::Type::ARR, "", "",
793 : : {
794 [ + - + - ]: 4912 : {RPCResult::Type::OBJ, "", "",
795 : : {
796 [ + - + - ]: 4912 : {RPCResult::Type::STR_HEX, "txid", "the transaction id of the checked output"},
797 [ + - + - ]: 4912 : {RPCResult::Type::NUM, "vout", "the vout value of the checked output"},
798 [ + - + - ]: 4912 : {RPCResult::Type::STR_HEX, "spendingtxid", /*optional=*/true, "the transaction id of the mempool transaction spending this output (omitted if unspent)"},
799 : : }},
800 : : }
801 [ + - + - : 22104 : },
+ - + + +
+ - - -
- ]
802 : 2456 : RPCExamples{
803 [ + - + - : 4912 : HelpExampleCli("gettxspendingprevout", "\"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":3}]\"")
+ - ]
804 [ + - + - : 9824 : + HelpExampleRpc("gettxspendingprevout", "\"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":3}]\"")
+ - + - ]
805 [ + - ]: 2456 : },
806 : 2456 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
807 : : {
808 : 75 : const UniValue& output_params = request.params[0].get_array();
809 [ - + + + ]: 75 : if (output_params.empty()) {
810 [ + - + - ]: 2 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, outputs are missing");
811 : : }
812 : :
813 : 74 : std::vector<COutPoint> prevouts;
814 [ + - ]: 74 : prevouts.reserve(output_params.size());
815 : :
816 [ - + + + ]: 146 : for (unsigned int idx = 0; idx < output_params.size(); idx++) {
817 [ + - + - ]: 77 : const UniValue& o = output_params[idx].get_obj();
818 : :
819 [ + + + + : 312 : RPCTypeCheckObj(o,
+ + ]
820 : : {
821 [ + - ]: 77 : {"txid", UniValueType(UniValue::VSTR)},
822 [ + - ]: 77 : {"vout", UniValueType(UniValue::VNUM)},
823 : : }, /*fAllowNull=*/false, /*fStrict=*/true);
824 : :
825 [ + - ]: 73 : const Txid txid = Txid::FromUint256(ParseHashO(o, "txid"));
826 [ + - + - ]: 73 : const int nOutput{o.find_value("vout").getInt<int>()};
827 [ + + ]: 73 : if (nOutput < 0) {
828 [ + - + - ]: 2 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative");
829 : : }
830 : :
831 [ + - ]: 72 : prevouts.emplace_back(txid, nOutput);
832 : : }
833 : :
834 [ + - ]: 69 : const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
835 [ + - ]: 69 : LOCK(mempool.cs);
836 : :
837 : 69 : UniValue result{UniValue::VARR};
838 : :
839 [ + + ]: 141 : for (const COutPoint& prevout : prevouts) {
840 : 72 : UniValue o(UniValue::VOBJ);
841 [ + - + - : 144 : o.pushKV("txid", prevout.hash.ToString());
+ - + - ]
842 [ + - + - : 144 : o.pushKV("vout", prevout.n);
+ - ]
843 : :
844 [ + - ]: 72 : const CTransaction* spendingTx = mempool.GetConflictTx(prevout);
845 [ + + ]: 72 : if (spendingTx != nullptr) {
846 [ + - + - : 138 : o.pushKV("spendingtxid", spendingTx->GetHash().ToString());
+ - + - ]
847 : : }
848 : :
849 [ + - ]: 72 : result.push_back(std::move(o));
850 : 72 : }
851 : :
852 [ + - ]: 69 : return result;
853 [ + - + - : 150 : },
+ - - + ]
854 [ + - + - : 29472 : };
+ - + - +
+ + + + +
- - - - -
- ]
855 [ + - + - : 29472 : }
+ - + - +
- + - + -
+ - - - -
- ]
856 : :
857 : 1276 : UniValue MempoolInfoToJSON(const CTxMemPool& pool)
858 : : {
859 : : // Make sure this call is atomic in the pool.
860 : 1276 : LOCK(pool.cs);
861 : 1276 : UniValue ret(UniValue::VOBJ);
862 [ + - + - : 2552 : ret.pushKV("loaded", pool.GetLoadTried());
+ - + - ]
863 [ + - + - : 2552 : ret.pushKV("size", pool.size());
+ - + - ]
864 [ + - + - : 2552 : ret.pushKV("bytes", pool.GetTotalTxSize());
+ - ]
865 [ + - + - : 2552 : ret.pushKV("usage", pool.DynamicMemoryUsage());
+ - + - ]
866 [ + - + - : 2552 : ret.pushKV("total_fee", ValueFromAmount(pool.GetTotalFee()));
+ - ]
867 [ + - + - : 2552 : ret.pushKV("maxmempool", pool.m_opts.max_size_bytes);
+ - ]
868 [ + - + - : 2552 : ret.pushKV("mempoolminfee", ValueFromAmount(std::max(pool.GetMinFee(), pool.m_opts.min_relay_feerate).GetFeePerK()));
+ - + - ]
869 [ + - + - : 2552 : ret.pushKV("minrelaytxfee", ValueFromAmount(pool.m_opts.min_relay_feerate.GetFeePerK()));
+ - ]
870 [ + - + - : 2552 : ret.pushKV("incrementalrelayfee", ValueFromAmount(pool.m_opts.incremental_relay_feerate.GetFeePerK()));
+ - ]
871 [ + - + - : 2552 : ret.pushKV("unbroadcastcount", pool.GetUnbroadcastTxs().size());
+ - + - ]
872 [ + - + - : 2552 : ret.pushKV("fullrbf", true);
+ - ]
873 [ + - + - : 2552 : ret.pushKV("permitbaremultisig", pool.m_opts.permit_bare_multisig);
+ - ]
874 [ + + + - : 3826 : ret.pushKV("maxdatacarriersize", pool.m_opts.max_datacarrier_bytes.value_or(0));
+ - + - ]
875 [ + - + - : 2552 : ret.pushKV("limitclustercount", pool.m_opts.limits.cluster_count);
+ - ]
876 [ + - + - : 2552 : ret.pushKV("limitclustersize", pool.m_opts.limits.cluster_size_vbytes);
+ - ]
877 [ + - ]: 1276 : return ret;
878 : 1276 : }
879 : :
880 : 3656 : static RPCHelpMan getmempoolinfo()
881 : : {
882 : 3656 : return RPCHelpMan{"getmempoolinfo",
883 [ + - ]: 7312 : "Returns details on the active state of the TX memory pool.",
884 : : {},
885 [ + - ]: 7312 : RPCResult{
886 [ + - ]: 7312 : RPCResult::Type::OBJ, "", "",
887 : : {
888 [ + - + - ]: 7312 : {RPCResult::Type::BOOL, "loaded", "True if the initial load attempt of the persisted mempool finished"},
889 [ + - + - ]: 7312 : {RPCResult::Type::NUM, "size", "Current tx count"},
890 [ + - + - ]: 7312 : {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"},
891 [ + - + - ]: 7312 : {RPCResult::Type::NUM, "usage", "Total memory usage for the mempool"},
892 [ + - + - ]: 7312 : {RPCResult::Type::STR_AMOUNT, "total_fee", "Total fees for the mempool in " + CURRENCY_UNIT + ", ignoring modified fees through prioritisetransaction"},
893 [ + - + - ]: 7312 : {RPCResult::Type::NUM, "maxmempool", "Maximum memory usage for the mempool"},
894 [ + - + - ]: 7312 : {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"},
895 [ + - + - ]: 10968 : {RPCResult::Type::STR_AMOUNT, "minrelaytxfee", "Current minimum relay fee for transactions"},
896 [ + - + - ]: 7312 : {RPCResult::Type::NUM, "incrementalrelayfee", "minimum fee rate increment for mempool limiting or replacement in " + CURRENCY_UNIT + "/kvB"},
897 [ + - + - ]: 7312 : {RPCResult::Type::NUM, "unbroadcastcount", "Current number of transactions that haven't passed initial broadcast yet"},
898 [ + - + - ]: 7312 : {RPCResult::Type::BOOL, "fullrbf", "True if the mempool accepts RBF without replaceability signaling inspection (DEPRECATED)"},
899 [ + - + - ]: 7312 : {RPCResult::Type::BOOL, "permitbaremultisig", "True if the mempool accepts transactions with bare multisig outputs"},
900 [ + - + - ]: 7312 : {RPCResult::Type::NUM, "maxdatacarriersize", "Maximum number of bytes that can be used by OP_RETURN outputs in the mempool"},
901 [ + - + - ]: 7312 : {RPCResult::Type::NUM, "limitclustercount", "Maximum number of transactions that can be in a cluster (configured by -limitclustercount)"},
902 [ + - + - ]: 7312 : {RPCResult::Type::NUM, "limitclustersize", "Maximum size of a cluster in virtual bytes (configured by -limitclustersize)"},
903 [ + - + - : 113336 : }},
+ + - - ]
904 : 3656 : RPCExamples{
905 [ + - + - : 7312 : HelpExampleCli("getmempoolinfo", "")
+ - ]
906 [ + - + - : 14624 : + HelpExampleRpc("getmempoolinfo", "")
+ - + - ]
907 [ + - ]: 3656 : },
908 : 3656 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
909 : : {
910 : 1275 : return MempoolInfoToJSON(EnsureAnyMemPool(request.context));
911 : : },
912 [ + - + - ]: 14624 : };
913 [ + - + - : 54840 : }
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- - - ]
914 : :
915 : 2384 : static RPCHelpMan importmempool()
916 : : {
917 : 2384 : return RPCHelpMan{
918 : 2384 : "importmempool",
919 [ + - ]: 4768 : "Import a mempool.dat file and attempt to add its contents to the mempool.\n"
920 : : "Warning: Importing untrusted files is dangerous, especially if metadata from the file is taken over.",
921 : : {
922 [ + - + - ]: 4768 : {"filepath", RPCArg::Type::STR, RPCArg::Optional::NO, "The mempool file"},
923 [ + - ]: 4768 : {"options",
924 : : RPCArg::Type::OBJ_NAMED_PARAMS,
925 : 2384 : RPCArg::Optional::OMITTED,
926 [ + - ]: 4768 : "",
927 : : {
928 [ + - + - ]: 4768 : {"use_current_time", RPCArg::Type::BOOL, RPCArg::Default{true},
929 [ + - ]: 4768 : "Whether to use the current system time or use the entry time metadata from the mempool file.\n"
930 : : "Warning: Importing untrusted metadata may lead to unexpected issues and undesirable behavior."},
931 [ + - + - ]: 4768 : {"apply_fee_delta_priority", RPCArg::Type::BOOL, RPCArg::Default{false},
932 [ + - ]: 4768 : "Whether to apply the fee delta metadata from the mempool file.\n"
933 : : "It will be added to any existing fee deltas.\n"
934 : : "The fee delta can be set by the prioritisetransaction RPC.\n"
935 : : "Warning: Importing untrusted metadata may lead to unexpected issues and undesirable behavior.\n"
936 : : "Only set this bool if you understand what it does."},
937 [ + - + - ]: 4768 : {"apply_unbroadcast_set", RPCArg::Type::BOOL, RPCArg::Default{false},
938 [ + - ]: 4768 : "Whether to apply the unbroadcast set metadata from the mempool file.\n"
939 : : "Warning: Importing untrusted metadata may lead to unexpected issues and undesirable behavior."},
940 : : },
941 [ + - ]: 2384 : RPCArgOptions{.oneline_description = "options"}},
942 : : },
943 [ + - + - : 4768 : RPCResult{RPCResult::Type::OBJ, "", "", std::vector<RPCResult>{}},
+ - + - ]
944 [ + - + - : 7152 : RPCExamples{HelpExampleCli("importmempool", "/path/to/mempool.dat") + HelpExampleRpc("importmempool", "/path/to/mempool.dat")},
+ - + - +
- + - + -
+ - ]
945 : 2384 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue {
946 : 3 : const NodeContext& node{EnsureAnyNodeContext(request.context)};
947 : :
948 : 3 : CTxMemPool& mempool{EnsureMemPool(node)};
949 : 3 : ChainstateManager& chainman = EnsureChainman(node);
950 : 3 : Chainstate& chainstate = chainman.ActiveChainstate();
951 : :
952 [ - + ]: 3 : if (chainman.IsInitialBlockDownload()) {
953 [ # # # # ]: 0 : throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Can only import the mempool after the block download and sync is done.");
954 : : }
955 : :
956 : 3 : const fs::path load_path{fs::u8path(self.Arg<std::string_view>("filepath"))};
957 [ + - + - : 3 : const UniValue& use_current_time{request.params[1]["use_current_time"]};
+ - ]
958 [ + - + - : 3 : const UniValue& apply_fee_delta{request.params[1]["apply_fee_delta_priority"]};
+ - ]
959 [ + - + - : 3 : const UniValue& apply_unbroadcast{request.params[1]["apply_unbroadcast_set"]};
+ - ]
960 [ - + ]: 3 : node::ImportMempoolOptions opts{
961 [ - + - - ]: 3 : .use_current_time = use_current_time.isNull() ? true : use_current_time.get_bool(),
962 [ + + + - ]: 3 : .apply_fee_delta_priority = apply_fee_delta.isNull() ? false : apply_fee_delta.get_bool(),
963 [ + + + - ]: 3 : .apply_unbroadcast_set = apply_unbroadcast.isNull() ? false : apply_unbroadcast.get_bool(),
964 [ - + + + : 5 : };
+ + ]
965 : :
966 [ + - - + ]: 3 : if (!node::LoadMempool(mempool, load_path, chainstate, std::move(opts))) {
967 [ # # # # ]: 0 : throw JSONRPCError(RPC_MISC_ERROR, "Unable to import mempool file, see debug.log for details.");
968 : : }
969 : :
970 : 3 : UniValue ret{UniValue::VOBJ};
971 : 3 : return ret;
972 : 6 : },
973 [ + - + - : 26224 : };
+ - + + +
+ - - -
- ]
974 [ + - + - : 21456 : }
+ - + - +
- - - -
- ]
975 : :
976 : 2385 : static RPCHelpMan savemempool()
977 : : {
978 : 2385 : return RPCHelpMan{
979 : 2385 : "savemempool",
980 [ + - ]: 4770 : "Dumps the mempool to disk. It will fail until the previous dump is fully loaded.\n",
981 : : {},
982 [ + - ]: 4770 : RPCResult{
983 [ + - ]: 4770 : RPCResult::Type::OBJ, "", "",
984 : : {
985 [ + - + - ]: 4770 : {RPCResult::Type::STR, "filename", "the directory and file where the mempool was saved"},
986 [ + - + - : 7155 : }},
+ + - - ]
987 : 2385 : RPCExamples{
988 [ + - + - : 4770 : HelpExampleCli("savemempool", "")
+ - ]
989 [ + - + - : 9540 : + HelpExampleRpc("savemempool", "")
+ - + - ]
990 [ + - ]: 2385 : },
991 : 2385 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
992 : : {
993 : 4 : const ArgsManager& args{EnsureAnyArgsman(request.context)};
994 : 4 : const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
995 : :
996 [ - + ]: 4 : if (!mempool.GetLoadTried()) {
997 [ # # # # ]: 0 : throw JSONRPCError(RPC_MISC_ERROR, "The mempool was not loaded yet");
998 : : }
999 : :
1000 : 4 : const fs::path& dump_path = MempoolPath(args);
1001 : :
1002 [ + - + + ]: 4 : if (!DumpMempool(mempool, dump_path)) {
1003 [ + - + - ]: 2 : throw JSONRPCError(RPC_MISC_ERROR, "Unable to dump mempool to disk");
1004 : : }
1005 : :
1006 : 3 : UniValue ret(UniValue::VOBJ);
1007 [ + - + - : 6 : ret.pushKV("filename", dump_path.utf8string());
+ - + - ]
1008 : :
1009 : 6 : return ret;
1010 : 0 : },
1011 [ + - + - ]: 9540 : };
1012 [ + - ]: 2385 : }
1013 : :
1014 : 5196 : static std::vector<RPCResult> OrphanDescription()
1015 : : {
1016 : 5196 : return {
1017 [ + - + - ]: 10392 : RPCResult{RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
1018 [ + - + - ]: 10392 : RPCResult{RPCResult::Type::STR_HEX, "wtxid", "The transaction witness hash in hex"},
1019 [ + - + - ]: 10392 : RPCResult{RPCResult::Type::NUM, "bytes", "The serialized transaction size in bytes"},
1020 [ + - + - ]: 10392 : 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."},
1021 [ + - + - ]: 10392 : RPCResult{RPCResult::Type::NUM, "weight", "The transaction weight as defined in BIP 141."},
1022 [ + - + - ]: 10392 : RPCResult{RPCResult::Type::ARR, "from", "",
1023 : : {
1024 [ + - + - ]: 10392 : RPCResult{RPCResult::Type::NUM, "peer_id", "Peer ID"},
1025 [ + - + + : 15588 : }},
- - ]
1026 [ + - + + : 46764 : };
- - ]
1027 [ + - + - : 36372 : }
+ - + - +
- + - + -
- - ]
1028 : :
1029 : 42 : static UniValue OrphanToJSON(const node::TxOrphanage::OrphanInfo& orphan)
1030 : : {
1031 : 42 : UniValue o(UniValue::VOBJ);
1032 [ + - + - : 84 : o.pushKV("txid", orphan.tx->GetHash().ToString());
+ - + - ]
1033 [ + - + - : 84 : o.pushKV("wtxid", orphan.tx->GetWitnessHash().ToString());
+ - + - ]
1034 [ + - + - : 84 : o.pushKV("bytes", orphan.tx->GetTotalSize());
+ - + - ]
1035 [ + - + - : 84 : o.pushKV("vsize", GetVirtualTransactionSize(*orphan.tx));
+ - + - ]
1036 [ + - + - : 84 : o.pushKV("weight", GetTransactionWeight(*orphan.tx));
+ - ]
1037 : 42 : UniValue from(UniValue::VARR);
1038 [ + + ]: 90 : for (const auto fromPeer: orphan.announcers) {
1039 [ + - + - ]: 48 : from.push_back(fromPeer);
1040 : : }
1041 [ + - + - : 84 : o.pushKV("from", from);
+ - ]
1042 : 42 : return o;
1043 : 42 : }
1044 : :
1045 : 2598 : static RPCHelpMan getorphantxs()
1046 : : {
1047 : 2598 : return RPCHelpMan{
1048 : 2598 : "getorphantxs",
1049 [ + - ]: 5196 : "Shows transactions in the tx orphanage.\n"
1050 : : "\nEXPERIMENTAL warning: this call may be changed in future releases.\n",
1051 : : {
1052 [ + - + - : 7794 : {"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",
+ - ]
1053 [ + - ]: 5196 : RPCArgOptions{.skip_type_check = true}},
1054 : : },
1055 : : {
1056 [ + - ]: 2598 : RPCResult{"for verbose = 0",
1057 [ + - + - ]: 5196 : RPCResult::Type::ARR, "", "",
1058 : : {
1059 [ + - + - ]: 5196 : {RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
1060 [ + - + + : 7794 : }},
- - ]
1061 [ + - ]: 5196 : RPCResult{"for verbose = 1",
1062 [ + - + - ]: 5196 : RPCResult::Type::ARR, "", "",
1063 : : {
1064 [ + - + - : 5196 : {RPCResult::Type::OBJ, "", "", OrphanDescription()},
+ - ]
1065 [ + - + + : 7794 : }},
- - ]
1066 [ + - ]: 5196 : RPCResult{"for verbose = 2",
1067 [ + - + - ]: 5196 : RPCResult::Type::ARR, "", "",
1068 : : {
1069 [ + - + - ]: 5196 : {RPCResult::Type::OBJ, "", "",
1070 [ + - + - : 12990 : Cat<std::vector<RPCResult>>(
+ + - - ]
1071 [ + - ]: 5196 : OrphanDescription(),
1072 [ + - + - ]: 5196 : {{RPCResult::Type::STR_HEX, "hex", "The serialized, hex-encoded transaction data"}}
1073 : : )
1074 : : },
1075 [ + - + + : 7794 : }},
- - ]
1076 : : },
1077 : 2598 : RPCExamples{
1078 [ + - + - : 5196 : HelpExampleCli("getorphantxs", "2")
+ - ]
1079 [ + - + - : 10392 : + HelpExampleRpc("getorphantxs", "2")
+ - ]
1080 [ + - ]: 2598 : },
1081 : 2598 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1082 : : {
1083 : 225 : const NodeContext& node = EnsureAnyNodeContext(request.context);
1084 : 225 : PeerManager& peerman = EnsurePeerman(node);
1085 : 225 : std::vector<node::TxOrphanage::OrphanInfo> orphanage = peerman.GetOrphanTransactions();
1086 : :
1087 [ + - + + ]: 225 : int verbosity{ParseVerbosity(request.params[0], /*default_verbosity=*/0, /*allow_bool*/false)};
1088 : :
1089 : 223 : UniValue ret(UniValue::VARR);
1090 : :
1091 [ + + ]: 223 : if (verbosity == 0) {
1092 [ + + ]: 18491 : for (auto const& orphan : orphanage) {
1093 [ + - + - : 18302 : ret.push_back(orphan.tx->GetHash().ToString());
+ - ]
1094 : : }
1095 [ + + ]: 34 : } else if (verbosity == 1) {
1096 [ + + ]: 55 : for (auto const& orphan : orphanage) {
1097 [ + - + - ]: 32 : ret.push_back(OrphanToJSON(orphan));
1098 : : }
1099 [ + + ]: 11 : } else if (verbosity == 2) {
1100 [ + + ]: 19 : for (auto const& orphan : orphanage) {
1101 [ + - ]: 10 : UniValue o{OrphanToJSON(orphan)};
1102 [ + - + - : 20 : o.pushKV("hex", EncodeHexTx(*orphan.tx));
+ - + - ]
1103 [ + - + - ]: 10 : ret.push_back(o);
1104 : 10 : }
1105 : : } else {
1106 [ + - + - : 4 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid verbosity value " + ToString(verbosity));
+ - ]
1107 : : }
1108 : :
1109 : 221 : return ret;
1110 : 227 : },
1111 [ + - + - : 28578 : };
+ - + - +
+ + + - -
- - ]
1112 [ + - + - : 20784 : }
+ - + - +
- + - + -
+ - - - ]
1113 : :
1114 : 2499 : static RPCHelpMan submitpackage()
1115 : : {
1116 : 2499 : return RPCHelpMan{"submitpackage",
1117 [ + - ]: 4998 : "Submit a package of raw transactions (serialized, hex-encoded) to local node.\n"
1118 : : "The package will be validated according to consensus and mempool policy rules. If any transaction passes, it will be accepted to mempool.\n"
1119 : : "This RPC is experimental and the interface may be unstable. Refer to doc/policy/packages.md for documentation on package policies.\n"
1120 : : "Warning: successful submission does not mean the transactions will propagate throughout the network.\n"
1121 : : ,
1122 : : {
1123 [ + - + - ]: 4998 : {"package", RPCArg::Type::ARR, RPCArg::Optional::NO, "An array of raw transactions.\n"
1124 : : "The package must consist of a transaction with (some, all, or none of) its unconfirmed parents. A single transaction is permitted.\n"
1125 : : "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"
1126 : : "The package must be topologically sorted, with the child being the last element in the array if there are multiple elements.",
1127 : : {
1128 [ + - + - ]: 4998 : {"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
1129 : : },
1130 : : },
1131 [ + - + - : 4998 : {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())},
+ - ]
1132 [ + - ]: 4998 : "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT +
1133 : 2499 : "/kvB.\nFee rates larger than 1BTC/kvB are rejected.\nSet to 0 to accept any fee rate."},
1134 [ + - + - : 4998 : {"maxburnamount", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_BURN_AMOUNT)},
+ - ]
1135 [ + - ]: 4998 : "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"
1136 : : "If burning funds through unspendable outputs is desired, increase this value.\n"
1137 : 2499 : "This check is based on heuristics and does not guarantee spendability of outputs.\n"
1138 : : },
1139 : : },
1140 [ + - ]: 4998 : RPCResult{
1141 [ + - + - ]: 4998 : RPCResult::Type::OBJ, "", "",
1142 : : {
1143 [ + - + - ]: 4998 : {RPCResult::Type::STR, "package_msg", "The transaction package result message. \"success\" indicates all transactions were accepted into or are already in the mempool."},
1144 [ + - + - ]: 4998 : {RPCResult::Type::OBJ_DYN, "tx-results", "The transaction results keyed by wtxid. An entry is returned for every submitted wtxid.",
1145 : : {
1146 [ + - + - ]: 4998 : {RPCResult::Type::OBJ, "wtxid", "transaction wtxid", {
1147 [ + - + - ]: 4998 : {RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
1148 [ + - + - ]: 4998 : {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."},
1149 [ + - + - ]: 4998 : {RPCResult::Type::NUM, "vsize", /*optional=*/true, "Sigops-adjusted virtual transaction size."},
1150 [ + - + - ]: 4998 : {RPCResult::Type::OBJ, "fees", /*optional=*/true, "Transaction fees", {
1151 [ + - + - ]: 4998 : {RPCResult::Type::STR_AMOUNT, "base", "transaction fee in " + CURRENCY_UNIT},
1152 [ + - + - ]: 4998 : {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."},
1153 [ + - + - ]: 4998 : {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.",
1154 [ + - + - ]: 4998 : {{RPCResult::Type::STR_HEX, "", "transaction wtxid in hex"},
1155 : : }},
1156 : : }},
1157 [ + - + - ]: 4998 : {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."},
1158 : : }}
1159 : : }},
1160 [ + - + - ]: 4998 : {RPCResult::Type::ARR, "replaced-transactions", /*optional=*/true, "List of txids of replaced transactions",
1161 : : {
1162 [ + - + - ]: 4998 : {RPCResult::Type::STR_HEX, "", "The transaction id"},
1163 : : }},
1164 : : },
1165 [ + - + - : 72471 : },
+ - + - +
- + - + -
+ + + + +
+ + + + +
+ + - - -
- - - - -
- - - - ]
1166 : 2499 : RPCExamples{
1167 [ + - + - : 4998 : HelpExampleRpc("submitpackage", R"(["raw-parent-tx-1", "raw-parent-tx-2", "raw-child-tx"])") +
+ - ]
1168 [ + - + - : 7497 : HelpExampleCli("submitpackage", R"('["raw-tx-without-unconfirmed-parents"]')")
+ - + - ]
1169 [ + - ]: 2499 : },
1170 : 2499 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1171 : : {
1172 : 118 : const UniValue raw_transactions = request.params[0].get_array();
1173 [ - + + + : 118 : if (raw_transactions.empty() || raw_transactions.size() > MAX_PACKAGE_COUNT) {
+ + ]
1174 : 2 : throw JSONRPCError(RPC_INVALID_PARAMETER,
1175 [ + - + - : 6 : "Array must contain between 1 and " + ToString(MAX_PACKAGE_COUNT) + " transactions.");
+ - ]
1176 : : }
1177 : :
1178 : : // Fee check needs to be run with chainstate and package context
1179 [ + - + - ]: 116 : const CFeeRate max_raw_tx_fee_rate{ParseFeeRate(self.Arg<UniValue>("maxfeerate"))};
1180 [ + + ]: 116 : std::optional<CFeeRate> client_maxfeerate{max_raw_tx_fee_rate};
1181 : : // 0-value is special; it's mapped to no sanity check
1182 [ + + ]: 116 : if (max_raw_tx_fee_rate == CFeeRate(0)) {
1183 : 29 : client_maxfeerate = std::nullopt;
1184 : : }
1185 : :
1186 : : // Burn sanity check is run with no context
1187 [ + - + + : 116 : const CAmount max_burn_amount = request.params[2].isNull() ? 0 : AmountFromValue(request.params[2]);
+ - + - ]
1188 : :
1189 : 116 : std::vector<CTransactionRef> txns;
1190 [ - + + - ]: 116 : txns.reserve(raw_transactions.size());
1191 [ + - + + ]: 495 : for (const auto& rawtx : raw_transactions.getValues()) {
1192 [ + - ]: 381 : CMutableTransaction mtx;
1193 [ + - + - : 381 : if (!DecodeHexTx(mtx, rawtx.get_str())) {
+ + ]
1194 : 1 : throw JSONRPCError(RPC_DESERIALIZATION_ERROR,
1195 [ + - + - : 3 : "TX decode failed: " + rawtx.get_str() + " Make sure the tx has at least one input.");
+ - ]
1196 : : }
1197 : :
1198 [ + + ]: 893 : for (const auto& out : mtx.vout) {
1199 [ + + + - : 514 : if((out.scriptPubKey.IsUnspendable() || !out.scriptPubKey.HasValidOps()) && out.nValue > max_burn_amount) {
- + + + ]
1200 [ + - + - ]: 2 : throw JSONRPCTransactionError(TransactionError::MAX_BURN_EXCEEDED);
1201 : : }
1202 : : }
1203 : :
1204 [ + - + - ]: 1137 : txns.emplace_back(MakeTransactionRef(std::move(mtx)));
1205 : 381 : }
1206 [ + - ]: 114 : CHECK_NONFATAL(!txns.empty());
1207 [ - + + + : 114 : if (txns.size() > 1 && !IsChildWithParentsTree(txns)) {
+ - + + ]
1208 [ + - + - ]: 4 : throw JSONRPCTransactionError(TransactionError::INVALID_PACKAGE, "package topology disallowed. not child-with-parents or parents depend on each other.");
1209 : : }
1210 : :
1211 [ + - ]: 112 : NodeContext& node = EnsureAnyNodeContext(request.context);
1212 [ + - ]: 112 : CTxMemPool& mempool = EnsureMemPool(node);
1213 [ + - + - ]: 112 : Chainstate& chainstate = EnsureChainman(node).ActiveChainstate();
1214 [ + - + - ]: 336 : const auto package_result = WITH_LOCK(::cs_main, return ProcessNewPackage(chainstate, mempool, txns, /*test_accept=*/ false, client_maxfeerate));
1215 : :
1216 [ + - ]: 112 : std::string package_msg = "success";
1217 : :
1218 : : // First catch package-wide errors, continue if we can
1219 [ + - + - ]: 112 : switch(package_result.m_state.GetResult()) {
1220 : 66 : case PackageValidationResult::PCKG_RESULT_UNSET:
1221 : 66 : {
1222 : : // Belt-and-suspenders check; everything should be successful here
1223 [ - + + - ]: 66 : CHECK_NONFATAL(package_result.m_tx_results.size() == txns.size());
1224 [ + + ]: 293 : for (const auto& tx : txns) {
1225 [ + - + - ]: 227 : CHECK_NONFATAL(mempool.exists(tx->GetHash()));
1226 : : }
1227 : : break;
1228 : : }
1229 : 0 : case PackageValidationResult::PCKG_MEMPOOL_ERROR:
1230 : 0 : {
1231 : : // This only happens with internal bug; user should stop and report
1232 : 0 : throw JSONRPCTransactionError(TransactionError::MEMPOOL_ERROR,
1233 [ # # # # ]: 0 : package_result.m_state.GetRejectReason());
1234 : : }
1235 : 46 : case PackageValidationResult::PCKG_POLICY:
1236 : 46 : case PackageValidationResult::PCKG_TX:
1237 : 46 : {
1238 : : // Package-wide error we want to return, but we also want to return individual responses
1239 [ + - ]: 46 : package_msg = package_result.m_state.ToString();
1240 [ - + + + : 48 : CHECK_NONFATAL(package_result.m_tx_results.size() == txns.size() ||
+ - + - ]
1241 : : package_result.m_tx_results.empty());
1242 : : break;
1243 : : }
1244 : : }
1245 : :
1246 : 112 : size_t num_broadcast{0};
1247 [ + + ]: 483 : for (const auto& tx : txns) {
1248 : : // We don't want to re-submit the txn for validation in BroadcastTransaction
1249 [ + - + + ]: 371 : if (!mempool.exists(tx->GetHash())) {
1250 : 82 : continue;
1251 : : }
1252 : :
1253 : : // We do not expect an error here; we are only broadcasting things already/still in mempool
1254 [ + - ]: 289 : std::string err_string;
1255 [ + - + - ]: 289 : const auto err = BroadcastTransaction(node,
1256 : : tx,
1257 : : err_string,
1258 [ + - ]: 289 : /*max_tx_fee=*/0,
1259 : : node::TxBroadcast::MEMPOOL_AND_BROADCAST_TO_ALL,
1260 : : /*wait_callback=*/true);
1261 [ - + ]: 289 : if (err != TransactionError::OK) {
1262 : 0 : throw JSONRPCTransactionError(err,
1263 [ # # ]: 0 : strprintf("transaction broadcast failed: %s (%d transactions were broadcast successfully)",
1264 [ # # ]: 0 : err_string, num_broadcast));
1265 : : }
1266 : 289 : num_broadcast++;
1267 : 289 : }
1268 : :
1269 : 112 : UniValue rpc_result{UniValue::VOBJ};
1270 [ + - + - : 224 : rpc_result.pushKV("package_msg", package_msg);
+ - ]
1271 : 224 : UniValue tx_result_map{UniValue::VOBJ};
1272 : 224 : std::set<Txid> replaced_txids;
1273 [ + + ]: 483 : for (const auto& tx : txns) {
1274 : 371 : UniValue result_inner{UniValue::VOBJ};
1275 [ + - + - : 742 : result_inner.pushKV("txid", tx->GetHash().GetHex());
+ - + - ]
1276 [ + - ]: 371 : const auto wtxid_hex = tx->GetWitnessHash().GetHex();
1277 : 371 : auto it = package_result.m_tx_results.find(tx->GetWitnessHash());
1278 [ + + ]: 371 : if (it == package_result.m_tx_results.end()) {
1279 : : // No per-tx result for this wtxid
1280 : : // Current invariant: per-tx results are all-or-none (every member or empty on package abort).
1281 : : // If any exist yet this one is missing, it's an unexpected partial map.
1282 [ + - ]: 6 : CHECK_NONFATAL(package_result.m_tx_results.empty());
1283 [ + - + - : 12 : result_inner.pushKV("error", "package-not-validated");
+ - ]
1284 [ - + + - ]: 18 : tx_result_map.pushKV(wtxid_hex, std::move(result_inner));
1285 : 6 : continue;
1286 : : }
1287 [ - + + - ]: 365 : const auto& tx_result = it->second;
1288 [ - + + - ]: 365 : switch(it->second.m_result_type) {
1289 : 0 : case MempoolAcceptResult::ResultType::DIFFERENT_WITNESS:
1290 [ # # # # : 0 : result_inner.pushKV("other-wtxid", it->second.m_other_wtxid.value().GetHex());
# # # # #
# ]
1291 : 0 : break;
1292 : 77 : case MempoolAcceptResult::ResultType::INVALID:
1293 [ + - + - : 154 : result_inner.pushKV("error", it->second.m_state.ToString());
+ - + - ]
1294 : 77 : break;
1295 : 288 : case MempoolAcceptResult::ResultType::VALID:
1296 : 288 : case MempoolAcceptResult::ResultType::MEMPOOL_ENTRY:
1297 [ + - + - : 576 : result_inner.pushKV("vsize", it->second.m_vsize.value());
+ - + - ]
1298 : 288 : UniValue fees(UniValue::VOBJ);
1299 [ + - + - : 576 : fees.pushKV("base", ValueFromAmount(it->second.m_base_fees.value()));
+ - + - ]
1300 [ + + ]: 288 : if (tx_result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
1301 : : // Effective feerate is not provided for MEMPOOL_ENTRY transactions even
1302 : : // though modified fees is known, because it is unknown whether package
1303 : : // feerate was used when it was originally submitted.
1304 [ + - + - : 370 : fees.pushKV("effective-feerate", ValueFromAmount(tx_result.m_effective_feerate.value().GetFeePerK()));
+ - + - ]
1305 : 185 : UniValue effective_includes_res(UniValue::VARR);
1306 [ + - + + ]: 438 : for (const auto& wtxid : tx_result.m_wtxids_fee_calculations.value()) {
1307 [ + - + - : 253 : effective_includes_res.push_back(wtxid.ToString());
+ - ]
1308 : : }
1309 [ + - + - ]: 370 : fees.pushKV("effective-includes", std::move(effective_includes_res));
1310 : 185 : }
1311 [ + - + - ]: 576 : result_inner.pushKV("fees", std::move(fees));
1312 [ + + ]: 671 : for (const auto& ptx : it->second.m_replaced_transactions) {
1313 [ + - ]: 383 : replaced_txids.insert(ptx->GetHash());
1314 : : }
1315 : 288 : break;
1316 : : }
1317 [ - + + - ]: 1095 : tx_result_map.pushKV(wtxid_hex, std::move(result_inner));
1318 : 371 : }
1319 [ + - + - ]: 224 : rpc_result.pushKV("tx-results", std::move(tx_result_map));
1320 : 224 : UniValue replaced_list(UniValue::VARR);
1321 [ + - + - : 495 : for (const auto& txid : replaced_txids) replaced_list.push_back(txid.ToString());
+ - + + ]
1322 [ + - + - ]: 224 : rpc_result.pushKV("replaced-transactions", std::move(replaced_list));
1323 : 224 : return rpc_result;
1324 : 122 : },
1325 [ + - + - : 24990 : };
+ - + + +
+ - - -
- ]
1326 [ + - + - : 54978 : }
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - - - -
- - - -
- ]
1327 : :
1328 : 1319 : void RegisterMempoolRPCCommands(CRPCTable& t)
1329 : : {
1330 : 1319 : static const CRPCCommand commands[]{
1331 [ + - ]: 2370 : {"rawtransactions", &sendrawtransaction},
1332 [ + - ]: 2370 : {"rawtransactions", &testmempoolaccept},
1333 [ + - ]: 2370 : {"blockchain", &getmempoolancestors},
1334 [ + - ]: 2370 : {"blockchain", &getmempooldescendants},
1335 [ + - ]: 2370 : {"blockchain", &getmempoolentry},
1336 [ + - ]: 2370 : {"blockchain", &getmempoolcluster},
1337 [ + - ]: 2370 : {"blockchain", &gettxspendingprevout},
1338 [ + - ]: 2370 : {"blockchain", &getmempoolinfo},
1339 [ + - ]: 2370 : {"hidden", &getmempoolfeeratediagram},
1340 [ + - ]: 2370 : {"blockchain", &getrawmempool},
1341 [ + - ]: 2370 : {"blockchain", &importmempool},
1342 [ + - ]: 2370 : {"blockchain", &savemempool},
1343 [ + - ]: 2370 : {"hidden", &getorphantxs},
1344 [ + - ]: 2370 : {"rawtransactions", &submitpackage},
1345 [ + + + - : 17909 : };
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - -
- ]
1346 [ + + ]: 19785 : for (const auto& c : commands) {
1347 : 18466 : t.appendCommand(c.name, &c);
1348 : : }
1349 : 1319 : }
|