Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
251};252}254static RPCMethod abortprivatebroadcast()255{256return RPCMethod{257"abortprivatebroadcast",258"Abort private broadcast attempts for a transaction currently being privately broadcast.\n"259"The transaction will be removed from the private broadcast queue.\n"260"This method is only available when running with -privatebroadcast enabled.\n",261{262{"id", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "A transaction identifier to abort. It will be matched against both txid and wtxid for all transactions in the private broadcast queue.\n"263"If the provided id matches a txid that corresponds to multiple transactions with different wtxids, multiple transactions will be removed and returned."},264},265RPCResult{266RPCResult::Type::OBJ, "", "",267{268{RPCResult::Type::ARR, "removed_transactions", "Transactions removed from the private broadcast queue",269{270{RPCResult::Type::OBJ, "", "",271{272{RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},273{RPCResult::Type::STR_HEX, "wtxid", "The transaction witness hash in hex"},274{RPCResult::Type::STR_HEX, "hex", "The serialized, hex-encoded transaction data"},275}},276}},277}278},279RPCExamples{280HelpExampleCli("abortprivatebroadcast", "\"id\"")281+ HelpExampleRpc("abortprivatebroadcast", "\"id\"")282},283[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue284{286const NodeContext& node{EnsureAnyNodeContext(request.context)};287PeerManager& peerman{EnsurePeerman(node)};288if (!peerman.GetInfo().private_broadcast) {289throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Private broadcast is not enabled. Ensure you're running Bitcoin Core with -privatebroadcast=1.");290}292const uint256 id{ParseHashV(self.Arg<UniValue>("id"), "id")};294const auto removed_txs{peerman.AbortPrivateBroadcast(id)};295if (removed_txs.empty()) {296throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not in private broadcast queue. Check getprivatebroadcastinfo.");297}299UniValue removed_transactions(UniValue::VARR);300for (const auto& tx : removed_txs) {301UniValue o(UniValue::VOBJ);302o.pushKV("txid", tx->GetHash().ToString());303o.pushKV("wtxid", tx->GetWitnessHash().ToString());304o.pushKV("hex", EncodeHexTx(*tx));305removed_transactions.push_back(std::move(o));306}307UniValue ret(UniValue::VOBJ);308ret.pushKV("removed_transactions", std::move(removed_transactions));309return ret;310},311};312}314static RPCMethod testmempoolaccept()315{316return RPCMethod{317"testmempoolaccept",318"Returns result of mempool acceptance tests indicating if raw transaction(s) (serialized, hex-encoded) would be accepted by mempool.\n"319"\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"320"\nIf one transaction fails, other transactions may not be fully validated (the 'allowed' key will be blank).\n"321"\nThe maximum number of transactions allowed is " + ToString(MAX_PACKAGE_COUNT) + ".\n"322"\nThis checks if transactions violate the consensus or policy rules.\n"323"\nSee sendrawtransaction call.\n",324{325{"rawtxs", RPCArg::Type::ARR, RPCArg::Optional::NO, "An array of hex strings of raw transactions.",326{327{"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},328},329},330{"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())},331"Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT +332"/kvB.\nFee rates larger than 1BTC/kvB are rejected.\nSet to 0 to accept any fee rate."},333},334RPCResult{335RPCResult::Type::ARR, "", "The result of the mempool acceptance test for each raw transaction in the input array.\n"336"Returns results for each transaction in the same order they were passed in.\n"337"Transactions that cannot be fully validated due to failures in other transactions will not contain an 'allowed' result.\n",338{339{RPCResult::Type::OBJ, "", "",340{341{RPCResult::Type::STR_HEX, "txid", "The transaction hash in hex"},342{RPCResult::Type::STR_HEX, "wtxid", "The transaction witness hash in hex"},343{RPCResult::Type::STR, "package-error", /*optional=*/true, "Package validation error, if any (only possible if rawtxs had more than 1 transaction)."},344{RPCResult::Type::BOOL, "allowed", /*optional=*/true, "Whether this tx would be accepted to the mempool and pass client-specified maxfeerate. "345"If not present, the tx was not fully validated due to a failure in another tx in the list."},346{RPCResult::Type::NUM, "vsize_adjusted", /*optional=*/true, "Maximum of sigop-adjusted size (-bytespersigop) and virtual transaction size as defined in BIP 141 (only present when 'allowed' is true)."},347{RPCResult::Type::NUM, "vsize", /*optional=*/true, "(DEPRECATED) Was previously erroneously described as the BIP 141 vsize, but is actually sigops-adjusted vsize.\n"348"Use vsize_bip141 to actually get that behavior or switch to the explicit vsize_adjusted for retained behavior."},349{RPCResult::Type::NUM, "vsize_bip141", /*optional=*/true, "Virtual transaction size as defined in BIP 141.\n"350"This is different from actual serialized size for witness transactions as witness data is discounted (only present when 'allowed' is true)."},351{RPCResult::Type::OBJ, "fees", /*optional=*/true, "Transaction fees (only present if 'allowed' is true)",352{353{RPCResult::Type::STR_AMOUNT, "base", "transaction fee in " + CURRENCY_UNIT},354{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."},355{RPCResult::Type::ARR, "effective-includes", /*optional=*/false, "transactions whose fees and vsizes are included in effective-feerate.",356{RPCResult{RPCResult::Type::STR_HEX, "", "transaction wtxid in hex"},357}},358}},359{RPCResult::Type::STR, "reject-reason", /*optional=*/true, "Rejection reason (only present when 'allowed' is false)"},360{RPCResult::Type::STR, "reject-details", /*optional=*/true, "Rejection details (only present when 'allowed' is false and rejection details exist)"},361}},362}363},364RPCExamples{365"\nCreate a transaction\n"366+ HelpExampleCli("createrawtransaction", "\"[{\\\"txid\\\" : \\\"mytxid\\\",\\\"vout\\\":0}]\" \"{\\\"myaddress\\\":0.01}\"") +367"Sign the transaction, and get back the hex\n"368+ HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") +369"\nTest acceptance of the transaction (signed hex)\n"370+ HelpExampleCli("testmempoolaccept", R"('["signedhex"]')") +371"\nAs a JSON-RPC call\n"372+ HelpExampleRpc("testmempoolaccept", "[\"signedhex\"]")373},374[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue375{376const UniValue raw_transactions = request.params[0].get_array();377if (raw_transactions.size() < 1 || raw_transactions.size() > MAX_PACKAGE_COUNT) {378throw JSONRPCError(RPC_INVALID_PARAMETER,379"Array must contain between 1 and " + ToString(MAX_PACKAGE_COUNT) + " transactions.");380}382const CFeeRate max_raw_tx_fee_rate{ParseFeeRate(self.Arg<UniValue>("maxfeerate"))};384std::vector<CTransactionRef> txns;385txns.reserve(raw_transactions.size());386for (const auto& rawtx : raw_transactions.getValues()) {387CMutableTransaction mtx;388if (!DecodeHexTx(mtx, rawtx.get_str())) {389throw JSONRPCError(RPC_DESERIALIZATION_ERROR,390"TX decode failed: " + rawtx.get_str() + " Make sure the tx has at least one input.");391}392txns.emplace_back(MakeTransactionRef(std::move(mtx)));393}395NodeContext& node = EnsureAnyNodeContext(request.context);396CTxMemPool& mempool = EnsureMemPool(node);397ChainstateManager& chainman = EnsureChainman(node);398Chainstate& chainstate = chainman.ActiveChainstate();399const PackageMempoolAcceptResult package_result = [&] {400LOCK(::cs_main);401if (txns.size() > 1) return ProcessNewPackage(chainstate, mempool, txns, /*test_accept=*/true, /*client_maxfeerate=*/{});402return PackageMempoolAcceptResult(txns[0]->GetWitnessHash(),403chainman.ProcessTransaction(txns[0], /*test_accept=*/true));404}();406UniValue rpc_result(UniValue::VARR);407// We will check transaction fees while we iterate through txns in order. If any transaction fee408// exceeds maxfeerate, we will leave the rest of the validation results blank, because it409// doesn't make sense to return a validation result for a transaction if its ancestor(s) would410// not be submitted.411bool exit_early{false};412for (const auto& tx : txns) {413UniValue result_inner(UniValue::VOBJ);414result_inner.pushKV("txid", tx->GetHash().GetHex());415result_inner.pushKV("wtxid", tx->GetWitnessHash().GetHex());416if (package_result.m_state.GetResult() == PackageValidationResult::PCKG_POLICY) {417result_inner.pushKV("package-error", package_result.m_state.ToString());418}419auto it = package_result.m_tx_results.find(tx->GetWitnessHash());420if (exit_early || it == package_result.m_tx_results.end()) {421// Validation unfinished. Just return the txid and wtxid.422rpc_result.push_back(std::move(result_inner));423continue;424}425const auto& tx_result = it->second;426// Package testmempoolaccept doesn't allow transactions to already be in the mempool.427CHECK_NONFATAL(tx_result.m_result_type != MempoolAcceptResult::ResultType::MEMPOOL_ENTRY);428if (tx_result.m_result_type == MempoolAcceptResult::ResultType::VALID) {429const CAmount fee = tx_result.m_base_fees.value();430// Check that fee does not exceed maximum fee431const int64_t virtual_size = tx_result.m_vsize.value();432const CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size);433if (max_raw_tx_fee && fee > max_raw_tx_fee) {434result_inner.pushKV("allowed", false);435result_inner.pushKV("reject-reason", "max-fee-exceeded");436exit_early = true;437} else {438// Only return the fee and vsize if the transaction would pass ATMP.439// These can be used to calculate the feerate.440result_inner.pushKV("allowed", true);441result_inner.pushKV("vsize_adjusted", virtual_size);442result_inner.pushKV("vsize", virtual_size);443result_inner.pushKV("vsize_bip141", GetVirtualTransactionSize(*tx));444UniValue fees(UniValue::VOBJ);445fees.pushKV("base", ValueFromAmount(fee));446fees.pushKV("effective-feerate", ValueFromAmount(tx_result.m_effective_feerate.value().GetFeePerK()));447UniValue effective_includes_res(UniValue::VARR);448for (const auto& wtxid : tx_result.m_wtxids_fee_calculations.value()) {449effective_includes_res.push_back(wtxid.ToString());450}451fees.pushKV("effective-includes", std::move(effective_includes_res));452result_inner.pushKV("fees", std::move(fees));453}454} else {455result_inner.pushKV("allowed", false);456const TxValidationState state = tx_result.m_state;457if (state.GetResult() == TxValidationResult::TX_MISSING_INPUTS) {458result_inner.pushKV("reject-reason", "missing-inputs");459} else {460result_inner.pushKV("reject-reason", state.GetRejectReason());461result_inner.pushKV("reject-details", state.ToString());462}463}464rpc_result.push_back(std::move(result_inner));465}466return rpc_result;467},468};469}471static std::vector<RPCResult> ClusterDescription()472{473return {474RPCResult{RPCResult::Type::NUM, "clusterweight", "total sigops-adjusted weight (as defined in BIP 141 and modified by '-bytespersigop')"},475RPCResult{RPCResult::Type::NUM, "txcount", "number of transactions"},476RPCResult{RPCResult::Type::ARR, "chunks", "chunks in this cluster (in mining order)",477{RPCResult{RPCResult::Type::OBJ, "chunk", "",478{479RPCResult{RPCResult::Type::STR_AMOUNT, "chunkfee", "fees of the transactions in this chunk"},480RPCResult{RPCResult::Type::NUM, "chunkweight", "sigops-adjusted weight of all transactions in this chunk"},481RPCResult{RPCResult::Type::ARR, "txs", "transactions in this chunk in mining order",482{RPCResult{RPCResult::Type::STR_HEX, "txid", "transaction id"}}},483}484}}485}486};487}489static std::vector<RPCResult> MempoolEntryDescription()490{491std::vector<RPCResult> list = {492{RPCResult::Type::NUM, "vsize", "(DEPRECATED) Was previously erroneously described as the BIP 141 vsize, but is actually sigops-adjusted vsize.\n"493"Use vsize_bip141 to actually get that behavior or switch to the explicit vsize_adjusted for retained behavior."},494{RPCResult::Type::NUM, "vsize_bip141", "Virtual transaction size as defined in BIP 141.\n"495"This is different from actual serialized size for witness transactions as witness data is discounted."},496{RPCResult::Type::NUM, "vsize_adjusted", "Maximum of sigop-adjusted size (-bytespersigop) and virtual transaction size as defined in BIP 141."},497RPCResult{RPCResult::Type::NUM, "weight", "transaction weight as defined in BIP 141."},498RPCResult{RPCResult::Type::NUM_TIME, "time", "local time transaction entered pool in seconds since 1 Jan 1970 GMT"},499RPCResult{RPCResult::Type::NUM, "height", "block height when transaction entered pool"},500RPCResult{RPCResult::Type::NUM, "descendantcount", "number of in-mempool descendant transactions (including this one)"},