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) 2010 Satoshi Nakamoto2// Copyright (c) 2009-present The Bitcoin Core developers3// Distributed under the MIT software license, see the accompanying4// file COPYING or http://www.opensource.org/licenses/mit-license.php.6#include <bitcoin-build-config.h> // IWYU pragma: keep8#include <wallet/rpc/wallet.h>10#include <coins.h>11#include <core_io.h>12#include <key.h>13#include <key_io.h>14#include <rpc/server.h>15#include <rpc/util.h>16#include <univalue.h>17#include <util/bip32.h>18#include <util/translation.h>19#include <wallet/context.h>20#include <wallet/export.h>21#include <wallet/receive.h>22#include <wallet/rpc/util.h>23#include <wallet/wallet.h>24#include <wallet/walletutil.h>26#include <algorithm>27#include <optional>28#include <string_view>31namespace wallet {33using HDPubKeyMap = CWallet::HDPubKeyMap;34using HDKeyFilter = CWallet::HDKeyFilter;36static const std::map<uint64_t, std::string> WALLET_FLAG_CAVEATS{37{WALLET_FLAG_AVOID_REUSE,38"You need to rescan the blockchain in order to correctly mark used "39"destinations in the past. Until this is done, some destinations may "40"be considered unused, even if the opposite is the case."},41};43static RPCMethod getwalletinfo()44{45return RPCMethod{"getwalletinfo",46"Returns an object containing various wallet state info.\n",47{},48RPCResult{49RPCResult::Type::OBJ, "", "",50{51{52{RPCResult::Type::STR, "walletname", "the wallet name"},53{RPCResult::Type::NUM, "walletversion", "(DEPRECATED) only related to unsupported legacy wallet, returns the latest version 169900 for backwards compatibility"},54{RPCResult::Type::STR, "format", "the database format (only sqlite)"},55{RPCResult::Type::NUM, "txcount", "the total number of transactions in the wallet"},56{RPCResult::Type::NUM, "keypoolsize", "how many new keys are pre-generated (only counts external keys)"},57{RPCResult::Type::NUM, "keypoolsize_hd_internal", "how many new keys are pre-generated for internal use (used for change outputs; 0 if external keys are used for change)"},58{RPCResult::Type::NUM_TIME, "unlocked_until", /*optional=*/true, "the " + UNIX_EPOCH_TIME + " until which the wallet is unlocked for transfers, or 0 if the wallet is locked (only present for passphrase-encrypted wallets)"},59{RPCResult::Type::BOOL, "private_keys_enabled", "false if privatekeys are disabled for this wallet (enforced watch-only wallet)"},60{RPCResult::Type::BOOL, "avoid_reuse", "whether this wallet tracks clean/dirty coins in terms of reuse"},61{RPCResult::Type::OBJ, "scanning", "current scanning details, or false if no scan is in progress",62{63{RPCResult::Type::NUM, "duration", "elapsed seconds since scan start"},64{RPCResult::Type::NUM, "progress", "scanning progress percentage [0.0, 1.0]"},65}, {.skip_type_check=true}, },66{RPCResult::Type::BOOL, "descriptors", "whether this wallet uses descriptors for output script management"},67{RPCResult::Type::BOOL, "external_signer", "whether this wallet is configured to use an external signer such as a hardware wallet"},68{RPCResult::Type::BOOL, "blank", "Whether this wallet intentionally does not contain any keys, scripts, or descriptors"},69{RPCResult::Type::NUM_TIME, "birthtime", /*optional=*/true, "The start time for blocks scanning. It could be modified by (re)importing any descriptor with an earlier timestamp."},70{RPCResult::Type::ARR, "flags", "The flags currently set on the wallet",71{72{RPCResult::Type::STR, "flag", "The name of the flag"},73}},74RESULT_LAST_PROCESSED_BLOCK,75}},76},77RPCExamples{78HelpExampleCli("getwalletinfo", "")79+ HelpExampleRpc("getwalletinfo", "")80},81[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue82{83const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);84if (!pwallet) return UniValue::VNULL;86// Make sure the results are valid at least up to the most recent block87// the user could have gotten from another RPC command prior to now88pwallet->BlockUntilSyncedToCurrentChain();90LOCK(pwallet->cs_wallet);92UniValue obj(UniValue::VOBJ);94const int latest_legacy_wallet_minversion{169900};96size_t kpExternalSize = pwallet->KeypoolCountExternalKeys();97obj.pushKV("walletname", pwallet->GetName());98obj.pushKV("walletversion", latest_legacy_wallet_minversion);99obj.pushKV("format", pwallet->GetDatabase().Format());100obj.pushKV("txcount", pwallet->mapWallet.size());101obj.pushKV("keypoolsize", kpExternalSize);102obj.pushKV("keypoolsize_hd_internal", pwallet->GetKeyPoolSize() - kpExternalSize);104if (pwallet->HasEncryptionKeys()) {105obj.pushKV("unlocked_until", pwallet->nRelockTime);106}107obj.pushKV("private_keys_enabled", !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));108obj.pushKV("avoid_reuse", pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE));109if (pwallet->IsScanning()) {110UniValue scanning(UniValue::VOBJ);111scanning.pushKV("duration", Ticks<std::chrono::seconds>(pwallet->ScanningDuration()));112scanning.pushKV("progress", pwallet->ScanningProgress());113obj.pushKV("scanning", std::move(scanning));114} else {115obj.pushKV("scanning", false);116}117obj.pushKV("descriptors", pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));118obj.pushKV("external_signer", pwallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER));119obj.pushKV("blank", pwallet->IsWalletFlagSet(WALLET_FLAG_BLANK_WALLET));120if (int64_t birthtime = pwallet->GetBirthTime(); birthtime != UNKNOWN_TIME) {121obj.pushKV("birthtime", birthtime);122}124// Push known flags125UniValue flags(UniValue::VARR);126uint64_t wallet_flags = pwallet->GetWalletFlags();127for (uint64_t i = 0; i < 64; ++i) {128uint64_t flag = uint64_t{1} << i;129if (flag & wallet_flags) {130if (flag & KNOWN_WALLET_FLAGS) {131flags.push_back(WALLET_FLAG_TO_STRING.at(WalletFlags{flag}));132} else {133flags.push_back(strprintf("unknown_flag_%u", i));134}135}136}137obj.pushKV("flags", flags);139AppendLastProcessedBlock(obj, *pwallet);140return obj;141},142};143}145static RPCMethod listwalletdir()146{147return RPCMethod{"listwalletdir",148"Returns a list of wallets in the wallet directory.\n",149{},150RPCResult{151RPCResult::Type::OBJ, "", "",152{153{RPCResult::Type::ARR, "wallets", "",154{155{RPCResult::Type::OBJ, "", "",156{157{RPCResult::Type::STR, "name", "The wallet name"},158{RPCResult::Type::ARR, "warnings", "Warning messages related to loading the wallet (may be empty).",159{160{RPCResult::Type::STR, "", ""},161}},162}},163}},164}165},166RPCExamples{167HelpExampleCli("listwalletdir", "")168+ HelpExampleRpc("listwalletdir", "")169},170[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue171{172UniValue wallets(UniValue::VARR);173for (const auto& [path, db_type] : ListDatabases(GetWalletDir())) {174UniValue wallet(UniValue::VOBJ);175wallet.pushKV("name", path.utf8string());176UniValue warnings(UniValue::VARR);177if (db_type == "bdb") {178warnings.push_back("This wallet is a legacy wallet and will need to be migrated with migratewallet before it can be loaded");179}180wallet.pushKV("warnings", warnings);181wallets.push_back(std::move(wallet));182}184UniValue result(UniValue::VOBJ);185result.pushKV("wallets", std::move(wallets));186return result;187},188};189}191static RPCMethod listwallets()192{193return RPCMethod{"listwallets",194"Returns a list of currently loaded wallets.\n"195"For full information on the wallet, use \"getwalletinfo\"\n",196{},197RPCResult{198RPCResult::Type::ARR, "", "",199{200{RPCResult::Type::STR, "walletname", "the wallet name"},201}202},203RPCExamples{204HelpExampleCli("listwallets", "")205+ HelpExampleRpc("listwallets", "")206},207[](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue208{209UniValue obj(UniValue::VARR);211WalletContext& context = EnsureWalletContext(request.context);212for (const std::shared_ptr<CWallet>& wallet : GetWallets(context)) {213LOCK(wallet->cs_wallet);214obj.push_back(wallet->GetName());215}217return obj;218},219};220}222static RPCMethod loadwallet()223{224return RPCMethod{225"loadwallet",226"Loads a wallet from a wallet file or directory."227"\nNote that all wallet command-line options used when starting bitcoind will be"228"\napplied to the new wallet.\n",229{230{"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The path to the directory of the wallet to be loaded, either absolute or relative to the \"wallets\" directory. The \"wallets\" directory is set by the -walletdir option and defaults to the \"wallets\" folder within the data directory."},231{"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},232},233RPCResult{234RPCResult::Type::OBJ, "", "",235{236{RPCResult::Type::STR, "name", "The wallet name if loaded successfully."},237{RPCResult::Type::ARR, "warnings", /*optional=*/true, "Warning messages, if any, related to loading the wallet.",238{239{RPCResult::Type::STR, "", ""},240}},241}242},243RPCExamples{244"\nLoad wallet from the wallet dir:\n"245+ HelpExampleCli("loadwallet", "\"walletname\"")246+ HelpExampleRpc("loadwallet", "\"walletname\"")247+ "\nLoad wallet using absolute path (Unix):\n"248+ HelpExampleCli("loadwallet", "\"/path/to/walletname/\"")249+ HelpExampleRpc("loadwallet", "\"/path/to/walletname/\"")250+ "\nLoad wallet using absolute path (Windows):\n"