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"simulaterawtransaction",502"Calculate the balance change resulting in the signing and broadcasting of the given transaction(s).\n",503{504{"rawtxs", RPCArg::Type::ARR, RPCArg::Optional::NO, "An array of hex strings of raw transactions.\n",505{506{"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},507},508},509{"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "",510{511{"include_watchonly", RPCArg::Type::BOOL, RPCArg::Default{false}, "(DEPRECATED) No longer used"},512},513},514},515RPCResult{516RPCResult::Type::OBJ, "", "",517{518{RPCResult::Type::STR_AMOUNT, "balance_change", "The wallet balance change (negative means decrease)."},519}520},521RPCExamples{522HelpExampleCli("simulaterawtransaction", "[\"myhex\"]")523+ HelpExampleRpc("simulaterawtransaction", "[\"myhex\"]")524},525[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue526{527const std::shared_ptr<const CWallet> rpc_wallet = GetWalletForJSONRPCRequest(request);528if (!rpc_wallet) return UniValue::VNULL;529const CWallet& wallet = *rpc_wallet;531LOCK(wallet.cs_wallet);533const auto& txs = request.params[0].get_array();534CAmount changes{0};535std::map<COutPoint, CAmount> new_utxos; // UTXO:s that were made available in transaction array536std::set<COutPoint> spent;538for (size_t i = 0; i < txs.size(); ++i) {539CMutableTransaction mtx;540if (!DecodeHexTx(mtx, txs[i].get_str(), /*try_no_witness=*/ true, /*try_witness=*/ true)) {541throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "Transaction hex string decoding failure.");542}544// Fetch previous transactions (inputs)545std::map<COutPoint, Coin> coins;546for (const CTxIn& txin : mtx.vin) {547coins[txin.prevout]; // Create empty map entry keyed by prevout.548}549wallet.chain().findCoins(coins);551// Fetch debit; we are *spending* these; if the transaction is signed and552// broadcast, we will lose everything in these553for (const auto& txin : mtx.vin) {554const auto& outpoint = txin.prevout;555if (spent.contains(outpoint)) {556throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction(s) are spending the same output more than once");557}558if (new_utxos.contains(outpoint)) {559changes -= new_utxos.at(outpoint);560new_utxos.erase(outpoint);561} else {562if (coins.at(outpoint).IsSpent()) {563throw JSONRPCError(RPC_INVALID_PARAMETER, "One or more transaction inputs are missing or have been spent already");564}565changes -= wallet.GetDebit(txin);566}567spent.insert(outpoint);568}570// Iterate over outputs; we are *receiving* these, if the wallet considers571// them "mine"; if the transaction is signed and broadcast, we will receive572// everything in these573// Also populate new_utxos in case these are spent in later transactions575const auto& hash = mtx.GetHash();576for (size_t i = 0; i < mtx.vout.size(); ++i) {577const auto& txout = mtx.vout[i];578bool is_mine = wallet.IsMine(txout);579changes += new_utxos[COutPoint(hash, i)] = is_mine ? txout.nValue : 0;580}581}583UniValue result(UniValue::VOBJ);584result.pushKV("balance_change", ValueFromAmount(changes));586return result;587}588};589}591static RPCMethod migratewallet()592{593return RPCMethod{594"migratewallet",595"Migrate the wallet to a descriptor wallet.\n"596"A new wallet backup will need to be made.\n"597"\nThe migration process will create a backup of the wallet before migrating. This backup\n"598"file will be named <wallet name>-<timestamp>.legacy.bak and can be found in the directory\n"599"for this wallet. In the event of an incorrect migration, the backup can be restored using restorewallet."600"\nEncrypted wallets must have the passphrase provided as an argument to this call.\n"601"\nThis RPC may take a long time to complete. Increasing the RPC client timeout is recommended.",602{603{"wallet_name", RPCArg::Type::STR, RPCArg::DefaultHint{"the wallet name from the RPC endpoint"}, "The name of the wallet to migrate. If provided both here and in the RPC endpoint, the two must be identical."},604{"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "The wallet passphrase"},605{"load_wallet", RPCArg::Type::BOOL, RPCArg::Default{true}, "Load the wallet after migration."},606},607RPCResult{608RPCResult::Type::OBJ, "", "",609{610{RPCResult::Type::STR, "wallet_name", "The name of the primary migrated wallet"},611{RPCResult::Type::STR, "watchonly_name", /*optional=*/true, "The name of the migrated wallet containing the watchonly scripts"},612{RPCResult::Type::STR, "solvables_name", /*optional=*/true, "The name of the migrated wallet containing solvable but not watched scripts"},613{RPCResult::Type::STR, "backup_path", "The location of the backup of the original wallet"},614}615},616RPCExamples{617HelpExampleCli("migratewallet", "")618+ HelpExampleRpc("migratewallet", "")619},620[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue621{622const std::string wallet_name{EnsureUniqueWalletName(request, self.MaybeArg<std::string_view>("wallet_name"))};624SecureString wallet_pass;625wallet_pass.reserve(100);626if (!request.params[1].isNull()) {627wallet_pass = std::string_view{request.params[1].get_str()};628}630const bool loadwallet = self.Arg<bool>("load_wallet");632WalletContext& context = EnsureWalletContext(request.context);633util::Result<MigrationResult> res = MigrateLegacyToDescriptor(wallet_name, wallet_pass, context, loadwallet);634if (!res) {635throw JSONRPCError(RPC_WALLET_ERROR, util::ErrorString(res).original);636}638UniValue r{UniValue::VOBJ};639r.pushKV("wallet_name", res->wallet_name);640if (res->watchonly_wallet_name.has_value()) {641r.pushKV("watchonly_name", res->watchonly_wallet_name.value());642}643if (res->solvables_wallet_name.has_value()) {644r.pushKV("solvables_name", res->solvables_wallet_name.value());645}646r.pushKV("backup_path", res->backup_path.utf8string());648return r;649},650};651}653RPCMethod gethdkeys()654{655return RPCMethod{656"gethdkeys",657"List all BIP 32 HD keys in the wallet and which descriptors use them.\n",658{659{"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "", {660{"active_only", RPCArg::Type::BOOL, RPCArg::Default{false}, "Show the keys for only active descriptors"},661{"private", RPCArg::Type::BOOL, RPCArg::Default{false}, "Show private keys"}662}},663},664RPCResult{RPCResult::Type::ARR, "", "", {665{666{RPCResult::Type::OBJ, "", "", {667{RPCResult::Type::STR, "xpub", "The extended public key"},668{RPCResult::Type::BOOL, "has_private", "Whether the wallet has the private key for this xpub"},669{RPCResult::Type::STR, "xprv", /*optional=*/true, "The extended private key if \"private\" is true"},670{RPCResult::Type::ARR, "descriptors", "Array of descriptor objects that use this HD key",671{672{RPCResult::Type::OBJ, "", "", {673{RPCResult::Type::STR, "desc", "Descriptor string public representation"},674{RPCResult::Type::BOOL, "active", "Whether this descriptor is currently used to generate new addresses"},675}},676}},677}},678}679}},680RPCExamples{681HelpExampleCli("gethdkeys", "") + HelpExampleRpc("gethdkeys", "")682+ HelpExampleCliNamed("gethdkeys", {{"active_only", "true"}, {"private", "true"}}) + HelpExampleRpcNamed("gethdkeys", {{"active_only", "true"}, {"private", "true"}})683},684[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue685{686const std::shared_ptr<const CWallet> wallet = GetWalletForJSONRPCRequest(request);687if (!wallet) return UniValue::VNULL;689LOCK(wallet->cs_wallet);691UniValue options{request.params[0].isNull() ? UniValue::VOBJ : request.params[0]};692const bool active_only{options.exists("active_only") ? options["active_only"].get_bool() : false};693const bool priv{options.exists("private") ? options["private"].get_bool() : false};694if (priv) {695EnsureWalletIsUnlocked(*wallet);696}698std::map<CExtPubKey, std::set<std::tuple<std::string, bool, bool>>> wallet_xpubs;699std::map<CExtPubKey, CExtKey> wallet_xprvs;700for (const auto& [xpub, spkms] : wallet->GetHDPubKeys(active_only ? HDKeyFilter::Active : HDKeyFilter::All)) {701for (auto* desc_spkm : spkms) {702LOCK(desc_spkm->cs_desc_man);703std::string desc_str;704bool ok = desc_spkm->GetDescriptorString(desc_str, /*priv=*/false);705CHECK_NONFATAL(ok);706wallet_xpubs[xpub].emplace(desc_str, wallet->IsActiveScriptPubKeyMan(*desc_spkm), desc_spkm->HasPrivKey(xpub.pubkey.GetID()));707if (std::optional<CKey> key = priv ? desc_spkm->GetKey(xpub.pubkey.GetID()) : std::nullopt) {708wallet_xprvs[xpub] = CExtKey(xpub, *key);709}710}711}713UniValue response(UniValue::VARR);714for (const auto& [xpub, descs] : wallet_xpubs) {715bool has_xprv = false;716UniValue descriptors(UniValue::VARR);717for (const auto& [desc, active, has_priv] : descs) {718UniValue d(UniValue::VOBJ);719d.pushKV("desc", desc);720d.pushKV("active", active);721has_xprv |= has_priv;723descriptors.push_back(std::move(d));724}725UniValue xpub_info(UniValue::VOBJ);726xpub_info.pushKV("xpub", EncodeExtPubKey(xpub));727xpub_info.pushKV("has_private", has_xprv);728if (priv && has_xprv) {729xpub_info.pushKV("xprv", EncodeExtKey(wallet_xprvs.at(xpub)));730}731xpub_info.pushKV("descriptors", std::move(descriptors));733response.push_back(std::move(xpub_info));734}736return response;737},738};739}741static RPCMethod createwalletdescriptor()742{743return RPCMethod{"createwalletdescriptor",744"Creates the wallet's descriptor for the given address type. "745"The address type must be one that the wallet does not already have a descriptor for."746+ HELP_REQUIRING_PASSPHRASE,747{748{"type", RPCArg::Type::STR, RPCArg::Optional::NO, "The address type the descriptor will produce. Options are " + FormatAllOutputTypes() + "."},749{"options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "", {750{"internal", RPCArg::Type::BOOL, RPCArg::DefaultHint{"Both external and internal will be generated unless this parameter is specified"}, "Whether to only make one descriptor that is internal (if parameter is true) or external (if parameter is false)"},