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.
501{"inputs", UniValueType(UniValue::VARR)},502{"lockUnspents", UniValueType(UniValue::VBOOL)},503{"lock_unspents", UniValueType(UniValue::VBOOL)},504{"locktime", UniValueType(UniValue::VNUM)},505{"fee_rate", UniValueType()}, // will be checked by AmountFromValue() in SetFeeEstimateMode()506{"feeRate", UniValueType()}, // will be checked by AmountFromValue() below507{"psbt", UniValueType(UniValue::VBOOL)},508{"solving_data", UniValueType(UniValue::VOBJ)},509{"subtractFeeFromOutputs", UniValueType(UniValue::VARR)},510{"subtract_fee_from_outputs", UniValueType(UniValue::VARR)},511{"replaceable", UniValueType(UniValue::VBOOL)},512{"conf_target", UniValueType(UniValue::VNUM)},513{"estimate_mode", UniValueType(UniValue::VSTR)},514{"minconf", UniValueType(UniValue::VNUM)},515{"maxconf", UniValueType(UniValue::VNUM)},516{"input_weights", UniValueType(UniValue::VARR)},517{"max_tx_weight", UniValueType(UniValue::VNUM)},518},519true, true);521if (options.exists("add_inputs")) {522coinControl.m_allow_other_inputs = options["add_inputs"].get_bool();523}525if (options.exists("changeAddress") || options.exists("change_address")) {526const std::string change_address_str = (options.exists("change_address") ? options["change_address"] : options["changeAddress"]).get_str();527CTxDestination dest = DecodeDestination(change_address_str);529if (!IsValidDestination(dest)) {530throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Change address must be a valid bitcoin address");531}533coinControl.destChange = dest;534}536if (options.exists("changePosition") || options.exists("change_position")) {537int pos = (options.exists("change_position") ? options["change_position"] : options["changePosition"]).getInt<int>();538if (pos < 0 || (unsigned int)pos > recipients.size()) {539throw JSONRPCError(RPC_INVALID_PARAMETER, "changePosition out of bounds");540}541change_position = (unsigned int)pos;542}544if (options.exists("change_type")) {545if (options.exists("changeAddress") || options.exists("change_address")) {546throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both change address and address type options");547}548if (std::optional<OutputType> parsed = ParseOutputType(options["change_type"].get_str())) {549coinControl.m_change_type.emplace(parsed.value());550} else {551throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown change type '%s'", options["change_type"].get_str()));552}553}555if (options.exists("lockUnspents") || options.exists("lock_unspents")) {556lockUnspents = (options.exists("lock_unspents") ? options["lock_unspents"] : options["lockUnspents"]).get_bool();557}559if (options.exists("include_unsafe")) {560coinControl.m_include_unsafe_inputs = options["include_unsafe"].get_bool();561}563if (options.exists("feeRate")) {564if (options.exists("fee_rate")) {565throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both fee_rate (" + CURRENCY_ATOM + "/vB) and feeRate (" + CURRENCY_UNIT + "/kvB)");566}567if (options.exists("conf_target")) {568throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both conf_target and feeRate. Please provide either a confirmation target in blocks for automatic fee estimation, or an explicit fee rate.");569}570if (options.exists("estimate_mode")) {571throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both estimate_mode and feeRate");572}573coinControl.m_feerate = CFeeRate(AmountFromValue(options["feeRate"]));574coinControl.fOverrideFeeRate = true;575}577if (options.exists("replaceable")) {578coinControl.m_signal_bip125_rbf = options["replaceable"].get_bool();579}581if (options.exists("minconf")) {582coinControl.m_min_depth = options["minconf"].getInt<int>();584if (coinControl.m_min_depth < 0) {585throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative minconf");586}587}589if (options.exists("maxconf")) {590coinControl.m_max_depth = options["maxconf"].getInt<int>();592if (coinControl.m_max_depth < coinControl.m_min_depth) {593throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("maxconf can't be lower than minconf: %d < %d", coinControl.m_max_depth, coinControl.m_min_depth));594}595}596SetFeeEstimateMode(wallet, coinControl, options["conf_target"], options["estimate_mode"], options["fee_rate"], override_min_fee);597}599if (options.exists("solving_data")) {600const UniValue solving_data = options["solving_data"].get_obj();601if (solving_data.exists("pubkeys")) {602for (const UniValue& pk_univ : solving_data["pubkeys"].get_array().getValues()) {603const CPubKey pubkey = HexToPubKey(pk_univ.get_str());604coinControl.m_external_provider.pubkeys.emplace(pubkey.GetID(), pubkey);605// Add witness script for pubkeys606const CScript wit_script = GetScriptForDestination(WitnessV0KeyHash(pubkey));607coinControl.m_external_provider.scripts.emplace(CScriptID(wit_script), wit_script);608}609}611if (solving_data.exists("scripts")) {612for (const UniValue& script_univ : solving_data["scripts"].get_array().getValues()) {613const std::string& script_str = script_univ.get_str();614if (!IsHex(script_str)) {615throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("'%s' is not hex", script_str));616}617std::vector<unsigned char> script_data(ParseHex(script_str));618const CScript script(script_data.begin(), script_data.end());619coinControl.m_external_provider.scripts.emplace(CScriptID(script), script);620}621}623if (solving_data.exists("descriptors")) {624for (const UniValue& desc_univ : solving_data["descriptors"].get_array().getValues()) {625const std::string& desc_str = desc_univ.get_str();626FlatSigningProvider desc_out;627std::string error;628std::vector<CScript> scripts_temp;629auto descs = Parse(desc_str, desc_out, error, true);630if (descs.empty()) {631throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Unable to parse descriptor '%s': %s", desc_str, error));632}633for (auto& desc : descs) {634desc->Expand(0, desc_out, scripts_temp, desc_out);635}636coinControl.m_external_provider.Merge(std::move(desc_out));637}638}639}641if (options.exists("input_weights")) {642for (const UniValue& input : options["input_weights"].get_array().getValues()) {643Txid txid = Txid::FromUint256(ParseHashO(input, "txid"));645const UniValue& vout_v = input.find_value("vout");646if (!vout_v.isNum()) {647throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing vout key");648}649int vout = vout_v.getInt<int>();650if (vout < 0) {651throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative");652}654const UniValue& weight_v = input.find_value("weight");655if (!weight_v.isNum()) {656throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, missing weight key");657}658int64_t weight = weight_v.getInt<int64_t>();659const int64_t min_input_weight = GetTransactionInputWeight(CTxIn());660CHECK_NONFATAL(min_input_weight == 165);661if (weight < min_input_weight) {662throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, weight cannot be less than 165 (41 bytes (size of outpoint + sequence + empty scriptSig) * 4 (witness scaling factor)) + 1 (empty witness)");663}664if (weight > MAX_STANDARD_TX_WEIGHT) {665throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, weight cannot be greater than the maximum standard tx weight of %d", MAX_STANDARD_TX_WEIGHT));666}668coinControl.SetInputWeight(COutPoint(txid, vout), weight);669}670}672if (options.exists("max_tx_weight")) {673coinControl.m_max_tx_weight = options["max_tx_weight"].getInt<int>();674}676if (tx.version == TRUC_VERSION) {677if (!coinControl.m_max_tx_weight.has_value() || coinControl.m_max_tx_weight.value() > TRUC_MAX_WEIGHT) {678coinControl.m_max_tx_weight = TRUC_MAX_WEIGHT;679}680}682if (recipients.empty())683throw JSONRPCError(RPC_INVALID_PARAMETER, "TX must have at least one output");685auto txr = FundTransaction(wallet, tx, recipients, change_position, lockUnspents, coinControl);686if (!txr) {687throw JSONRPCError(RPC_WALLET_ERROR, ErrorString(txr).original);688}689return *txr;690}692static void SetOptionsInputWeights(const UniValue& inputs, UniValue& options)693{694if (options.exists("input_weights")) {695throw JSONRPCError(RPC_INVALID_PARAMETER, "Input weights should be specified in inputs rather than in options.");696}697if (inputs.size() == 0) {698return;699}700UniValue weights(UniValue::VARR);701for (const UniValue& input : inputs.getValues()) {702if (input.exists("weight")) {703weights.push_back(input);704}705}706options.pushKV("input_weights", std::move(weights));707}709RPCMethod fundrawtransaction()710{711return RPCMethod{712"fundrawtransaction",713"If the transaction has no inputs, they will be automatically selected to meet its out value.\n"714"It will add at most one change output to the outputs.\n"715"No existing outputs will be modified unless \"subtractFeeFromOutputs\" is specified.\n"716"Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n"717"The inputs added will not be signed, use signrawtransactionwithkey\n"718"or signrawtransactionwithwallet for that.\n"719"All existing inputs must either have their previous output transaction be in the wallet\n"720"or be in the UTXO set. Solving data must be provided for non-wallet inputs.\n"721"Note that all inputs selected must be of standard form and P2SH scripts must be\n"722"in the wallet using importdescriptors (to calculate fees).\n"723"You can see whether this is the case by checking the \"solvable\" field in the listunspent output.\n"724"Note that if specifying an exact fee rate, the resulting transaction may have a higher fee rate\n"725"if the transaction has unconfirmed inputs. This is because the wallet will attempt to make the\n"726"entire package have the given fee rate, not the resulting transaction.\n",727{728{"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"},729{"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "",730Cat<std::vector<RPCArg>>(731{732{"add_inputs", RPCArg::Type::BOOL, RPCArg::Default{true}, "For a transaction with existing inputs, automatically include more if they are not enough."},733{"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include inputs that are not safe to spend (unconfirmed transactions from outside keys and unconfirmed replacement transactions).\n"734"Warning: the resulting transaction may become invalid if one of the unsafe inputs disappears.\n"735"If that happens, you will need to fund the transaction with different inputs and republish it."},736{"minconf", RPCArg::Type::NUM, RPCArg::Default{0}, "If add_inputs is specified, require inputs with at least this many confirmations."},737{"maxconf", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "If add_inputs is specified, require inputs with at most this many confirmations."},738{"changeAddress", RPCArg::Type::STR, RPCArg::DefaultHint{"automatic"}, "The bitcoin address to receive the change"},739{"changePosition", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},740{"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if changeAddress is not specified. Options are " + FormatAllOutputTypes() + "."},741{"includeWatching", RPCArg::Type::BOOL, RPCArg::Default{false}, "(DEPRECATED) No longer used"},742{"lockUnspents", RPCArg::Type::BOOL, RPCArg::Default{false}, "Lock selected unspent outputs"},743{"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},744{"feeRate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_UNIT + "/kvB."},745{"subtractFeeFromOutputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "The integers.\n"746"The fee will be equally deducted from the amount of each specified output.\n"747"Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"748"If no outputs are specified here, the sender pays the fee.",749{750{"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."},