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