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