Inside Bitcoin
Opening the selected file…
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.
1// Copyright (c) 2011-present The Bitcoin Core developers2// Distributed under the MIT software license, see the accompanying3// file COPYING or http://www.opensource.org/licenses/mit-license.php.5#include <wallet/rpc/util.h>7#include <common/url.h>8#include <rpc/util.h>9#include <util/any.h>10#include <util/translation.h>11#include <wallet/context.h>12#include <wallet/wallet.h>14#include <optional>15#include <string_view>16#include <univalue.h>18namespace wallet {19static const std::string WALLET_ENDPOINT_BASE = "/wallet/";20const std::string HELP_REQUIRING_PASSPHRASE{"\nRequires wallet passphrase to be set with walletpassphrase call if wallet is encrypted.\n"};22bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param) {23bool can_avoid_reuse = wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);24bool avoid_reuse = param.isNull() ? can_avoid_reuse : param.get_bool();26if (avoid_reuse && !can_avoid_reuse) {27throw JSONRPCError(RPC_WALLET_ERROR, "wallet does not have the \"avoid reuse\" feature enabled");28}30return avoid_reuse;31}33std::string EnsureUniqueWalletName(const JSONRPCRequest& request, std::optional<std::string_view> wallet_name)34{35if (auto endpoint_wallet{GetWalletNameFromJSONRPCRequest(request)}) {36// wallet endpoint was used37if (wallet_name && *wallet_name != *endpoint_wallet) {38throw JSONRPCError(RPC_INVALID_PARAMETER,39"The RPC endpoint wallet and the wallet name parameter specify different wallets");40}41return *endpoint_wallet;42}44// Not a wallet endpoint; parameter must be provided45if (!wallet_name) {46throw JSONRPCError(RPC_INVALID_PARAMETER,47"Either the RPC endpoint wallet or the wallet name parameter must be provided");48}50return std::string{*wallet_name};51}53std::optional<std::string> GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request)54{55if (request.URI.starts_with(WALLET_ENDPOINT_BASE)) {56// wallet endpoint was used57return UrlDecode(std::string_view{request.URI}.substr(WALLET_ENDPOINT_BASE.size()));58}59return std::nullopt;60}62std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request)63{64CHECK_NONFATAL(request.mode == JSONRPCRequest::EXECUTE);65WalletContext& context = EnsureWalletContext(request.context);67if (auto wallet_name{GetWalletNameFromJSONRPCRequest(request)}) {68std::shared_ptr<CWallet> pwallet{GetWallet(context, *wallet_name)};69if (!pwallet) throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");70return pwallet;71}73size_t count{0};74auto wallet = GetDefaultWallet(context, count);75if (wallet) return wallet;77if (count == 0) {78throw JSONRPCError(79RPC_WALLET_NOT_FOUND, "No wallet is loaded. Load a wallet using loadwallet or create a new one with createwallet. (Note: A default wallet is no longer automatically created)");80}81throw JSONRPCError(RPC_WALLET_NOT_SPECIFIED,82"Multiple wallets are loaded. Please select which wallet to use by requesting the RPC through the /wallet/<walletname> URI path.");83}85void EnsureWalletIsUnlocked(const CWallet& wallet)86{87if (wallet.IsLocked()) {88throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");89}90}92WalletContext& EnsureWalletContext(const std::any& context)93{94auto wallet_context = util::AnyPtr<WalletContext>(context);95if (!wallet_context) {96throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet context not found");97}98return *wallet_context;99}101std::string LabelFromValue(const UniValue& value)102{103static const std::string empty_string;104if (value.isNull()) return empty_string;106const std::string& label{value.get_str()};107if (label == "*")108throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, "Invalid label name");109return label;110}112void PushParentDescriptors(const CWallet& wallet, const CScript& script_pubkey, UniValue& entry)113{114UniValue parent_descs(UniValue::VARR);115for (const auto& desc: wallet.GetWalletDescriptors(script_pubkey)) {116std::string desc_str;117FlatSigningProvider dummy_provider;118if (!CHECK_NONFATAL(desc.descriptor->ToNormalizedString(dummy_provider, desc_str, &desc.cache))) continue;119parent_descs.push_back(desc_str);120}121entry.pushKV("parent_descs", std::move(parent_descs));122}124void HandleWalletError(const std::shared_ptr<CWallet>& wallet, DatabaseStatus& status, bilingual_str& error)125{126if (!wallet) {127// Map bad format to not found, since bad format is returned when the128// wallet directory exists, but doesn't contain a data file.129RPCErrorCode code = RPC_WALLET_ERROR;130switch (status) {131case DatabaseStatus::FAILED_NOT_FOUND:132case DatabaseStatus::FAILED_BAD_FORMAT:133case DatabaseStatus::FAILED_LEGACY_DISABLED:134code = RPC_WALLET_NOT_FOUND;135break;136case DatabaseStatus::FAILED_ALREADY_LOADED:137code = RPC_WALLET_ALREADY_LOADED;138break;139case DatabaseStatus::FAILED_ALREADY_EXISTS:140code = RPC_WALLET_ALREADY_EXISTS;141break;142case DatabaseStatus::FAILED_NEW_UNNAMED:143case DatabaseStatus::FAILED_INVALID_BACKUP_FILE:144code = RPC_INVALID_PARAMETER;145break;146case DatabaseStatus::FAILED_ENCRYPT:147code = RPC_WALLET_ENCRYPTION_FAILED;148break;149default: // RPC_WALLET_ERROR is returned for all other cases.150break;151}152throw JSONRPCError(code, error.original);153}154}156void AppendLastProcessedBlock(UniValue& entry, const CWallet& wallet)157{158AssertLockHeld(wallet.cs_wallet);159UniValue lastprocessedblock{UniValue::VOBJ};160lastprocessedblock.pushKV("hash", wallet.GetLastBlockHash().GetHex());161lastprocessedblock.pushKV("height", wallet.GetLastBlockHeight());162entry.pushKV("lastprocessedblock", std::move(lastprocessedblock));163}165} // namespace wallet