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) 2017-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#ifndef BITCOIN_WALLET_WALLETUTIL_H6#define BITCOIN_WALLET_WALLETUTIL_H8#include <script/descriptor.h>9#include <util/fs.h>11#include <vector>13namespace wallet {15enum WalletFlags : uint64_t {16// wallet flags in the upper section (> 1 << 31) will lead to not opening the wallet if flag is unknown17// unknown wallet flags in the lower section <= (1 << 31) will be tolerated19// will categorize coins as clean (not reused) and dirty (reused), and handle20// them with privacy considerations in mind21WALLET_FLAG_AVOID_REUSE = (1ULL << 0),23// Indicates that the metadata has already been upgraded to contain key origins24WALLET_FLAG_KEY_ORIGIN_METADATA = (1ULL << 1),26// Indicates that the descriptor cache has been upgraded to cache last hardened xpubs27WALLET_FLAG_LAST_HARDENED_XPUB_CACHED = (1ULL << 2),29// will enforce the rule that the wallet can't contain any private keys (only watch-only/pubkeys)30WALLET_FLAG_DISABLE_PRIVATE_KEYS = (1ULL << 32),32//! Flag set when a wallet contains no HD seed and no private keys, scripts,33//! addresses, and other watch only things, and is therefore "blank."34//!35//! The main function this flag serves is to distinguish a blank wallet from36//! a newly created wallet when the wallet database is loaded, to avoid37//! initialization that should only happen on first run.38//!39//! A secondary function of this flag, which applies to descriptor wallets40//! only, is to serve as an ongoing indication that descriptors in the41//! wallet should be created manually, and that the wallet should not42//! generate automatically generate new descriptors if it is later43//! encrypted. To support this behavior, descriptor wallets unlike legacy44//! wallets do not automatically unset the BLANK flag when things are45//! imported.46//!47//! This flag is also a mandatory flag to prevent previous versions of48//! bitcoin from opening the wallet, thinking it was newly created, and49//! then improperly reinitializing it.50WALLET_FLAG_BLANK_WALLET = (1ULL << 33),52//! Indicate that this wallet supports DescriptorScriptPubKeyMan53WALLET_FLAG_DESCRIPTORS = (1ULL << 34),55//! Indicates that the wallet needs an external signer56WALLET_FLAG_EXTERNAL_SIGNER = (1ULL << 35),57};59//! Get the path of the wallet directory.60fs::path GetWalletDir();62/** Descriptor with some wallet metadata */63class WalletDescriptor64{65private:66int32_t range_start = 0; // First item in range; start of range, inclusive, i.e. [range_start, range_end). This never changes.67int32_t next_index = 0; // Position of the next item to generate68int32_t range_end = 0; // Item after the last; end of range, exclusive, i.e. [range_start, range_end). This will increment with each TopUp()70mutable std::optional<uint256> m_canonical_hash; // Hash of the canonical string, used as a shortcut for comparing canonical strings72uint256 GetCanonicalHash() const;74public:75const std::shared_ptr<const Descriptor> descriptor;76uint64_t creation_time = 0;77DescriptorCache cache;79int32_t GetStart() const { return range_start; }80int32_t GetNext() const { return next_index; }81int32_t GetEnd() const { return range_end; }83//! Increments the next_index of the descriptor.84void IncNext()85{86next_index++;87}89//! Increments the next_index of the descriptor.90void DecNext()91{92next_index--;93}95//! Sets the range_end of the descriptor.96void SetEnd(int32_t end)97{98if (!descriptor->IsRange()) {99CHECK_NONFATAL(end == 1);100}101range_end = end;102}104template <typename Stream>105void Serialize(Stream& s) const106{107std::string descriptor_str = descriptor->ToString();108s << descriptor_str << creation_time << next_index << range_start << range_end;109}111template <typename Stream>112static WalletDescriptor FromStream(deserialize_type, Stream& s)113{114std::string descriptor_str;115uint64_t creation_time;116int32_t next_index, range_start, range_end;117s >> descriptor_str >> creation_time >> next_index >> range_start >> range_end;119std::string error;120FlatSigningProvider keys;121auto descs = Parse(descriptor_str, keys, error, true);122if (descs.empty()) {123throw std::ios_base::failure("Invalid descriptor: " + error);124}125if (descs.size() > 1) {126throw std::ios_base::failure("Can't load a multipath descriptor from databases");127}128return WalletDescriptor(std::move(descs.at(0)), creation_time, range_start, range_end, next_index);129}131WalletDescriptor() = delete;132WalletDescriptor(std::shared_ptr<Descriptor> descriptor, uint64_t creation_time, int32_t range_start, int32_t range_end, int32_t next_index)133: range_start(descriptor->IsRange() ? range_start : 0),134next_index(next_index),135range_end(descriptor->IsRange() ? range_end : 1),136descriptor(descriptor),137creation_time(creation_time)138{}140/** Replaces all metadata (range, start, end, creation time), and cache from another WalletDescriptor if it has the same canonical descriptor string.141* The descriptor itself is not replaced to preserve existing serialization to maintain compatibility with previous software versions that expect142* specific serialization.143*/144void UpdateFrom(const WalletDescriptor& other);146// Compare by using the canonical string to make the hardened indicators consistent for comparison147bool IsCanonicallyEquivalent(const WalletDescriptor& other) const;148};150WalletDescriptor GenerateWalletDescriptor(const CExtPubKey& master_key, const OutputType& output_type, bool internal);151} // namespace wallet153#endif // BITCOIN_WALLET_WALLETUTIL_H