diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h index 6ad87289b..9a7b549f2 100644 --- a/src/wallet/scriptpubkeyman.h +++ b/src/wallet/scriptpubkeyman.h @@ -1,759 +1,759 @@ // Copyright (c) 2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_WALLET_SCRIPTPUBKEYMAN_H #define BITCOIN_WALLET_SCRIPTPUBKEYMAN_H #include <psbt.h> #include <script/descriptor.h> #include <script/signingprovider.h> #include <script/standard.h> #include <util/error.h> #include <util/message.h> #include <wallet/crypter.h> #include <wallet/ismine.h> #include <wallet/walletdb.h> #include <wallet/walletutil.h> #include <boost/signals2/signal.hpp> enum class OutputType; class CChainParams; struct bilingual_str; // Wallet storage things that ScriptPubKeyMans need in order to be able to store // things to the wallet database. It provides access to things that are part of // the entire wallet and not specific to a ScriptPubKeyMan such as wallet flags, // wallet version, encryption keys, encryption status, and the database itself. // This allows a ScriptPubKeyMan to have callbacks into CWallet without causing // a circular dependency. WalletStorage should be the same for all // ScriptPubKeyMans of a wallet. class WalletStorage { public: virtual ~WalletStorage() = default; virtual const std::string GetDisplayName() const = 0; virtual WalletDatabase &GetDatabase() = 0; virtual const CChainParams &GetChainParams() const = 0; virtual bool IsWalletFlagSet(uint64_t) const = 0; virtual void UnsetBlankWalletFlag(WalletBatch &) = 0; virtual bool CanSupportFeature(enum WalletFeature) const = 0; virtual void SetMinVersion(enum WalletFeature, WalletBatch * = nullptr, bool = false) = 0; virtual const CKeyingMaterial &GetEncryptionKey() const = 0; virtual bool HasEncryptionKeys() const = 0; virtual bool IsLocked() const = 0; }; //! Default for -keypool static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000; std::vector<CKeyID> GetAffectedKeys(const CScript &spk, const SigningProvider &provider); /** * A key from a CWallet's keypool * * The wallet holds one (for pre HD-split wallets) or several keypools. These * are sets of keys that have not yet been used to provide addresses or receive * change. * * The Bitcoin ABC wallet was originally a collection of unrelated private * keys with their associated addresses. If a non-HD wallet generated a * key/address, gave that address out and then restored a backup from before * that key's generation, then any funds sent to that address would be * lost definitively. * * The keypool was implemented to avoid this scenario (commit: 10384941). The * wallet would generate a set of keys (100 by default). When a new public key * was required, either to give out as an address or to use in a change output, * it would be drawn from the keypool. The keypool would then be topped up to * maintain 100 keys. This ensured that as long as the wallet hadn't used more * than 100 keys since the previous backup, all funds would be safe, since a * restored wallet would be able to scan for all owned addresses. * * A keypool also allowed encrypted wallets to give out addresses without * having to be decrypted to generate a new private key. * * With the introduction of HD wallets (commit: f1902510), the keypool * essentially became an address look-ahead pool. Restoring old backups can no * longer definitively lose funds as long as the addresses used were from the * wallet's HD seed (since all private keys can be rederived from the seed). * However, if many addresses were used since the backup, then the wallet may * not know how far ahead in the HD chain to look for its addresses. The * keypool is used to implement a 'gap limit'. The keypool maintains a set of * keys (by default 1000) ahead of the last used key and scans for the * addresses of those keys. This avoids the risk of not seeing transactions * involving the wallet's addresses, or of re-using the same address. * In the unlikely case where none of the addresses in the `gap limit` are * used on-chain, the look-ahead will not be incremented to keep * a constant size and addresses beyond this range will not be detected by an * old backup. For this reason, it is not recommended to decrease keypool size * lower than default value. * * The HD-split wallet feature added a second keypool (commit: 02592f4c). There * is an external keypool (for addresses to hand out) and an internal keypool * (for change addresses). * * Keypool keys are stored in the wallet/keystore's keymap. The keypool data is * stored as sets of indexes in the wallet (setInternalKeyPool, * setExternalKeyPool and set_pre_split_keypool), and a map from the key to the * index (m_pool_key_to_index). The CKeyPool object is used to * serialize/deserialize the pool data to/from the database. */ class CKeyPool { public: //! The time at which the key was generated. Set in AddKeypoolPubKeyWithDB int64_t nTime; //! The public key CPubKey vchPubKey; //! Whether this keypool entry is in the internal keypool (for change //! outputs) bool fInternal; //! Whether this key was generated for a keypool before the wallet was //! upgraded to HD-split bool m_pre_split; CKeyPool(); CKeyPool(const CPubKey &vchPubKeyIn, bool internalIn); ADD_SERIALIZE_METHODS; template <typename Stream, typename Operation> inline void SerializationOp(Stream &s, Operation ser_action) { int nVersion = s.GetVersion(); if (!(s.GetType() & SER_GETHASH)) { READWRITE(nVersion); } READWRITE(nTime); READWRITE(vchPubKey); if (ser_action.ForRead()) { try { READWRITE(fInternal); } catch (std::ios_base::failure &) { /** * flag as external address if we can't read the internal * boolean (this will be the case for any wallet before the HD * chain split version) */ fInternal = false; } try { READWRITE(m_pre_split); } catch (std::ios_base::failure &) { /** * flag as postsplit address if we can't read the m_pre_split * boolean (this will be the case for any wallet that upgrades * to HD chain split) */ m_pre_split = false; } } else { READWRITE(fInternal); READWRITE(m_pre_split); } } }; /** * A class implementing ScriptPubKeyMan manages some (or all) scriptPubKeys used * in a wallet. It contains the scripts and keys related to the scriptPubKeys it * manages. A ScriptPubKeyMan will be able to give out scriptPubKeys to be used, * as well as marking when a scriptPubKey has been used. It also handles when * and how to store a scriptPubKey and its related scripts and keys, including * encryption. */ class ScriptPubKeyMan { protected: WalletStorage &m_storage; public: ScriptPubKeyMan(WalletStorage &storage) : m_storage(storage) {} virtual ~ScriptPubKeyMan(){}; virtual bool GetNewDestination(const OutputType type, CTxDestination &dest, std::string &error) { return false; } virtual isminetype IsMine(const CScript &script) const { return ISMINE_NO; } //! Check that the given decryption key is valid for this ScriptPubKeyMan, //! i.e. it decrypts all of the keys handled by it. virtual bool CheckDecryptionKey(const CKeyingMaterial &master_key, bool accept_no_keys = false) { return false; } virtual bool Encrypt(const CKeyingMaterial &master_key, WalletBatch *batch) { return false; } virtual bool GetReservedDestination(const OutputType type, bool internal, CTxDestination &address, int64_t &index, CKeyPool &keypool) { return false; } virtual void KeepDestination(int64_t index, const OutputType &type) {} virtual void ReturnDestination(int64_t index, bool internal, const CTxDestination &addr) {} /** * Fills internal address pool. Use within ScriptPubKeyMan implementations * should be used sparingly and only when something from the address pool is * removed, excluding GetNewDestination and GetReservedDestination. External * wallet code is primarily responsible for topping up prior to fetching new * addresses */ virtual bool TopUp(unsigned int size = 0) { return false; } //! Mark unused addresses as being used virtual void MarkUnusedAddresses(const CScript &script) {} /** * Sets up the key generation stuff, i.e. generates new HD seeds and sets * them as active. Returns false if already setup or setup fails, true if * setup is successful Set force=true to make it re-setup if already setup, * used for upgrades */ virtual bool SetupGeneration(bool force = false) { return false; } /* Returns true if HD is enabled */ virtual bool IsHDEnabled() const { return false; } /** * Returns true if the wallet can give out new addresses. This means it has * keys in the keypool or can generate new keys. */ virtual bool CanGetAddresses(bool internal = false) const { return false; } /** Upgrades the wallet to the specified version */ virtual bool Upgrade(int prev_version, bilingual_str &error) { return false; } virtual bool HavePrivateKeys() const { return false; } //! The action to do when the DB needs rewrite virtual void RewriteDB() {} virtual int64_t GetOldestKeyPoolTime() const { return GetTime(); } virtual size_t KeypoolCountExternalKeys() const { return 0; } virtual unsigned int GetKeyPoolSize() const { return 0; } virtual int64_t GetTimeFirstKey() const { return 0; } virtual std::unique_ptr<CKeyMetadata> GetMetadata(const CTxDestination &dest) const { return nullptr; } virtual std::unique_ptr<SigningProvider> GetSolvingProvider(const CScript &script) const { return nullptr; } /** * Whether this ScriptPubKeyMan can provide a SigningProvider (via * GetSolvingProvider) that, combined with sigdata, can produce solving * data. */ virtual bool CanProvide(const CScript &script, SignatureData &sigdata) { return false; } /** * Creates new signatures and adds them to the transaction. Returns whether * all inputs were signed */ virtual bool SignTransaction(CMutableTransaction &tx, const std::map<COutPoint, Coin> &coins, SigHashType sighash, std::map<int, std::string> &input_errors) const { return false; } /** Sign a message with the given script */ virtual SigningResult SignMessage(const std::string &message, const PKHash &pkhash, std::string &str_sig) const { return SigningResult::SIGNING_FAILED; }; /** * Adds script and derivation path information to a PSBT, and optionally * signs it. */ virtual TransactionError FillPSBT(PartiallySignedTransaction &psbt, SigHashType sighash_type = SigHashType().withForkId(), bool sign = true, bool bip32derivs = false) const { return TransactionError::INVALID_PSBT; } virtual uint256 GetID() const { return uint256(); } virtual void SetType(OutputType type, bool internal) {} /** * Prepends the wallet name in logging output to ease debugging in * multi-wallet use cases */ template <typename... Params> void WalletLogPrintf(std::string fmt, Params... parameters) const { LogPrintf(("%s " + fmt).c_str(), m_storage.GetDisplayName(), parameters...); }; /** Watch-only address added */ boost::signals2::signal<void(bool fHaveWatchOnly)> NotifyWatchonlyChanged; /** Keypool has new keys */ boost::signals2::signal<void()> NotifyCanGetAddressesChanged; }; class LegacyScriptPubKeyMan : public ScriptPubKeyMan, public FillableSigningProvider { private: //! keeps track of whether Unlock has run a thorough check before bool fDecryptionThoroughlyChecked = false; using WatchOnlySet = std::set<CScript>; using WatchKeyMap = std::map<CKeyID, CPubKey>; WalletBatch *encrypted_batch GUARDED_BY(cs_KeyStore) = nullptr; using CryptedKeyMap = std::map<CKeyID, std::pair<CPubKey, std::vector<uint8_t>>>; CryptedKeyMap mapCryptedKeys GUARDED_BY(cs_KeyStore); WatchOnlySet setWatchOnly GUARDED_BY(cs_KeyStore); WatchKeyMap mapWatchKeys GUARDED_BY(cs_KeyStore); int64_t nTimeFirstKey GUARDED_BY(cs_KeyStore) = 0; bool AddKeyPubKeyInner(const CKey &key, const CPubKey &pubkey); bool AddCryptedKeyInner(const CPubKey &vchPubKey, const std::vector<uint8_t> &vchCryptedSecret); /** * Private version of AddWatchOnly method which does not accept a * timestamp, and which will reset the wallet's nTimeFirstKey value to 1 if * the watch key did not previously have a timestamp associated with it. * Because this is an inherited virtual method, it is accessible despite * being marked private, but it is marked private anyway to encourage use * of the other AddWatchOnly which accepts a timestamp and sets * nTimeFirstKey more intelligently for more efficient rescans. */ bool AddWatchOnly(const CScript &dest) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); bool AddWatchOnlyWithDB(WalletBatch &batch, const CScript &dest) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); bool AddWatchOnlyInMem(const CScript &dest); //! Adds a watch-only address to the store, and saves it to disk. bool AddWatchOnlyWithDB(WalletBatch &batch, const CScript &dest, int64_t create_time) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); //! Adds a key to the store, and saves it to disk. bool AddKeyPubKeyWithDB(WalletBatch &batch, const CKey &key, const CPubKey &pubkey) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); void AddKeypoolPubkeyWithDB(const CPubKey &pubkey, const bool internal, WalletBatch &batch); //! Adds a script to the store and saves it to disk bool AddCScriptWithDB(WalletBatch &batch, const CScript &script); /** Add a KeyOriginInfo to the wallet */ bool AddKeyOriginWithDB(WalletBatch &batch, const CPubKey &pubkey, const KeyOriginInfo &info); /* the HD chain data model (external chain counters) */ CHDChain hdChain; /* HD derive new child key (on internal or external chain) */ void DeriveNewChildKey(WalletBatch &batch, CKeyMetadata &metadata, CKey &secret, bool internal = false) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); std::set<int64_t> setInternalKeyPool GUARDED_BY(cs_KeyStore); std::set<int64_t> setExternalKeyPool GUARDED_BY(cs_KeyStore); std::set<int64_t> set_pre_split_keypool GUARDED_BY(cs_KeyStore); int64_t m_max_keypool_index GUARDED_BY(cs_KeyStore) = 0; std::map<CKeyID, int64_t> m_pool_key_to_index; // Tracks keypool indexes to CKeyIDs of keys that have been taken out of the // keypool but may be returned to it std::map<int64_t, CKeyID> m_index_to_reserved_key; //! Fetches a key from the keypool bool GetKeyFromPool(CPubKey &key, const OutputType type, bool internal = false); /** * Reserves a key from the keypool and sets nIndex to its index * * @param[out] nIndex the index of the key in keypool * @param[out] keypool the keypool the key was drawn from, which could be * the the pre-split pool if present, or the internal or external pool * @param fRequestedInternal true if the caller would like the key drawn * from the internal keypool, false if external is preferred * * @return true if succeeded, false if failed due to empty keypool * @throws std::runtime_error if keypool read failed, key was invalid, * was not found in the wallet, or was misclassified in the internal * or external keypool */ bool ReserveKeyFromKeyPool(int64_t &nIndex, CKeyPool &keypool, bool fRequestedInternal); public: using ScriptPubKeyMan::ScriptPubKeyMan; bool GetNewDestination(const OutputType type, CTxDestination &dest, std::string &error) override; isminetype IsMine(const CScript &script) const override; bool CheckDecryptionKey(const CKeyingMaterial &master_key, bool accept_no_keys = false) override; bool Encrypt(const CKeyingMaterial &master_key, WalletBatch *batch) override; bool GetReservedDestination(const OutputType type, bool internal, CTxDestination &address, int64_t &index, CKeyPool &keypool) override; void KeepDestination(int64_t index, const OutputType &type) override; void ReturnDestination(int64_t index, bool internal, const CTxDestination &) override; bool TopUp(unsigned int size = 0) override; void MarkUnusedAddresses(const CScript &script) override; //! Upgrade stored CKeyMetadata objects to store key origin info as //! KeyOriginInfo void UpgradeKeyMetadata(); bool IsHDEnabled() const override; bool SetupGeneration(bool force = false) override; bool Upgrade(int prev_version, bilingual_str &error) override; bool HavePrivateKeys() const override; void RewriteDB() override; int64_t GetOldestKeyPoolTime() const override; size_t KeypoolCountExternalKeys() const override; unsigned int GetKeyPoolSize() const override; int64_t GetTimeFirstKey() const override; std::unique_ptr<CKeyMetadata> GetMetadata(const CTxDestination &dest) const override; bool CanGetAddresses(bool internal = false) const override; std::unique_ptr<SigningProvider> GetSolvingProvider(const CScript &script) const override; bool CanProvide(const CScript &script, SignatureData &sigdata) override; bool SignTransaction(CMutableTransaction &tx, const std::map<COutPoint, Coin> &coins, SigHashType sighash, std::map<int, std::string> &input_errors) const override; SigningResult SignMessage(const std::string &message, const PKHash &pkhash, std::string &str_sig) const override; TransactionError FillPSBT(PartiallySignedTransaction &psbt, SigHashType sighash_type = SigHashType().withForkId(), bool sign = true, bool bip32derivs = false) const override; uint256 GetID() const override; void SetType(OutputType type, bool internal) override; // Map from Key ID to key metadata. std::map<CKeyID, CKeyMetadata> mapKeyMetadata GUARDED_BY(cs_KeyStore); // Map from Script ID to key metadata (for watch-only keys). std::map<CScriptID, CKeyMetadata> m_script_metadata GUARDED_BY(cs_KeyStore); //! Adds a key to the store, and saves it to disk. bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey) override; //! Adds a key to the store, without saving it to disk (used by LoadWallet) bool LoadKey(const CKey &key, const CPubKey &pubkey); //! Adds an encrypted key to the store, and saves it to disk. bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector<uint8_t> &vchCryptedSecret); //! Adds an encrypted key to the store, without saving it to disk (used by //! LoadWallet) bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector<uint8_t> &vchCryptedSecret); void UpdateTimeFirstKey(int64_t nCreateTime) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); //! Adds a CScript to the store bool LoadCScript(const CScript &redeemScript); //! Load metadata (used by LoadWallet) void LoadKeyMetadata(const CKeyID &keyID, const CKeyMetadata &metadata); void LoadScriptMetadata(const CScriptID &script_id, const CKeyMetadata &metadata); //! Generate a new key CPubKey GenerateNewKey(WalletBatch &batch, bool internal = false) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); /* Set the HD chain model (chain child index counters) */ void SetHDChain(const CHDChain &chain, bool memonly); const CHDChain &GetHDChain() const { return hdChain; } //! Adds a watch-only address to the store, without saving it to disk (used //! by LoadWallet) bool LoadWatchOnly(const CScript &dest); //! Returns whether the watch-only script is in the wallet bool HaveWatchOnly(const CScript &dest) const; //! Returns whether there are any watch-only things in the wallet bool HaveWatchOnly() const; //! Remove a watch only script from the keystore bool RemoveWatchOnly(const CScript &dest); bool AddWatchOnly(const CScript &dest, int64_t nCreateTime) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); //! Fetches a pubkey from mapWatchKeys if it exists there bool GetWatchPubKey(const CKeyID &address, CPubKey &pubkey_out) const; /* SigningProvider overrides */ bool HaveKey(const CKeyID &address) const override; bool GetKey(const CKeyID &address, CKey &keyOut) const override; bool GetPubKey(const CKeyID &address, CPubKey &vchPubKeyOut) const override; bool AddCScript(const CScript &redeemScript) override; bool GetKeyOrigin(const CKeyID &keyid, KeyOriginInfo &info) const override; //! Load a keypool entry void LoadKeyPool(int64_t nIndex, const CKeyPool &keypool); bool NewKeyPool(); void MarkPreSplitKeys() EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); bool ImportScripts(const std::set<CScript> scripts, int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); bool ImportPrivKeys(const std::map<CKeyID, CKey> &privkey_map, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); bool ImportPubKeys( const std::vector<CKeyID> &ordered_pubkeys, const std::map<CKeyID, CPubKey> &pubkey_map, const std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> &key_origins, const bool add_keypool, const bool internal, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); bool ImportScriptPubKeys(const std::set<CScript> &script_pub_keys, const bool have_solving_data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); /* Returns true if the wallet can generate new keys */ bool CanGenerateKeys() const; /* Generates a new HD seed (will not be activated) */ CPubKey GenerateNewSeed(); /* Derives a new HD seed (will not be activated) */ CPubKey DeriveNewSeed(const CKey &key); /* Set the current HD seed (will reset the chain child index counters) Sets the seed's version based on the current wallet version (so the caller must ensure the current wallet version is correct before calling this function). */ void SetHDSeed(const CPubKey &key); /** * Explicitly make the wallet learn the related scripts for outputs to the * given key. This is purely to make the wallet file compatible with older * software, as FillableSigningProvider automatically does this implicitly * for all keys now. */ void LearnRelatedScripts(const CPubKey &key, OutputType); /** * Same as LearnRelatedScripts, but when the OutputType is not known (and * could be anything). */ void LearnAllRelatedScripts(const CPubKey &key); /** * Marks all keys in the keypool up to and including reserve_key as used. */ void MarkReserveKeysAsUsed(int64_t keypool_id) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); const std::map<CKeyID, int64_t> &GetAllReserveKeys() const { return m_pool_key_to_index; } std::set<CKeyID> GetKeys() const override; }; /** * Wraps a LegacyScriptPubKeyMan so that it can be returned in a new unique_ptr. * Does not provide privkeys. */ class LegacySigningProvider : public SigningProvider { private: const LegacyScriptPubKeyMan &m_spk_man; public: LegacySigningProvider(const LegacyScriptPubKeyMan &spk_man) : m_spk_man(spk_man) {} bool GetCScript(const CScriptID &scriptid, CScript &script) const override { return m_spk_man.GetCScript(scriptid, script); } bool HaveCScript(const CScriptID &scriptid) const override { return m_spk_man.HaveCScript(scriptid); } bool GetPubKey(const CKeyID &address, CPubKey &pubkey) const override { return m_spk_man.GetPubKey(address, pubkey); } bool GetKey(const CKeyID &address, CKey &key) const override { return false; } bool HaveKey(const CKeyID &address) const override { return false; } bool GetKeyOrigin(const CKeyID &keyid, KeyOriginInfo &info) const override { return m_spk_man.GetKeyOrigin(keyid, info); } }; class DescriptorScriptPubKeyMan : public ScriptPubKeyMan { private: WalletDescriptor m_wallet_descriptor GUARDED_BY(cs_desc_man); // Map of scripts to descriptor range index using ScriptPubKeyMap = std::map<CScript, int32_t>; // Map of pubkeys involved in scripts to descriptor range index using PubKeyMap = std::map<CPubKey, int32_t>; using CryptedKeyMap = std::map<CKeyID, std::pair<CPubKey, std::vector<uint8_t>>>; using KeyMap = std::map<CKeyID, CKey>; ScriptPubKeyMap m_map_script_pub_keys GUARDED_BY(cs_desc_man); PubKeyMap m_map_pubkeys GUARDED_BY(cs_desc_man); int32_t m_max_cached_index = -1; OutputType m_address_type; - bool m_internal; + bool m_internal = false; KeyMap m_map_keys GUARDED_BY(cs_desc_man); CryptedKeyMap m_map_crypted_keys GUARDED_BY(cs_desc_man); bool SetCrypted(); //! keeps track of whether Unlock has run a thorough check before bool m_decryption_thoroughly_checked = false; bool AddDescriptorKeyWithDB(WalletBatch &batch, const CKey &key, const CPubKey &pubkey); KeyMap GetKeys() const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man); // Fetch the SigningProvider for the given script and optionally include // private keys std::unique_ptr<FlatSigningProvider> GetSigningProvider(const CScript &script, bool include_private = false) const; // Fetch the SigningProvider for the given pubkey and always include private // keys. This should only be called by signing code. std::unique_ptr<FlatSigningProvider> GetSigningProvider(const CPubKey &pubkey) const; // Fetch the SigningProvider for a given index and optionally include // private keys. Called by the above functions. std::unique_ptr<FlatSigningProvider> GetSigningProvider(int32_t index, bool include_private = false) const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man); public: DescriptorScriptPubKeyMan(WalletStorage &storage, WalletDescriptor &descriptor) : ScriptPubKeyMan(storage), m_wallet_descriptor(descriptor) {} DescriptorScriptPubKeyMan(WalletStorage &storage, OutputType address_type, bool internal) : ScriptPubKeyMan(storage), m_address_type(address_type), m_internal(internal) {} mutable RecursiveMutex cs_desc_man; bool GetNewDestination(const OutputType type, CTxDestination &dest, std::string &error) override; isminetype IsMine(const CScript &script) const override; bool CheckDecryptionKey(const CKeyingMaterial &master_key, bool accept_no_keys = false) override; bool Encrypt(const CKeyingMaterial &master_key, WalletBatch *batch) override; bool GetReservedDestination(const OutputType type, bool internal, CTxDestination &address, int64_t &index, CKeyPool &keypool) override; void ReturnDestination(int64_t index, bool internal, const CTxDestination &addr) override; // Tops up the descriptor cache and m_map_script_pub_keys. The cache is // stored in the wallet file and is used to expand the descriptor in // GetNewDestination. DescriptorScriptPubKeyMan relies more on ephemeral // data than LegacyScriptPubKeyMan. For wallets using unhardened derivation // (with or without private keys), the "keypool" is a single xpub. bool TopUp(unsigned int size = 0) override; void MarkUnusedAddresses(const CScript &script) override; bool IsHDEnabled() const override; //! Setup descriptors based on the given CExtkey bool SetupDescriptorGeneration(const CExtKey &master_key); bool HavePrivateKeys() const override; int64_t GetOldestKeyPoolTime() const override; size_t KeypoolCountExternalKeys() const override; unsigned int GetKeyPoolSize() const override; int64_t GetTimeFirstKey() const override; std::unique_ptr<CKeyMetadata> GetMetadata(const CTxDestination &dest) const override; bool CanGetAddresses(bool internal = false) const override; std::unique_ptr<SigningProvider> GetSolvingProvider(const CScript &script) const override; bool CanProvide(const CScript &script, SignatureData &sigdata) override; bool SignTransaction(CMutableTransaction &tx, const std::map<COutPoint, Coin> &coins, SigHashType sighash, std::map<int, std::string> &input_errors) const override; SigningResult SignMessage(const std::string &message, const PKHash &pkhash, std::string &str_sig) const override; TransactionError FillPSBT(PartiallySignedTransaction &psbt, SigHashType sighash_type = SigHashType().withForkId(), bool sign = true, bool bip32derivs = false) const override; uint256 GetID() const override; void SetType(OutputType type, bool internal) override; void SetCache(const DescriptorCache &cache); bool AddKey(const CKeyID &key_id, const CKey &key); bool AddCryptedKey(const CKeyID &key_id, const CPubKey &pubkey, const std::vector<uint8_t> &crypted_key); bool HasWalletDescriptor(const WalletDescriptor &desc) const; void AddDescriptorKey(const CKey &key, const CPubKey &pubkey); void WriteDescriptor(); const WalletDescriptor GetWalletDescriptor() const EXCLUSIVE_LOCKS_REQUIRED(cs_desc_man); const std::vector<CScript> GetScriptPubKeys() const; }; #endif // BITCOIN_WALLET_SCRIPTPUBKEYMAN_H diff --git a/src/wallet/walletutil.h b/src/wallet/walletutil.h index 7d31fc224..b1c81f743 100644 --- a/src/wallet/walletutil.h +++ b/src/wallet/walletutil.h @@ -1,142 +1,144 @@ // Copyright (c) 2017 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_WALLET_WALLETUTIL_H #define BITCOIN_WALLET_WALLETUTIL_H #include <fs.h> #include <script/descriptor.h> #include <vector> /** (client) version numbers for particular wallet features */ enum WalletFeature { // the earliest version new wallets supports (only useful for // getwalletinfo's clientversion output) FEATURE_BASE = 10500, // wallet encryption FEATURE_WALLETCRYPT = 40000, // compressed public keys FEATURE_COMPRPUBKEY = 60000, // Hierarchical key derivation after BIP32 (HD Wallet) FEATURE_HD = 130000, // Wallet with HD chain split (change outputs will use m/0'/1'/k) FEATURE_HD_SPLIT = 160300, // Wallet without a default key written FEATURE_NO_DEFAULT_KEY = 190700, // Upgraded to HD SPLIT and can have a pre-split keypool FEATURE_PRE_SPLIT_KEYPOOL = 200300, FEATURE_LATEST = FEATURE_PRE_SPLIT_KEYPOOL, }; enum WalletFlags : uint64_t { // Wallet flags in the upper section (> 1 << 31) will lead to not opening // the wallet if flag is unknown. // Unknown wallet flags in the lower section <= (1 << 31) will be tolerated. // will categorize coins as clean (not reused) and dirty (reused), and // handle // them with privacy considerations in mind WALLET_FLAG_AVOID_REUSE = (1ULL << 0), // Indicates that the metadata has already been upgraded to contain key // origins WALLET_FLAG_KEY_ORIGIN_METADATA = (1ULL << 1), // Will enforce the rule that the wallet can't contain any private keys // (only watch-only/pubkeys). WALLET_FLAG_DISABLE_PRIVATE_KEYS = (1ULL << 32), //! Flag set when a wallet contains no HD seed and no private keys, scripts, //! addresses, and other watch only things, and is therefore "blank." //! //! The only function this flag serves is to distinguish a blank wallet from //! a newly created wallet when the wallet database is loaded, to avoid //! initialization that should only happen on first run. //! //! This flag is also a mandatory flag to prevent previous versions of //! bitcoin from opening the wallet, thinking it was newly created, and //! then improperly reinitializing it. WALLET_FLAG_BLANK_WALLET = (1ULL << 33), //! Indicate that this wallet supports DescriptorScriptPubKeyMan WALLET_FLAG_DESCRIPTORS = (1ULL << 34), }; //! Get the path of the wallet directory. fs::path GetWalletDir(); //! Get wallets in wallet directory. std::vector<fs::path> ListWalletDir(); //! The WalletLocation class provides wallet information. class WalletLocation final { std::string m_name; fs::path m_path; public: explicit WalletLocation() {} explicit WalletLocation(const std::string &name); //! Get wallet name. const std::string &GetName() const { return m_name; } //! Get wallet absolute path. const fs::path &GetPath() const { return m_path; } //! Return whether the wallet exists. bool Exists() const; }; /** Descriptor with some wallet metadata */ class WalletDescriptor { public: std::shared_ptr<Descriptor> descriptor; - uint64_t creation_time; - int32_t range_start; // First item in range; start of range, inclusive, i.e. - // [range_start, range_end). This never changes. - int32_t range_end; // Item after the last; end of range, exclusive, i.e. - // [range_start, range_end). This will increment with - // each TopUp() - int32_t next_index; // Position of the next item to generate + uint64_t creation_time = 0; + // First item in range; start of range, inclusive, i.e. + // [range_start, range_end). This never changes. + int32_t range_start = 0; + // Item after the last; end of range, exclusive, i.e. + // [range_start, range_end). This will increment with each TopUp() + int32_t range_end = 0; + // Position of the next item to generate + int32_t next_index = 0; DescriptorCache cache; ADD_SERIALIZE_METHODS; template <typename Stream, typename Operation> inline void SerializationOp(Stream &s, Operation ser_action) { if (ser_action.ForRead()) { std::string desc; std::string error; READWRITE(desc); FlatSigningProvider keys; descriptor = Parse(desc, keys, error, true); if (!descriptor) { throw std::ios_base::failure("Invalid descriptor: " + error); } } else { READWRITE(descriptor->ToString()); } READWRITE(creation_time); READWRITE(next_index); READWRITE(range_start); READWRITE(range_end); } WalletDescriptor() {} WalletDescriptor(std::shared_ptr<Descriptor> descriptor_, uint64_t creation_time_, int32_t range_start_, int32_t range_end_, int32_t next_index_) : descriptor(descriptor_), creation_time(creation_time_), range_start(range_start_), range_end(range_end_), next_index(next_index_) {} }; #endif // BITCOIN_WALLET_WALLETUTIL_H