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