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 <core_io.h>
# 9 : : #include <fs.h>
# 10 : : #include <policy/rbf.h>
# 11 : : #include <primitives/transaction.h>
# 12 : : #include <rpc/server.h>
# 13 : : #include <rpc/server_util.h>
# 14 : : #include <rpc/util.h>
# 15 : : #include <txmempool.h>
# 16 : : #include <univalue.h>
# 17 : : #include <util/moneystr.h>
# 18 : : #include <validation.h>
# 19 : :
# 20 : : using node::DEFAULT_MAX_RAW_TX_FEE_RATE;
# 21 : : using node::NodeContext;
# 22 : :
# 23 : : static RPCHelpMan sendrawtransaction()
# 24 : 12786 : {
# 25 : 12786 : return RPCHelpMan{"sendrawtransaction",
# 26 : 12786 : "\nSubmit a raw transaction (serialized, hex-encoded) to local node and network.\n"
# 27 : 12786 : "\nThe transaction will be sent unconditionally to all peers, so using sendrawtransaction\n"
# 28 : 12786 : "for manual rebroadcast may degrade privacy by leaking the transaction's origin, as\n"
# 29 : 12786 : "nodes will normally not rebroadcast non-wallet transactions already in their mempool.\n"
# 30 : 12786 : "\nA specific exception, RPC_TRANSACTION_ALREADY_IN_CHAIN, may throw if the transaction cannot be added to the mempool.\n"
# 31 : 12786 : "\nRelated RPCs: createrawtransaction, signrawtransactionwithkey\n",
# 32 : 12786 : {
# 33 : 12786 : {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"},
# 34 : 12786 : {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())},
# 35 : 12786 : "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT +
# 36 : 12786 : "/kvB.\nSet to 0 to accept any fee rate.\n"},
# 37 : 12786 : },
# 38 : 12786 : RPCResult{
# 39 : 12786 : RPCResult::Type::STR_HEX, "", "The transaction hash in hex"
# 40 : 12786 : },
# 41 : 12786 : RPCExamples{
# 42 : 12786 : "\nCreate a transaction\n"
# 43 : 12786 : + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") +
# 44 : 12786 : "Sign the transaction, and get back the hex\n"
# 45 : 12786 : + HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") +
# 46 : 12786 : "\nSend the transaction (signed hex)\n"
# 47 : 12786 : + HelpExampleCli("sendrawtransaction", "\"signedhex\"") +
# 48 : 12786 : "\nAs a JSON-RPC call\n"
# 49 : 12786 : + HelpExampleRpc("sendrawtransaction", "\"signedhex\"")
# 50 : 12786 : },
# 51 : 12786 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
# 52 : 12786 : {
# 53 : 11190 : RPCTypeCheck(request.params, {
# 54 : 11190 : UniValue::VSTR,
# 55 : 11190 : UniValueType(), // VNUM or VSTR, checked inside AmountFromValue()
# 56 : 11190 : });
# 57 : :
# 58 : 11190 : CMutableTransaction mtx;
# 59 [ + + ]: 11190 : if (!DecodeHexTx(mtx, request.params[0].get_str())) {
# 60 : 4 : throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input.");
# 61 : 4 : }
# 62 : 11186 : CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
# 63 : :
# 64 [ + + ]: 11186 : const CFeeRate max_raw_tx_fee_rate = request.params[1].isNull() ?
# 65 : 2197 : DEFAULT_MAX_RAW_TX_FEE_RATE :
# 66 : 11186 : CFeeRate(AmountFromValue(request.params[1]));
# 67 : :
# 68 : 11186 : int64_t virtual_size = GetVirtualTransactionSize(*tx);
# 69 : 11186 : CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size);
# 70 : :
# 71 : 11186 : std::string err_string;
# 72 : 11186 : AssertLockNotHeld(cs_main);
# 73 : 11186 : NodeContext& node = EnsureAnyNodeContext(request.context);
# 74 : 11186 : const TransactionError err = BroadcastTransaction(node, tx, err_string, max_raw_tx_fee, /*relay=*/true, /*wait_callback=*/true);
# 75 [ + + ]: 11186 : if (TransactionError::OK != err) {
# 76 : 4221 : throw JSONRPCTransactionError(err, err_string);
# 77 : 4221 : }
# 78 : :
# 79 : 6965 : return tx->GetHash().GetHex();
# 80 : 11186 : },
# 81 : 12786 : };
# 82 : 12786 : }
# 83 : :
# 84 : : static RPCHelpMan testmempoolaccept()
# 85 : 6815 : {
# 86 : 6815 : return RPCHelpMan{"testmempoolaccept",
# 87 : 6815 : "\nReturns result of mempool acceptance tests indicating if raw transaction(s) (serialized, hex-encoded) would be accepted by mempool.\n"
# 88 : 6815 : "\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"
# 89 : 6815 : "\nIf one transaction fails, other transactions may not be fully validated (the 'allowed' key will be blank).\n"
# 90 : 6815 : "\nThe maximum number of transactions allowed is " + ToString(MAX_PACKAGE_COUNT) + ".\n"
# 91 : 6815 : "\nThis checks if transactions violate the consensus or policy rules.\n"
# 92 : 6815 : "\nSee sendrawtransaction call.\n",
# 93 : 6815 : {
# 94 : 6815 : {"rawtxs", RPCArg::Type::ARR, RPCArg::Optional::NO, "An array of hex strings of raw transactions.",
# 95 : 6815 : {
# 96 : 6815 : {"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
# 97 : 6815 : },
# 98 : 6815 : },
# 99 : 6815 : {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())},
# 100 : 6815 : "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT + "/kvB\n"},
# 101 : 6815 : },
# 102 : 6815 : RPCResult{
# 103 : 6815 : RPCResult::Type::ARR, "", "The result of the mempool acceptance test for each raw transaction in the input array.\n"
# 104 : 6815 : "Returns results for each transaction in the same order they were passed in.\n"
# 105 : 6815 : "Transactions that cannot be fully validated due to failures in other transactions will not contain an 'allowed' result.\n",
# 106 : 6815 : {
# 107 : 6815 : {RPCResult::Type::OBJ, "", "",
# 108 : 6815 : {
# 109 : 6815 : {RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},
# 110 : 6815 : {RPCResult::Type::STR_HEX, "wtxid", "The transaction witness hash in hex"},
# 111 : 6815 : {RPCResult::Type::STR, "package-error", /*optional=*/true, "Package validation error, if any (only possible if rawtxs had more than 1 transaction)."},
# 112 : 6815 : {RPCResult::Type::BOOL, "allowed", /*optional=*/true, "Whether this tx would be accepted to the mempool and pass client-specified maxfeerate. "
# 113 : 6815 : "If not present, the tx was not fully validated due to a failure in another tx in the list."},
# 114 : 6815 : {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)"},
# 115 : 6815 : {RPCResult::Type::OBJ, "fees", /*optional=*/true, "Transaction fees (only present if 'allowed' is true)",
# 116 : 6815 : {
# 117 : 6815 : {RPCResult::Type::STR_AMOUNT, "base", "transaction fee in " + CURRENCY_UNIT},
# 118 : 6815 : }},
# 119 : 6815 : {RPCResult::Type::STR, "reject-reason", /*optional=*/true, "Rejection string (only present when 'allowed' is false)"},
# 120 : 6815 : }},
# 121 : 6815 : }
# 122 : 6815 : },
# 123 : 6815 : RPCExamples{
# 124 : 6815 : "\nCreate a transaction\n"
# 125 : 6815 : + HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") +
# 126 : 6815 : "Sign the transaction, and get back the hex\n"
# 127 : 6815 : + HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") +
# 128 : 6815 : "\nTest acceptance of the transaction (signed hex)\n"
# 129 : 6815 : + HelpExampleCli("testmempoolaccept", R"('["signedhex"]')") +
# 130 : 6815 : "\nAs a JSON-RPC call\n"
# 131 : 6815 : + HelpExampleRpc("testmempoolaccept", "[\"signedhex\"]")
# 132 : 6815 : },
# 133 : 6815 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
# 134 : 6815 : {
# 135 : 5221 : RPCTypeCheck(request.params, {
# 136 : 5221 : UniValue::VARR,
# 137 : 5221 : UniValueType(), // VNUM or VSTR, checked inside AmountFromValue()
# 138 : 5221 : });
# 139 : 5221 : const UniValue raw_transactions = request.params[0].get_array();
# 140 [ + + ][ + + ]: 5221 : if (raw_transactions.size() < 1 || raw_transactions.size() > MAX_PACKAGE_COUNT) {
# 141 : 2 : throw JSONRPCError(RPC_INVALID_PARAMETER,
# 142 : 2 : "Array must contain between 1 and " + ToString(MAX_PACKAGE_COUNT) + " transactions.");
# 143 : 2 : }
# 144 : :
# 145 [ + + ]: 5219 : const CFeeRate max_raw_tx_fee_rate = request.params[1].isNull() ?
# 146 : 5204 : DEFAULT_MAX_RAW_TX_FEE_RATE :
# 147 : 5219 : CFeeRate(AmountFromValue(request.params[1]));
# 148 : :
# 149 : 5219 : std::vector<CTransactionRef> txns;
# 150 : 5219 : txns.reserve(raw_transactions.size());
# 151 [ + + ]: 5743 : for (const auto& rawtx : raw_transactions.getValues()) {
# 152 : 5743 : CMutableTransaction mtx;
# 153 [ + + ]: 5743 : if (!DecodeHexTx(mtx, rawtx.get_str())) {
# 154 : 1 : throw JSONRPCError(RPC_DESERIALIZATION_ERROR,
# 155 : 1 : "TX decode failed: " + rawtx.get_str() + " Make sure the tx has at least one input.");
# 156 : 1 : }
# 157 : 5742 : txns.emplace_back(MakeTransactionRef(std::move(mtx)));
# 158 : 5742 : }
# 159 : :
# 160 : 5218 : NodeContext& node = EnsureAnyNodeContext(request.context);
# 161 : 5218 : CTxMemPool& mempool = EnsureMemPool(node);
# 162 : 5218 : ChainstateManager& chainman = EnsureChainman(node);
# 163 : 5218 : CChainState& chainstate = chainman.ActiveChainstate();
# 164 : 5218 : const PackageMempoolAcceptResult package_result = [&] {
# 165 : 5217 : LOCK(::cs_main);
# 166 [ + + ]: 5217 : if (txns.size() > 1) return ProcessNewPackage(chainstate, mempool, txns, /*test_accept=*/true);
# 167 : 5155 : return PackageMempoolAcceptResult(txns[0]->GetWitnessHash(),
# 168 : 5155 : chainman.ProcessTransaction(txns[0], /*test_accept=*/true));
# 169 : 5217 : }();
# 170 : :
# 171 : 5218 : UniValue rpc_result(UniValue::VARR);
# 172 : : // We will check transaction fees while we iterate through txns in order. If any transaction fee
# 173 : : // exceeds maxfeerate, we will leave the rest of the validation results blank, because it
# 174 : : // doesn't make sense to return a validation result for a transaction if its ancestor(s) would
# 175 : : // not be submitted.
# 176 : 5218 : bool exit_early{false};
# 177 [ + + ]: 5742 : for (const auto& tx : txns) {
# 178 : 5742 : UniValue result_inner(UniValue::VOBJ);
# 179 : 5742 : result_inner.pushKV("txid", tx->GetHash().GetHex());
# 180 : 5742 : result_inner.pushKV("wtxid", tx->GetWitnessHash().GetHex());
# 181 [ + + ]: 5742 : if (package_result.m_state.GetResult() == PackageValidationResult::PCKG_POLICY) {
# 182 : 89 : result_inner.pushKV("package-error", package_result.m_state.GetRejectReason());
# 183 : 89 : }
# 184 : 5742 : auto it = package_result.m_tx_results.find(tx->GetWitnessHash());
# 185 [ + + ][ + + ]: 5742 : if (exit_early || it == package_result.m_tx_results.end()) {
# [ + + ]
# 186 : : // Validation unfinished. Just return the txid and wtxid.
# 187 : 98 : rpc_result.push_back(result_inner);
# 188 : 98 : continue;
# 189 : 98 : }
# 190 : 5644 : const auto& tx_result = it->second;
# 191 : : // Package testmempoolaccept doesn't allow transactions to already be in the mempool.
# 192 [ - + ]: 5644 : CHECK_NONFATAL(tx_result.m_result_type != MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);
# 193 [ + + ]: 5644 : if (tx_result.m_result_type == MempoolAcceptResult::ResultType::VALID) {
# 194 : 1557 : const CAmount fee = tx_result.m_base_fees.value();
# 195 : : // Check that fee does not exceed maximum fee
# 196 : 1557 : const int64_t virtual_size = tx_result.m_vsize.value();
# 197 : 1557 : const CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size);
# 198 [ + + ][ + + ]: 1557 : if (max_raw_tx_fee && fee > max_raw_tx_fee) {
# 199 : 6 : result_inner.pushKV("allowed", false);
# 200 : 6 : result_inner.pushKV("reject-reason", "max-fee-exceeded");
# 201 : 6 : exit_early = true;
# 202 : 1551 : } else {
# 203 : : // Only return the fee and vsize if the transaction would pass ATMP.
# 204 : : // These can be used to calculate the feerate.
# 205 : 1551 : result_inner.pushKV("allowed", true);
# 206 : 1551 : result_inner.pushKV("vsize", virtual_size);
# 207 : 1551 : UniValue fees(UniValue::VOBJ);
# 208 : 1551 : fees.pushKV("base", ValueFromAmount(fee));
# 209 : 1551 : result_inner.pushKV("fees", fees);
# 210 : 1551 : }
# 211 : 4087 : } else {
# 212 : 4087 : result_inner.pushKV("allowed", false);
# 213 : 4087 : const TxValidationState state = tx_result.m_state;
# 214 [ + + ]: 4087 : if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {
# 215 : 6 : result_inner.pushKV("reject-reason", "missing-inputs");
# 216 : 4081 : } else {
# 217 : 4081 : result_inner.pushKV("reject-reason", state.GetRejectReason());
# 218 : 4081 : }
# 219 : 4087 : }
# 220 : 5644 : rpc_result.push_back(result_inner);
# 221 : 5644 : }
# 222 : 5218 : return rpc_result;
# 223 : 5218 : },
# 224 : 6815 : };
# 225 : 6815 : }
# 226 : :
# 227 : : static std::vector<RPCResult> MempoolEntryDescription()
# 228 : 15961 : {
# 229 : 15961 : return {
# 230 : 15961 : 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."},
# 231 : 15961 : RPCResult{RPCResult::Type::NUM, "weight", "transaction weight as defined in BIP 141."},
# 232 : 15961 : RPCResult{RPCResult::Type::STR_AMOUNT, "fee", /*optional=*/true,
# 233 : 15961 : "transaction fee, denominated in " + CURRENCY_UNIT + " (DEPRECATED, returned only if config option -deprecatedrpc=fees is passed)"},
# 234 : 15961 : RPCResult{RPCResult::Type::STR_AMOUNT, "modifiedfee", /*optional=*/true,
# 235 : 15961 : "transaction fee with fee deltas used for mining priority, denominated in " + CURRENCY_UNIT +
# 236 : 15961 : " (DEPRECATED, returned only if config option -deprecatedrpc=fees is passed)"},
# 237 : 15961 : RPCResult{RPCResult::Type::NUM_TIME, "time", "local time transaction entered pool in seconds since 1 Jan 1970 GMT"},
# 238 : 15961 : RPCResult{RPCResult::Type::NUM, "height", "block height when transaction entered pool"},
# 239 : 15961 : RPCResult{RPCResult::Type::NUM, "descendantcount", "number of in-mempool descendant transactions (including this one)"},
# 240 : 15961 : RPCResult{RPCResult::Type::NUM, "descendantsize", "virtual transaction size of in-mempool descendants (including this one)"},
# 241 : 15961 : RPCResult{RPCResult::Type::STR_AMOUNT, "descendantfees", /*optional=*/true,
# 242 : 15961 : "transaction fees of in-mempool descendants (including this one) with fee deltas used for mining priority, denominated in " +
# 243 : 15961 : CURRENCY_ATOM + "s (DEPRECATED, returned only if config option -deprecatedrpc=fees is passed)"},
# 244 : 15961 : RPCResult{RPCResult::Type::NUM, "ancestorcount", "number of in-mempool ancestor transactions (including this one)"},
# 245 : 15961 : RPCResult{RPCResult::Type::NUM, "ancestorsize", "virtual transaction size of in-mempool ancestors (including this one)"},
# 246 : 15961 : RPCResult{RPCResult::Type::STR_AMOUNT, "ancestorfees", /*optional=*/true,
# 247 : 15961 : "transaction fees of in-mempool ancestors (including this one) with fee deltas used for mining priority, denominated in " +
# 248 : 15961 : CURRENCY_ATOM + "s (DEPRECATED, returned only if config option -deprecatedrpc=fees is passed)"},
# 249 : 15961 : RPCResult{RPCResult::Type::STR_HEX, "wtxid", "hash of serialized transaction, including witness data"},
# 250 : 15961 : RPCResult{RPCResult::Type::OBJ, "fees", "",
# 251 : 15961 : {
# 252 : 15961 : RPCResult{RPCResult::Type::STR_AMOUNT, "base", "transaction fee, denominated in " + CURRENCY_UNIT},
# 253 : 15961 : RPCResult{RPCResult::Type::STR_AMOUNT, "modified", "transaction fee with fee deltas used for mining priority, denominated in " + CURRENCY_UNIT},
# 254 : 15961 : 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},
# 255 : 15961 : 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},
# 256 : 15961 : }},
# 257 : 15961 : RPCResult{RPCResult::Type::ARR, "depends", "unconfirmed transactions used as inputs for this transaction",
# 258 : 15961 : {RPCResult{RPCResult::Type::STR_HEX, "transactionid", "parent transaction id"}}},
# 259 : 15961 : RPCResult{RPCResult::Type::ARR, "spentby", "unconfirmed transactions spending outputs from this transaction",
# 260 : 15961 : {RPCResult{RPCResult::Type::STR_HEX, "transactionid", "child transaction id"}}},
# 261 : 15961 : RPCResult{RPCResult::Type::BOOL, "bip125-replaceable", "Whether this transaction could be replaced due to BIP125 (replace-by-fee)"},
# 262 : 15961 : RPCResult{RPCResult::Type::BOOL, "unbroadcast", "Whether this transaction is currently unbroadcast (initial broadcast not yet acknowledged by any peers)"},
# 263 : 15961 : };
# 264 : 15961 : }
# 265 : :
# 266 : : static void entryToJSON(const CTxMemPool& pool, UniValue& info, const CTxMemPoolEntry& e) EXCLUSIVE_LOCKS_REQUIRED(pool.cs)
# 267 : 1346 : {
# 268 : 1346 : AssertLockHeld(pool.cs);
# 269 : :
# 270 : 1346 : info.pushKV("vsize", (int)e.GetTxSize());
# 271 : 1346 : info.pushKV("weight", (int)e.GetTxWeight());
# 272 : : // TODO: top-level fee fields are deprecated. deprecated_fee_fields_enabled blocks should be removed in v24
# 273 : 1346 : const bool deprecated_fee_fields_enabled{IsDeprecatedRPCEnabled("fees")};
# 274 [ + + ]: 1346 : if (deprecated_fee_fields_enabled) {
# 275 : 3 : info.pushKV("fee", ValueFromAmount(e.GetFee()));
# 276 : 3 : info.pushKV("modifiedfee", ValueFromAmount(e.GetModifiedFee()));
# 277 : 3 : }
# 278 : 1346 : info.pushKV("time", count_seconds(e.GetTime()));
# 279 : 1346 : info.pushKV("height", (int)e.GetHeight());
# 280 : 1346 : info.pushKV("descendantcount", e.GetCountWithDescendants());
# 281 : 1346 : info.pushKV("descendantsize", e.GetSizeWithDescendants());
# 282 [ + + ]: 1346 : if (deprecated_fee_fields_enabled) {
# 283 : 3 : info.pushKV("descendantfees", e.GetModFeesWithDescendants());
# 284 : 3 : }
# 285 : 1346 : info.pushKV("ancestorcount", e.GetCountWithAncestors());
# 286 : 1346 : info.pushKV("ancestorsize", e.GetSizeWithAncestors());
# 287 [ + + ]: 1346 : if (deprecated_fee_fields_enabled) {
# 288 : 3 : info.pushKV("ancestorfees", e.GetModFeesWithAncestors());
# 289 : 3 : }
# 290 : 1346 : info.pushKV("wtxid", pool.vTxHashes[e.vTxHashesIdx].first.ToString());
# 291 : :
# 292 : 1346 : UniValue fees(UniValue::VOBJ);
# 293 : 1346 : fees.pushKV("base", ValueFromAmount(e.GetFee()));
# 294 : 1346 : fees.pushKV("modified", ValueFromAmount(e.GetModifiedFee()));
# 295 : 1346 : fees.pushKV("ancestor", ValueFromAmount(e.GetModFeesWithAncestors()));
# 296 : 1346 : fees.pushKV("descendant", ValueFromAmount(e.GetModFeesWithDescendants()));
# 297 : 1346 : info.pushKV("fees", fees);
# 298 : :
# 299 : 1346 : const CTransaction& tx = e.GetTx();
# 300 : 1346 : std::set<std::string> setDepends;
# 301 [ + + ]: 1346 : for (const CTxIn& txin : tx.vin)
# 302 : 11128 : {
# 303 [ + + ]: 11128 : if (pool.exists(GenTxid::Txid(txin.prevout.hash)))
# 304 : 7033 : setDepends.insert(txin.prevout.hash.ToString());
# 305 : 11128 : }
# 306 : :
# 307 : 1346 : UniValue depends(UniValue::VARR);
# 308 [ + + ]: 1346 : for (const std::string& dep : setDepends)
# 309 : 7033 : {
# 310 : 7033 : depends.push_back(dep);
# 311 : 7033 : }
# 312 : :
# 313 : 1346 : info.pushKV("depends", depends);
# 314 : :
# 315 : 1346 : UniValue spent(UniValue::VARR);
# 316 : 1346 : const CTxMemPool::txiter& it = pool.mapTx.find(tx.GetHash());
# 317 : 1346 : const CTxMemPoolEntry::Children& children = it->GetMemPoolChildrenConst();
# 318 [ + + ]: 5783 : for (const CTxMemPoolEntry& child : children) {
# 319 : 5783 : spent.push_back(child.GetTx().GetHash().ToString());
# 320 : 5783 : }
# 321 : :
# 322 : 1346 : info.pushKV("spentby", spent);
# 323 : :
# 324 : : // Add opt-in RBF status
# 325 : 1346 : bool rbfStatus = false;
# 326 : 1346 : RBFTransactionState rbfState = IsRBFOptIn(tx, pool);
# 327 [ - + ]: 1346 : if (rbfState == RBFTransactionState::UNKNOWN) {
# 328 : 0 : throw JSONRPCError(RPC_MISC_ERROR, "Transaction is not in mempool");
# 329 [ + + ]: 1346 : } else if (rbfState == RBFTransactionState::REPLACEABLE_BIP125) {
# 330 : 997 : rbfStatus = true;
# 331 : 997 : }
# 332 : :
# 333 : 1346 : info.pushKV("bip125-replaceable", rbfStatus);
# 334 : 1346 : info.pushKV("unbroadcast", pool.IsUnbroadcastTx(tx.GetHash()));
# 335 : 1346 : }
# 336 : :
# 337 : : UniValue MempoolToJSON(const CTxMemPool& pool, bool verbose, bool include_mempool_sequence)
# 338 : 8996 : {
# 339 [ + + ]: 8996 : if (verbose) {
# 340 [ - + ]: 13 : if (include_mempool_sequence) {
# 341 : 0 : throw JSONRPCError(RPC_INVALID_PARAMETER, "Verbose results cannot contain mempool sequence values.");
# 342 : 0 : }
# 343 : 13 : LOCK(pool.cs);
# 344 : 13 : UniValue o(UniValue::VOBJ);
# 345 [ + + ]: 216 : for (const CTxMemPoolEntry& e : pool.mapTx) {
# 346 : 216 : const uint256& hash = e.GetTx().GetHash();
# 347 : 216 : UniValue info(UniValue::VOBJ);
# 348 : 216 : entryToJSON(pool, info, e);
# 349 : : // Mempool has unique entries so there is no advantage in using
# 350 : : // UniValue::pushKV, which checks if the key already exists in O(N).
# 351 : : // UniValue::__pushKV is used instead which currently is O(1).
# 352 : 216 : o.__pushKV(hash.ToString(), info);
# 353 : 216 : }
# 354 : 13 : return o;
# 355 : 8983 : } else {
# 356 : 8983 : uint64_t mempool_sequence;
# 357 : 8983 : std::vector<uint256> vtxid;
# 358 : 8983 : {
# 359 : 8983 : LOCK(pool.cs);
# 360 : 8983 : pool.queryHashes(vtxid);
# 361 : 8983 : mempool_sequence = pool.GetSequence();
# 362 : 8983 : }
# 363 : 8983 : UniValue a(UniValue::VARR);
# 364 [ + + ]: 8983 : for (const uint256& hash : vtxid)
# 365 : 393787 : a.push_back(hash.ToString());
# 366 : :
# 367 [ + - ]: 8983 : if (!include_mempool_sequence) {
# 368 : 8983 : return a;
# 369 : 8983 : } else {
# 370 : 0 : UniValue o(UniValue::VOBJ);
# 371 : 0 : o.pushKV("txids", a);
# 372 : 0 : o.pushKV("mempool_sequence", mempool_sequence);
# 373 : 0 : return o;
# 374 : 0 : }
# 375 : 8983 : }
# 376 : 8996 : }
# 377 : :
# 378 : : static RPCHelpMan getrawmempool()
# 379 : 10589 : {
# 380 : 10589 : return RPCHelpMan{"getrawmempool",
# 381 : 10589 : "\nReturns all transaction ids in memory pool as a json array of string transaction ids.\n"
# 382 : 10589 : "\nHint: use getmempoolentry to fetch a specific transaction from the mempool.\n",
# 383 : 10589 : {
# 384 : 10589 : {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"},
# 385 : 10589 : {"mempool_sequence", RPCArg::Type::BOOL, RPCArg::Default{false}, "If verbose=false, returns a json object with transaction list and mempool sequence number attached."},
# 386 : 10589 : },
# 387 : 10589 : {
# 388 : 10589 : RPCResult{"for verbose = false",
# 389 : 10589 : RPCResult::Type::ARR, "", "",
# 390 : 10589 : {
# 391 : 10589 : {RPCResult::Type::STR_HEX, "", "The transaction id"},
# 392 : 10589 : }},
# 393 : 10589 : RPCResult{"for verbose = true",
# 394 : 10589 : RPCResult::Type::OBJ_DYN, "", "",
# 395 : 10589 : {
# 396 : 10589 : {RPCResult::Type::OBJ, "transactionid", "", MempoolEntryDescription()},
# 397 : 10589 : }},
# 398 : 10589 : RPCResult{"for verbose = false and mempool_sequence = true",
# 399 : 10589 : RPCResult::Type::OBJ, "", "",
# 400 : 10589 : {
# 401 : 10589 : {RPCResult::Type::ARR, "txids", "",
# 402 : 10589 : {
# 403 : 10589 : {RPCResult::Type::STR_HEX, "", "The transaction id"},
# 404 : 10589 : }},
# 405 : 10589 : {RPCResult::Type::NUM, "mempool_sequence", "The mempool sequence value."},
# 406 : 10589 : }},
# 407 : 10589 : },
# 408 : 10589 : RPCExamples{
# 409 : 10589 : HelpExampleCli("getrawmempool", "true")
# 410 : 10589 : + HelpExampleRpc("getrawmempool", "true")
# 411 : 10589 : },
# 412 : 10589 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
# 413 : 10589 : {
# 414 : 8995 : bool fVerbose = false;
# 415 [ + + ]: 8995 : if (!request.params[0].isNull())
# 416 : 16 : fVerbose = request.params[0].get_bool();
# 417 : :
# 418 : 8995 : bool include_mempool_sequence = false;
# 419 [ - + ]: 8995 : if (!request.params[1].isNull()) {
# 420 : 0 : include_mempool_sequence = request.params[1].get_bool();
# 421 : 0 : }
# 422 : :
# 423 : 8995 : return MempoolToJSON(EnsureAnyMemPool(request.context), fVerbose, include_mempool_sequence);
# 424 : 8995 : },
# 425 : 10589 : };
# 426 : 10589 : }
# 427 : :
# 428 : : static RPCHelpMan getmempoolancestors()
# 429 : 1645 : {
# 430 : 1645 : return RPCHelpMan{"getmempoolancestors",
# 431 : 1645 : "\nIf txid is in the mempool, returns all in-mempool ancestors.\n",
# 432 : 1645 : {
# 433 : 1645 : {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
# 434 : 1645 : {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"},
# 435 : 1645 : },
# 436 : 1645 : {
# 437 : 1645 : RPCResult{"for verbose = false",
# 438 : 1645 : RPCResult::Type::ARR, "", "",
# 439 : 1645 : {{RPCResult::Type::STR_HEX, "", "The transaction id of an in-mempool ancestor transaction"}}},
# 440 : 1645 : RPCResult{"for verbose = true",
# 441 : 1645 : RPCResult::Type::OBJ_DYN, "", "",
# 442 : 1645 : {
# 443 : 1645 : {RPCResult::Type::OBJ, "transactionid", "", MempoolEntryDescription()},
# 444 : 1645 : }},
# 445 : 1645 : },
# 446 : 1645 : RPCExamples{
# 447 : 1645 : HelpExampleCli("getmempoolancestors", "\"mytxid\"")
# 448 : 1645 : + HelpExampleRpc("getmempoolancestors", "\"mytxid\"")
# 449 : 1645 : },
# 450 : 1645 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
# 451 : 1645 : {
# 452 : 51 : bool fVerbose = false;
# 453 [ + + ]: 51 : if (!request.params[1].isNull())
# 454 : 26 : fVerbose = request.params[1].get_bool();
# 455 : :
# 456 : 51 : uint256 hash = ParseHashV(request.params[0], "parameter 1");
# 457 : :
# 458 : 51 : const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
# 459 : 51 : LOCK(mempool.cs);
# 460 : :
# 461 : 51 : CTxMemPool::txiter it = mempool.mapTx.find(hash);
# 462 [ - + ]: 51 : if (it == mempool.mapTx.end()) {
# 463 : 0 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool");
# 464 : 0 : }
# 465 : :
# 466 : 51 : CTxMemPool::setEntries setAncestors;
# 467 : 51 : uint64_t noLimit = std::numeric_limits<uint64_t>::max();
# 468 : 51 : std::string dummy;
# 469 : 51 : mempool.CalculateMemPoolAncestors(*it, setAncestors, noLimit, noLimit, noLimit, noLimit, dummy, false);
# 470 : :
# 471 [ + + ]: 51 : if (!fVerbose) {
# 472 : 25 : UniValue o(UniValue::VARR);
# 473 [ + + ]: 300 : for (CTxMemPool::txiter ancestorIt : setAncestors) {
# 474 : 300 : o.push_back(ancestorIt->GetTx().GetHash().ToString());
# 475 : 300 : }
# 476 : 25 : return o;
# 477 : 26 : } else {
# 478 : 26 : UniValue o(UniValue::VOBJ);
# 479 [ + + ]: 324 : for (CTxMemPool::txiter ancestorIt : setAncestors) {
# 480 : 324 : const CTxMemPoolEntry &e = *ancestorIt;
# 481 : 324 : const uint256& _hash = e.GetTx().GetHash();
# 482 : 324 : UniValue info(UniValue::VOBJ);
# 483 : 324 : entryToJSON(mempool, info, e);
# 484 : 324 : o.pushKV(_hash.ToString(), info);
# 485 : 324 : }
# 486 : 26 : return o;
# 487 : 26 : }
# 488 : 51 : },
# 489 : 1645 : };
# 490 : 1645 : }
# 491 : :
# 492 : : static RPCHelpMan getmempooldescendants()
# 493 : 1645 : {
# 494 : 1645 : return RPCHelpMan{"getmempooldescendants",
# 495 : 1645 : "\nIf txid is in the mempool, returns all in-mempool descendants.\n",
# 496 : 1645 : {
# 497 : 1645 : {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
# 498 : 1645 : {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "True for a json object, false for array of transaction ids"},
# 499 : 1645 : },
# 500 : 1645 : {
# 501 : 1645 : RPCResult{"for verbose = false",
# 502 : 1645 : RPCResult::Type::ARR, "", "",
# 503 : 1645 : {{RPCResult::Type::STR_HEX, "", "The transaction id of an in-mempool descendant transaction"}}},
# 504 : 1645 : RPCResult{"for verbose = true",
# 505 : 1645 : RPCResult::Type::OBJ_DYN, "", "",
# 506 : 1645 : {
# 507 : 1645 : {RPCResult::Type::OBJ, "transactionid", "", MempoolEntryDescription()},
# 508 : 1645 : }},
# 509 : 1645 : },
# 510 : 1645 : RPCExamples{
# 511 : 1645 : HelpExampleCli("getmempooldescendants", "\"mytxid\"")
# 512 : 1645 : + HelpExampleRpc("getmempooldescendants", "\"mytxid\"")
# 513 : 1645 : },
# 514 : 1645 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
# 515 : 1645 : {
# 516 : 51 : bool fVerbose = false;
# 517 [ + + ]: 51 : if (!request.params[1].isNull())
# 518 : 26 : fVerbose = request.params[1].get_bool();
# 519 : :
# 520 : 51 : uint256 hash = ParseHashV(request.params[0], "parameter 1");
# 521 : :
# 522 : 51 : const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
# 523 : 51 : LOCK(mempool.cs);
# 524 : :
# 525 : 51 : CTxMemPool::txiter it = mempool.mapTx.find(hash);
# 526 [ - + ]: 51 : if (it == mempool.mapTx.end()) {
# 527 : 0 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool");
# 528 : 0 : }
# 529 : :
# 530 : 51 : CTxMemPool::setEntries setDescendants;
# 531 : 51 : mempool.CalculateDescendants(it, setDescendants);
# 532 : : // CTxMemPool::CalculateDescendants will include the given tx
# 533 : 51 : setDescendants.erase(it);
# 534 : :
# 535 [ + + ]: 51 : if (!fVerbose) {
# 536 : 25 : UniValue o(UniValue::VARR);
# 537 [ + + ]: 300 : for (CTxMemPool::txiter descendantIt : setDescendants) {
# 538 : 300 : o.push_back(descendantIt->GetTx().GetHash().ToString());
# 539 : 300 : }
# 540 : :
# 541 : 25 : return o;
# 542 : 26 : } else {
# 543 : 26 : UniValue o(UniValue::VOBJ);
# 544 [ + + ]: 324 : for (CTxMemPool::txiter descendantIt : setDescendants) {
# 545 : 324 : const CTxMemPoolEntry &e = *descendantIt;
# 546 : 324 : const uint256& _hash = e.GetTx().GetHash();
# 547 : 324 : UniValue info(UniValue::VOBJ);
# 548 : 324 : entryToJSON(mempool, info, e);
# 549 : 324 : o.pushKV(_hash.ToString(), info);
# 550 : 324 : }
# 551 : 26 : return o;
# 552 : 26 : }
# 553 : 51 : },
# 554 : 1645 : };
# 555 : 1645 : }
# 556 : :
# 557 : : static RPCHelpMan getmempoolentry()
# 558 : 2082 : {
# 559 : 2082 : return RPCHelpMan{"getmempoolentry",
# 560 : 2082 : "\nReturns mempool data for given transaction\n",
# 561 : 2082 : {
# 562 : 2082 : {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id (must be in mempool)"},
# 563 : 2082 : },
# 564 : 2082 : RPCResult{
# 565 : 2082 : RPCResult::Type::OBJ, "", "", MempoolEntryDescription()},
# 566 : 2082 : RPCExamples{
# 567 : 2082 : HelpExampleCli("getmempoolentry", "\"mytxid\"")
# 568 : 2082 : + HelpExampleRpc("getmempoolentry", "\"mytxid\"")
# 569 : 2082 : },
# 570 : 2082 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
# 571 : 2082 : {
# 572 : 488 : uint256 hash = ParseHashV(request.params[0], "parameter 1");
# 573 : :
# 574 : 488 : const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
# 575 : 488 : LOCK(mempool.cs);
# 576 : :
# 577 : 488 : CTxMemPool::txiter it = mempool.mapTx.find(hash);
# 578 [ + + ]: 488 : if (it == mempool.mapTx.end()) {
# 579 : 6 : throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in mempool");
# 580 : 6 : }
# 581 : :
# 582 : 482 : const CTxMemPoolEntry &e = *it;
# 583 : 482 : UniValue info(UniValue::VOBJ);
# 584 : 482 : entryToJSON(mempool, info, e);
# 585 : 482 : return info;
# 586 : 488 : },
# 587 : 2082 : };
# 588 : 2082 : }
# 589 : :
# 590 : : UniValue MempoolInfoToJSON(const CTxMemPool& pool)
# 591 : 910 : {
# 592 : : // Make sure this call is atomic in the pool.
# 593 : 910 : LOCK(pool.cs);
# 594 : 910 : UniValue ret(UniValue::VOBJ);
# 595 : 910 : ret.pushKV("loaded", pool.IsLoaded());
# 596 : 910 : ret.pushKV("size", (int64_t)pool.size());
# 597 : 910 : ret.pushKV("bytes", (int64_t)pool.GetTotalTxSize());
# 598 : 910 : ret.pushKV("usage", (int64_t)pool.DynamicMemoryUsage());
# 599 : 910 : ret.pushKV("total_fee", ValueFromAmount(pool.GetTotalFee()));
# 600 : 910 : int64_t maxmempool{gArgs.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000};
# 601 : 910 : ret.pushKV("maxmempool", maxmempool);
# 602 : 910 : ret.pushKV("mempoolminfee", ValueFromAmount(std::max(pool.GetMinFee(maxmempool), ::minRelayTxFee).GetFeePerK()));
# 603 : 910 : ret.pushKV("minrelaytxfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()));
# 604 : 910 : ret.pushKV("unbroadcastcount", uint64_t{pool.GetUnbroadcastTxs().size()});
# 605 : 910 : return ret;
# 606 : 910 : }
# 607 : :
# 608 : : static RPCHelpMan getmempoolinfo()
# 609 : 2503 : {
# 610 : 2503 : return RPCHelpMan{"getmempoolinfo",
# 611 : 2503 : "\nReturns details on the active state of the TX memory pool.\n",
# 612 : 2503 : {},
# 613 : 2503 : RPCResult{
# 614 : 2503 : RPCResult::Type::OBJ, "", "",
# 615 : 2503 : {
# 616 : 2503 : {RPCResult::Type::BOOL, "loaded", "True if the mempool is fully loaded"},
# 617 : 2503 : {RPCResult::Type::NUM, "size", "Current tx count"},
# 618 : 2503 : {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"},
# 619 : 2503 : {RPCResult::Type::NUM, "usage", "Total memory usage for the mempool"},
# 620 : 2503 : {RPCResult::Type::STR_AMOUNT, "total_fee", "Total fees for the mempool in " + CURRENCY_UNIT + ", ignoring modified fees through prioritisetransaction"},
# 621 : 2503 : {RPCResult::Type::NUM, "maxmempool", "Maximum memory usage for the mempool"},
# 622 : 2503 : {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"},
# 623 : 2503 : {RPCResult::Type::STR_AMOUNT, "minrelaytxfee", "Current minimum relay fee for transactions"},
# 624 : 2503 : {RPCResult::Type::NUM, "unbroadcastcount", "Current number of transactions that haven't passed initial broadcast yet"}
# 625 : 2503 : }},
# 626 : 2503 : RPCExamples{
# 627 : 2503 : HelpExampleCli("getmempoolinfo", "")
# 628 : 2503 : + HelpExampleRpc("getmempoolinfo", "")
# 629 : 2503 : },
# 630 : 2503 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
# 631 : 2503 : {
# 632 : 909 : return MempoolInfoToJSON(EnsureAnyMemPool(request.context));
# 633 : 909 : },
# 634 : 2503 : };
# 635 : 2503 : }
# 636 : :
# 637 : : static RPCHelpMan savemempool()
# 638 : 1596 : {
# 639 : 1596 : return RPCHelpMan{"savemempool",
# 640 : 1596 : "\nDumps the mempool to disk. It will fail until the previous dump is fully loaded.\n",
# 641 : 1596 : {},
# 642 : 1596 : RPCResult{
# 643 : 1596 : RPCResult::Type::OBJ, "", "",
# 644 : 1596 : {
# 645 : 1596 : {RPCResult::Type::STR, "filename", "the directory and file where the mempool was saved"},
# 646 : 1596 : }},
# 647 : 1596 : RPCExamples{
# 648 : 1596 : HelpExampleCli("savemempool", "")
# 649 : 1596 : + HelpExampleRpc("savemempool", "")
# 650 : 1596 : },
# 651 : 1596 : [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
# 652 : 1596 : {
# 653 : 2 : const ArgsManager& args{EnsureAnyArgsman(request.context)};
# 654 : 2 : const CTxMemPool& mempool = EnsureAnyMemPool(request.context);
# 655 : :
# 656 [ - + ]: 2 : if (!mempool.IsLoaded()) {
# 657 : 0 : throw JSONRPCError(RPC_MISC_ERROR, "The mempool was not loaded yet");
# 658 : 0 : }
# 659 : :
# 660 [ + + ]: 2 : if (!DumpMempool(mempool)) {
# 661 : 1 : throw JSONRPCError(RPC_MISC_ERROR, "Unable to dump mempool to disk");
# 662 : 1 : }
# 663 : :
# 664 : 1 : UniValue ret(UniValue::VOBJ);
# 665 : 1 : ret.pushKV("filename", fs::path((args.GetDataDirNet() / "mempool.dat")).u8string());
# 666 : :
# 667 : 1 : return ret;
# 668 : 2 : },
# 669 : 1596 : };
# 670 : 1596 : }
# 671 : :
# 672 : : void RegisterMempoolRPCCommands(CRPCTable& t)
# 673 : 993 : {
# 674 : 993 : static const CRPCCommand commands[]{
# 675 : : // category actor (function)
# 676 : : // -------- ----------------
# 677 : 993 : {"rawtransactions", &sendrawtransaction},
# 678 : 993 : {"rawtransactions", &testmempoolaccept},
# 679 : 993 : {"blockchain", &getmempoolancestors},
# 680 : 993 : {"blockchain", &getmempooldescendants},
# 681 : 993 : {"blockchain", &getmempoolentry},
# 682 : 993 : {"blockchain", &getmempoolinfo},
# 683 : 993 : {"blockchain", &getrawmempool},
# 684 : 993 : {"blockchain", &savemempool},
# 685 : 993 : };
# 686 [ + + ]: 7944 : for (const auto& c : commands) {
# 687 : 7944 : t.appendCommand(c.name, &c);
# 688 : 7944 : }
# 689 : 993 : }
|