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) 2019-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_SCRIPTPUBKEYMAN_H6#define BITCOIN_WALLET_SCRIPTPUBKEYMAN_H8#include <addresstype.h>9#include <common/messages.h>10#include <common/signmessage.h>11#include <common/types.h>12#include <musig.h>13#include <node/types.h>14#include <psbt.h>15#include <script/descriptor.h>16#include <script/script.h>17#include <script/signingprovider.h>18#include <util/btcsignals.h>19#include <util/hasher.h>20#include <util/log.h>21#include <util/result.h>22#include <util/time.h>23#include <wallet/crypter.h>24#include <wallet/types.h>25#include <wallet/walletdb.h>26#include <wallet/walletutil.h>28#include <functional>29#include <optional>30#include <unordered_map>31#include <unordered_set>33enum class OutputType;35namespace wallet {36struct MigrationData;37class ScriptPubKeyMan;39// Wallet storage things that ScriptPubKeyMans need in order to be able to store things to the wallet database.40// It provides access to things that are part of the entire wallet and not specific to a ScriptPubKeyMan such as41// wallet flags, wallet version, encryption keys, encryption status, and the database itself. This allows a42// ScriptPubKeyMan to have callbacks into CWallet without causing a circular dependency.43// WalletStorage should be the same for all ScriptPubKeyMans of a wallet.44class WalletStorage45{46public:47virtual ~WalletStorage() = default;48virtual std::string LogName() const = 0;49virtual WalletDatabase& GetDatabase() const = 0;50virtual bool IsWalletFlagSet(uint64_t) const = 0;51virtual void UnsetBlankWalletFlag(WalletBatch&) = 0;52//! Pass the encryption key to cb().53virtual bool WithEncryptionKey(std::function<bool (const CKeyingMaterial&)> cb) const = 0;54virtual bool HasEncryptionKeys() const = 0;55virtual bool IsLocked() const = 0;56//! Callback function for after TopUp completes containing any scripts that were added by a SPKMan57virtual void TopUpCallback(const std::set<CScript>&, ScriptPubKeyMan*) = 0;58};60//! Constant representing an unknown spkm creation time61inline constexpr int64_t UNKNOWN_TIME = std::numeric_limits<int64_t>::max();63//! Default for -keypool64inline constexpr unsigned int DEFAULT_KEYPOOL_SIZE = 1000;66struct WalletDestination67{68CTxDestination dest;69std::optional<bool> internal;70};72/*73* A class implementing ScriptPubKeyMan manages some (or all) scriptPubKeys used in a wallet.74* It contains the scripts and keys related to the scriptPubKeys it manages.75* A ScriptPubKeyMan will be able to give out scriptPubKeys to be used, as well as marking76* when a scriptPubKey has been used. It also handles when and how to store a scriptPubKey77* and its related scripts and keys, including encryption.78*/79class ScriptPubKeyMan80{81protected:82WalletStorage& m_storage;84public:85explicit ScriptPubKeyMan(WalletStorage& storage) : m_storage(storage) {}86virtual ~ScriptPubKeyMan() = default;87virtual util::Result<CTxDestination> GetNewDestination(const OutputType type) { return util::Error{Untranslated("Not supported")}; }88virtual bool IsMine(const CScript& script) const { return false; }90//! Check that the given decryption key is valid for this ScriptPubKeyMan, i.e. it decrypts all of the keys handled by it.91virtual bool CheckDecryptionKey(const CKeyingMaterial& master_key) { return false; }92virtual bool Encrypt(const CKeyingMaterial& master_key, WalletBatch* batch) { return false; }94virtual util::Result<CTxDestination> GetReservedDestination(const OutputType type, bool internal, int64_t& index) { return util::Error{Untranslated("Not supported")}; }95virtual void KeepDestination(int64_t index, const OutputType& type) {}96virtual void ReturnDestination(int64_t index, bool internal, const CTxDestination& addr) {}98/** Fills internal address pool. Use within ScriptPubKeyMan implementations should be used sparingly and only99* when something from the address pool is removed, excluding GetNewDestination and GetReservedDestination.100* External wallet code is primarily responsible for topping up prior to fetching new addresses101*/102virtual bool TopUp(unsigned int size = 0) { return false; }104/** Mark unused addresses as being used105* Affects all keys up to and including the one determined by provided script.106*107* @param script determines the last key to mark as used108*109* @return All of the addresses affected110*/111virtual std::vector<WalletDestination> MarkUnusedAddresses(const CScript& script) { return {}; }113/* Returns true if HD is enabled */114virtual bool IsHDEnabled() const { return false; }116/* Returns true if the wallet can give out new addresses. This means it has keys in the keypool or can generate new keys */117virtual bool CanGetAddresses(bool internal = false) const { return false; }119virtual bool HavePrivateKeys() const { return false; }120virtual bool HaveCryptedKeys() const { return false; }122virtual unsigned int GetKeyPoolSize() const { return 0; }124virtual int64_t GetTimeFirstKey() const { return 0; }126virtual std::unique_ptr<CKeyMetadata> GetMetadata(const CTxDestination& dest) const { return nullptr; }128virtual std::unique_ptr<SigningProvider> GetSolvingProvider(const CScript& script) const { return nullptr; }130/** Whether this ScriptPubKeyMan can provide a SigningProvider (via GetSolvingProvider) that, combined with131* sigdata, can produce solving data.132*/133virtual bool CanProvide(const CScript& script, SignatureData& sigdata) { return false; }135/** Creates new signatures and adds them to the transaction. Returns whether all inputs were signed */136virtual bool SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, bilingual_str>& input_errors) const { return false; }137/** Sign a message with the given script */138virtual SigningResult SignMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) const { return SigningResult::SIGNING_FAILED; };139/** Adds script and derivation path information to a PSBT, and optionally signs it. */140virtual std::optional<common::PSBTError> FillPSBT(PartiallySignedTransaction& psbt, const PrecomputedTransactionData& txdata, const common::PSBTFillOptions& options, int* n_signed = nullptr) const { return common::PSBTError::UNSUPPORTED; }142virtual uint256 GetID() const { return uint256(); }144/** Returns a set of all the scriptPubKeys that this ScriptPubKeyMan watches */145virtual std::unordered_set<CScript, SaltedSipHasher> GetScriptPubKeys() const { return {}; };147/** Prepends the wallet name in logging output to ease debugging in multi-wallet use cases */148template <typename... Params>149void WalletLogPrintf(util::ConstevalFormatString<sizeof...(Params)> wallet_fmt, const Params&... params) const150{151LogInfo("[%s] %s", m_storage.LogName(), tfm::format(wallet_fmt, params...));152};154/** Keypool has new keys */155btcsignals::signal<void ()> NotifyCanGetAddressesChanged;157/** Birth time changed */158btcsignals::signal<void (const ScriptPubKeyMan* spkm, int64_t new_birth_time)> NotifyFirstKeyTimeChanged;159};161/** Output types associated with LegacyDataSPKM. */162inline const std::unordered_set<OutputType> LEGACY_OUTPUT_TYPES {163OutputType::LEGACY,164OutputType::P2SH_SEGWIT,165OutputType::BECH32,166};168using KeyMap = std::map<CKeyID, CKey>;169using CryptedKeyMap = std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char>>>;171// Manages the minimum data needed to load and migrate a legacy wallet.172class LegacyDataSPKM : public ScriptPubKeyMan, public FillableSigningProvider173{174private:175using WatchOnlySet = std::set<CScript>;176using WatchKeyMap = std::map<CKeyID, CPubKey>;178CryptedKeyMap mapCryptedKeys GUARDED_BY(cs_KeyStore);179WatchOnlySet setWatchOnly GUARDED_BY(cs_KeyStore);180WatchKeyMap mapWatchKeys GUARDED_BY(cs_KeyStore);182/* the HD chain data model (external chain counters) */183CHDChain m_hd_chain;184std::unordered_map<CKeyID, CHDChain, SaltedSipHasher> m_inactive_hd_chains;186//! keeps track of whether Unlock has run a thorough check before187bool fDecryptionThoroughlyChecked = true;189bool AddWatchOnlyInMem(const CScript &dest);190virtual bool AddKeyPubKeyInner(const CKey& key, const CPubKey &pubkey);191bool AddCryptedKeyInner(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret);193// Helper function to retrieve a conservative superset of all output scripts that may be relevant to this LegacyDataSPKM.194// It may include scripts that are invalid or not actually watched by this LegacyDataSPKM.195// Used only in migration.196std::unordered_set<CScript, SaltedSipHasher> GetCandidateScriptPubKeys() const;198bool IsMine(const CScript& script) const override;199bool CanProvide(const CScript& script, SignatureData& sigdata) override;200public:201using ScriptPubKeyMan::ScriptPubKeyMan;203// Map from Key ID to key metadata.204std::map<CKeyID, CKeyMetadata> mapKeyMetadata GUARDED_BY(cs_KeyStore);206// Map from Script ID to key metadata (for watch-only keys).207std::map<CScriptID, CKeyMetadata> m_script_metadata GUARDED_BY(cs_KeyStore);209// ScriptPubKeyMan overrides210bool CheckDecryptionKey(const CKeyingMaterial& master_key) override;211std::unordered_set<CScript, SaltedSipHasher> GetScriptPubKeys() const override;212std::unique_ptr<SigningProvider> GetSolvingProvider(const CScript& script) const override;213uint256 GetID() const override { return uint256::ONE; }215// FillableSigningProvider overrides216bool HaveKey(const CKeyID &address) const override;217bool GetKey(const CKeyID &address, CKey& keyOut) const override;218bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override;219bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override;221//! Load metadata (used by LoadWallet)222virtual void LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata &metadata);223virtual void LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata &metadata);225//! Adds a watch-only address to the store, without saving it to disk (used by LoadWallet)226bool LoadWatchOnly(const CScript &dest);227//! Returns whether the watch-only script is in the wallet228bool HaveWatchOnly(const CScript &dest) const;229//! Adds a key to the store, without saving it to disk (used by LoadWallet)230bool LoadKey(const CKey& key, const CPubKey &pubkey);231//! Adds an encrypted key to the store, without saving it to disk (used by LoadWallet)232bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret, bool checksum_valid);233//! Adds a CScript to the store234bool LoadCScript(const CScript& redeemScript);235//! Load a HD chain model (used by LoadWallet)236void LoadHDChain(const CHDChain& chain);237void AddInactiveHDChain(const CHDChain& chain);238const CHDChain& GetHDChain() const { return m_hd_chain; }240//! Fetches a pubkey from mapWatchKeys if it exists there241bool GetWatchPubKey(const CKeyID &address, CPubKey &pubkey_out) const;243/**244* Retrieves scripts that were imported by bugs into the legacy spkm and are245* simply invalid, such as a sh(sh(pkh())) script, or not watched.246*/247std::unordered_set<CScript, SaltedSipHasher> GetNotMineScriptPubKeys() const;249/** Get the DescriptorScriptPubKeyMans (with private keys) that have the same scriptPubKeys as this LegacyDataSPKM.250* Does not modify this LegacyDataSPKM. */