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.
1// Copyright (c) 2009-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 <wallet/wallet.h>8#include <bitcoin-build-config.h> // IWYU pragma: keep10#include <addresstype.h>11#include <blockfilter.h>12#include <chain.h>13#include <coins.h>14#include <common/args.h>15#include <common/messages.h>16#include <common/settings.h>17#include <common/signmessage.h>18#include <common/system.h>19#include <consensus/amount.h>20#include <consensus/consensus.h>21#include <consensus/validation.h>22#include <external_signer.h>23#include <interfaces/chain.h>24#include <interfaces/handler.h>25#include <interfaces/wallet.h>26#include <kernel/mempool_removal_reason.h>27#include <kernel/types.h>28#include <key.h>29#include <key_io.h>30#include <node/types.h>31#include <outputtype.h>32#include <policy/feerate.h>33#include <policy/truc_policy.h>34#include <primitives/block.h>35#include <primitives/transaction.h>36#include <psbt.h>37#include <pubkey.h>38#include <random.h>39#include <script/descriptor.h>40#include <script/interpreter.h>41#include <script/script.h>42#include <script/sign.h>43#include <script/signingprovider.h>44#include <script/solver.h>45#include <serialize.h>46#include <span.h>47#include <streams.h>48#include <support/allocators/secure.h>49#include <support/allocators/zeroafterfree.h>50#include <support/cleanse.h>51#include <sync.h>52#include <tinyformat.h>53#include <uint256.h>54#include <univalue.h>55#include <util/check.h>56#include <util/fs.h>57#include <util/fs_helpers.h>58#include <util/log.h>59#include <util/moneystr.h>60#include <util/result.h>61#include <util/string.h>62#include <util/time.h>63#include <util/translation.h>64#include <wallet/coincontrol.h>65#include <wallet/context.h>66#include <wallet/crypter.h>67#include <wallet/db.h>68#include <wallet/external_signer_scriptpubkeyman.h>69#include <wallet/scriptpubkeyman.h>70#include <wallet/transaction.h>71#include <wallet/types.h>72#include <wallet/walletdb.h>73#include <wallet/walletutil.h>75#include <algorithm>76#include <cassert>77#include <condition_variable>78#include <exception>79#include <limits>80#include <optional>81#include <stdexcept>82#include <thread>83#include <tuple>84#include <utility>85#include <variant>87struct KeyOriginInfo;89using common::AmountErrMsg;90using common::AmountHighWarn;91using common::PSBTError;92using interfaces::FoundBlock;93using kernel::ChainstateRole;94using util::ReplaceAll;95using util::ToString;97namespace wallet {99bool AddWalletSetting(interfaces::Chain& chain, const std::string& wallet_name)100{101const auto update_function = [&wallet_name](common::SettingsValue& setting_value) {102if (!setting_value.isArray()) setting_value.setArray();103for (const auto& value : setting_value.getValues()) {104if (value.isStr() && value.get_str() == wallet_name) return interfaces::SettingsAction::SKIP_WRITE;105}106setting_value.push_back(wallet_name);107return interfaces::SettingsAction::WRITE;108};109return chain.updateRwSetting("wallet", update_function);110}112bool RemoveWalletSetting(interfaces::Chain& chain, const std::string& wallet_name)113{114const auto update_function = [&wallet_name](common::SettingsValue& setting_value) {115if (!setting_value.isArray()) {116if (wallet_name.empty() && setting_value.isNull()) {117// Empty setting suppresses backwards-compatible default wallet autoload.118setting_value.setArray();119return interfaces::SettingsAction::WRITE;120}121return interfaces::SettingsAction::SKIP_WRITE;122}123common::SettingsValue new_value(common::SettingsValue::VARR);124for (const auto& value : setting_value.getValues()) {125if (!value.isStr() || value.get_str() != wallet_name) new_value.push_back(value);126}127if (new_value.size() == setting_value.size()) return interfaces::SettingsAction::SKIP_WRITE;128setting_value = std::move(new_value);129return interfaces::SettingsAction::WRITE;130};131return chain.updateRwSetting("wallet", update_function);132}134static void UpdateWalletSetting(interfaces::Chain& chain,135const std::string& wallet_name,136std::optional<bool> load_on_startup,137std::vector<bilingual_str>& warnings)138{139if (!load_on_startup) return;140if (load_on_startup.value() && !AddWalletSetting(chain, wallet_name)) {141warnings.emplace_back(Untranslated("Wallet load on startup setting could not be updated, so wallet may not be loaded next node startup."));142} else if (!load_on_startup.value() && !RemoveWalletSetting(chain, wallet_name)) {143warnings.emplace_back(Untranslated("Wallet load on startup setting could not be updated, so wallet may still be loaded next node startup."));144}145}147/**148* Refresh mempool status so the wallet is in an internally consistent state and149* immediately knows the transaction's status: Whether it can be considered150* trusted and is eligible to be abandoned ...151*/152static void RefreshMempoolStatus(CWalletTx& tx, interfaces::Chain& chain)153{154if (chain.isInMempool(tx.GetHash())) {155tx.m_state = TxStateInMempool();156} else if (tx.state<TxStateInMempool>()) {157tx.m_state = TxStateInactive();158}159}161bool AddWallet(WalletContext& context, const std::shared_ptr<CWallet>& wallet)162{163LOCK(context.wallets_mutex);164assert(wallet);165std::vector<std::shared_ptr<CWallet>>::const_iterator i = std::find(context.wallets.begin(), context.wallets.end(), wallet);166if (i != context.wallets.end()) return false;167context.wallets.push_back(wallet);168wallet->ConnectScriptPubKeyManNotifiers();169wallet->NotifyCanGetAddressesChanged();170return true;171}173bool RemoveWallet(WalletContext& context, const std::shared_ptr<CWallet>& wallet, std::optional<bool> load_on_start, std::vector<bilingual_str>& warnings)174{175assert(wallet);177interfaces::Chain& chain = wallet->chain();178std::string name = wallet->GetName();179WITH_LOCK(wallet->cs_wallet, wallet->WriteBestBlock());181// Unregister with the validation interface which also drops shared pointers.182wallet->DisconnectChainNotifications();183{184LOCK(context.wallets_mutex);185std::vector<std::shared_ptr<CWallet>>::iterator i = std::find(context.wallets.begin(), context.wallets.end(), wallet);186if (i == context.wallets.end()) return false;187context.wallets.erase(i);188}189// Notify unload so that upper layers release the shared pointer.190wallet->NotifyUnload();192// Write the wallet setting193UpdateWalletSetting(chain, name, load_on_start, warnings);195return true;196}198bool RemoveWallet(WalletContext& context, const std::shared_ptr<CWallet>& wallet, std::optional<bool> load_on_start)199{200std::vector<bilingual_str> warnings;201return RemoveWallet(context, wallet, load_on_start, warnings);202}204std::vector<std::shared_ptr<CWallet>> GetWallets(WalletContext& context)205{206LOCK(context.wallets_mutex);207return context.wallets;208}210std::shared_ptr<CWallet> GetDefaultWallet(WalletContext& context, size_t& count)211{212LOCK(context.wallets_mutex);213count = context.wallets.size();214return count == 1 ? context.wallets[0] : nullptr;215}217std::shared_ptr<CWallet> GetWallet(WalletContext& context, const std::string& name)218{219LOCK(context.wallets_mutex);220for (const std::shared_ptr<CWallet>& wallet : context.wallets) {221if (wallet->GetName() == name) return wallet;222}223return nullptr;224}226std::unique_ptr<interfaces::Handler> HandleLoadWallet(WalletContext& context, LoadWalletFn load_wallet)227{228LOCK(context.wallets_mutex);229auto it = context.wallet_load_fns.emplace(context.wallet_load_fns.end(), std::move(load_wallet));230return interfaces::MakeCleanupHandler([&context, it] { LOCK(context.wallets_mutex); context.wallet_load_fns.erase(it); });231}233void NotifyWalletLoaded(WalletContext& context, const std::shared_ptr<CWallet>& wallet)234{235LOCK(context.wallets_mutex);236for (auto& load_wallet : context.wallet_load_fns) {237load_wallet(interfaces::MakeWallet(context, wallet));238}239}241static GlobalMutex g_loading_wallet_mutex;242static GlobalMutex g_wallet_release_mutex;243static std::condition_variable g_wallet_release_cv;244static std::set<std::string> g_loading_wallet_set GUARDED_BY(g_loading_wallet_mutex);245static std::set<std::string> g_unloading_wallet_set GUARDED_BY(g_wallet_release_mutex);247// Custom deleter for shared_ptr<CWallet>.248static void FlushAndDeleteWallet(CWallet* wallet)249{250const std::string name = wallet->GetName();