diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 717377e10f..00ed39c33b 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3617,34 +3617,31 @@ UniValue getaddressinfo(const JSONRPCRequest& request) ret.pushKV("label", pwallet->mapAddressBook[dest].name); } ret.pushKV("ischange", pwallet->IsChange(scriptPubKey)); - const CKeyMetadata* meta = nullptr; - const CKeyID *key_id = boost::get(&dest); - if (key_id != nullptr && !key_id->IsNull()) { - auto it = pwallet->mapKeyMetadata.find(*key_id); - if (it != pwallet->mapKeyMetadata.end()) { - meta = &it->second; + ScriptPubKeyMan* spk_man = pwallet->GetScriptPubKeyMan(); + if (spk_man) { + const CKeyID *key_id = boost::get(&dest); + const CKeyMetadata* meta = nullptr; + if (key_id != nullptr && !key_id->IsNull()) { + meta = spk_man->GetMetadata(*key_id); } - } - if (!meta) { - auto it = pwallet->m_script_metadata.find(CScriptID(scriptPubKey)); - if (it != pwallet->m_script_metadata.end()) { - meta = &it->second; + if (!meta) { + meta = spk_man->GetMetadata(CScriptID(scriptPubKey)); } - } - if (meta) { - ret.pushKV("timestamp", meta->nCreateTime); - CHDChain hdChainCurrent; - LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan(); - if (spk_man != nullptr) { - LOCK(pwallet->cs_KeyStore); - AssertLockHeld(spk_man->cs_KeyStore); - if (key_id && pwallet->mapHdPubKeys.count(*key_id) && spk_man->GetHDChain(hdChainCurrent)) { - ret.pushKV("hdchainid", hdChainCurrent.GetID().GetHex()); + if (meta) { + ret.pushKV("timestamp", meta->nCreateTime); + CHDChain hdChainCurrent; + LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan(); + if (spk_man != nullptr) { + LOCK(pwallet->cs_KeyStore); + AssertLockHeld(spk_man->cs_KeyStore); + if (key_id && pwallet->mapHdPubKeys.count(*key_id) && spk_man->GetHDChain(hdChainCurrent)) { + ret.pushKV("hdchainid", hdChainCurrent.GetID().GetHex()); + } + } + if (meta->has_key_origin) { + ret.pushKV("hdkeypath", WriteHDKeypath(meta->key_origin.path)); + ret.pushKV("hdmasterfingerprint", HexStr(meta->key_origin.fingerprint)); } - } - if (meta->has_key_origin) { - ret.pushKV("hdkeypath", WriteHDKeypath(meta->key_origin.path)); - ret.pushKV("hdmasterfingerprint", HexStr(meta->key_origin.fingerprint)); } } diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index 2f4e21e45d..f91e793c2a 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -12,9 +12,8 @@ #include #include -bool LegacyScriptPubKeyMan::GetNewDestination(const std::string label, CTxDestination& dest, std::string& error) +bool LegacyScriptPubKeyMan::GetNewDestination(CTxDestination& dest, std::string& error) { - LOCK(cs_wallet); error.clear(); TopUpKeyPool(); @@ -26,8 +25,6 @@ bool LegacyScriptPubKeyMan::GetNewDestination(const std::string label, CTxDestin } //LearnRelatedScripts(new_key); dest = new_key.GetID(); - - m_wallet.SetAddressBook(dest, label, "receive"); return true; } @@ -266,6 +263,62 @@ bool LegacyScriptPubKeyMan::EncryptKeys(CKeyingMaterial& vMasterKeyIn) return true; } +bool LegacyScriptPubKeyMan::GetReservedDestination(bool internal, int64_t& index, CKeyPool& keypool) +{ + { + if (!ReserveKeyFromKeyPool(index, keypool, internal)) { + return false; + } + } + return true; +} + +void LegacyScriptPubKeyMan::KeepDestination(int64_t index) +{ + KeepKey(index); +} + +void LegacyScriptPubKeyMan::ReturnDestination(int64_t index, bool internal, const CPubKey& pubkey) +{ + ReturnKey(index, internal, pubkey); +} + +bool LegacyScriptPubKeyMan::TopUp(unsigned int size) +{ + return TopUpKeyPool(size); +} + +void LegacyScriptPubKeyMan::MarkUnusedAddresses(WalletBatch &batch, const CScript& script, const uint256& hashBlock) +{ + AssertLockHeld(cs_wallet); + // extract addresses and check if they match with an unused keypool key + for (const auto& keyid : GetAffectedKeys(script, *this)) { + std::map::const_iterator mi = m_pool_key_to_index.find(keyid); + if (mi != m_pool_key_to_index.end()) { + WalletLogPrintf("%s: Detected a used keypool key, mark all keypool key up to this key as used\n", __func__); + MarkReserveKeysAsUsed(mi->second); + + if (!TopUpKeyPool()) { + WalletLogPrintf("%s: Topping up keypool failed (locked wallet)\n", __func__); + } + } + if (!hashBlock.IsNull()) { + int64_t block_time; + bool found_block = m_wallet.chain().findBlock(hashBlock, nullptr /* block */, &block_time); + assert(found_block); + if (mapKeyMetadata[keyid].nCreateTime > block_time) { + WalletLogPrintf("%s: Found a key which appears to be used earlier than we expected, updating metadata\n", __func__); + CPubKey vchPubKey; + bool res = GetPubKey(keyid, vchPubKey); + assert(res); // this should never fail + mapKeyMetadata[keyid].nCreateTime = block_time; + batch.WriteKeyMetadata(mapKeyMetadata[keyid], vchPubKey, true); + UpdateTimeFirstKey(block_time); + } + } + } +} + void LegacyScriptPubKeyMan::UpgradeKeyMetadata() { AssertLockHeld(cs_wallet); // mapKeyMetadata @@ -314,8 +367,6 @@ void LegacyScriptPubKeyMan::UpgradeKeyMetadata() } } } - batch.reset(); //write before setting the flag - m_storage.SetWalletFlag(WALLET_FLAG_KEY_ORIGIN_METADATA); } void LegacyScriptPubKeyMan::GenerateNewHDChain(const SecureString& secureMnemonic, const SecureString& secureMnemonicPassphrase) @@ -421,7 +472,7 @@ bool LegacyScriptPubKeyMan::SetHDChain(WalletBatch &batch, const CHDChain& chain throw std::runtime_error(std::string(__func__) + ": WriteHDChain failed"); } - m_wallet.UnsetWalletFlag(batch, WALLET_FLAG_BLANK_WALLET); + m_storage.UnsetBlankWalletFlag(batch); } return true; @@ -442,7 +493,7 @@ bool LegacyScriptPubKeyMan::SetCryptedHDChain(WalletBatch &batch, const CHDChain if (!batch.WriteCryptedHDChain(chain)) throw std::runtime_error(std::string(__func__) + ": WriteCryptedHDChain failed"); } - m_wallet.UnsetWalletFlag(batch, WALLET_FLAG_BLANK_WALLET); + m_storage.UnsetBlankWalletFlag(batch); } return true; @@ -615,7 +666,30 @@ bool LegacyScriptPubKeyMan::CanGetAddresses(bool internal) return keypool_has_keys; } -static int64_t GetOldestKeyInPool(const std::set& setKeyPool, WalletBatch& batch) { + +bool LegacyScriptPubKeyMan::HavePrivateKeys() const +{ + LOCK(cs_KeyStore); + return !mapKeys.empty() || !mapCryptedKeys.empty(); +} + +void LegacyScriptPubKeyMan::RewriteDB() +{ + AssertLockHeld(cs_wallet); + setInternalKeyPool.clear(); + setExternalKeyPool.clear(); + m_pool_key_to_index.clear(); + // Note: can't top-up keypool here, because wallet is locked. + // User will be prompted to unlock wallet the next operation + // that requires a new key. +} + +static int64_t GetOldestKeyTimeInPool(const std::set& setKeyPool, WalletBatch& batch) { + if (setKeyPool.empty()) { + // if the keypool is empty, return + return GetTime(); + } + CKeyPool keypool; int64_t nIndex = *(setKeyPool.begin()); if (!batch.ReadPool(nIndex, keypool)) { @@ -629,19 +703,11 @@ int64_t LegacyScriptPubKeyMan::GetOldestKeyPoolTime() { LOCK(cs_wallet); - // if the keypool is empty, return - if (setExternalKeyPool.empty() && setInternalKeyPool.empty()) - return GetTime(); - WalletBatch batch(m_storage.GetDatabase()); - int64_t oldestKey = -1; + int64_t oldestKey = GetOldestKeyTimeInPool(setExternalKeyPool, batch); - // load oldest key from keypool, get time and return - if (!setInternalKeyPool.empty()) { - oldestKey = std::max(GetOldestKeyInPool(setInternalKeyPool, batch), oldestKey); - } - if (!setExternalKeyPool.empty()) { - oldestKey = std::max(GetOldestKeyInPool(setExternalKeyPool, batch), oldestKey); + if (IsHDEnabled()) { + oldestKey = std::max(GetOldestKeyTimeInPool(setInternalKeyPool, batch), oldestKey); } return oldestKey; } @@ -658,6 +724,33 @@ size_t LegacyScriptPubKeyMan::KeypoolCountInternalKeys() return setInternalKeyPool.size(); } +unsigned int LegacyScriptPubKeyMan::GetKeyPoolSize() const +{ + AssertLockHeld(cs_wallet); + return setInternalKeyPool.size() + setExternalKeyPool.size(); +} + +int64_t LegacyScriptPubKeyMan::GetTimeFirstKey() const +{ + AssertLockHeld(cs_wallet); + return nTimeFirstKey; +} + +const CKeyMetadata* LegacyScriptPubKeyMan::GetMetadata(uint160 id) const +{ + AssertLockHeld(cs_wallet); + auto it = mapKeyMetadata.find(CKeyID(id)); + if (it != mapKeyMetadata.end()) { + return &it->second; + } else { + auto it2 = m_script_metadata.find(CScriptID(id)); + if (it2 != m_script_metadata.end()) { + return &it2->second; + } + } + return nullptr; +} + /** * Update wallet first key creation time. This should be called whenever keys * are added to the wallet, with the oldest key creation time. @@ -674,10 +767,9 @@ void LegacyScriptPubKeyMan::UpdateTimeFirstKey(int64_t nCreateTime) } } -int64_t LegacyScriptPubKeyMan::GetTimeFirstKey() const +bool LegacyScriptPubKeyMan::LoadKey(const CKey& key, const CPubKey &pubkey) { - AssertLockHeld(cs_wallet); - return nTimeFirstKey; + return AddKeyPubKeyInner(key, pubkey); } bool LegacyScriptPubKeyMan::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey) @@ -722,7 +814,7 @@ bool LegacyScriptPubKeyMan::AddKeyPubKeyWithDB(WalletBatch& batch, const CKey& s secret.GetPrivKey(), mapKeyMetadata[pubkey.GetID()]); } - m_wallet.UnsetWalletFlag(batch, WALLET_FLAG_BLANK_WALLET); + m_storage.UnsetBlankWalletFlag(batch); return true; } @@ -932,7 +1024,7 @@ bool LegacyScriptPubKeyMan::AddWatchOnlyWithDB(WalletBatch &batch, const CScript UpdateTimeFirstKey(meta.nCreateTime); NotifyWatchonlyChanged(true); if (batch.WriteWatchOnly(dest, meta)) { - m_wallet.UnsetWalletFlag(batch, WALLET_FLAG_BLANK_WALLET); + m_storage.UnsetBlankWalletFlag(batch); return true; } return false; @@ -1015,7 +1107,7 @@ bool LegacyScriptPubKeyMan::AddHDPubKey(WalletBatch &batch, const CExtPubKey &ex if (!batch.WriteHDPubKey(hdPubKey, mapKeyMetadata[extPubKey.pubkey.GetID()])) { return false; } - m_wallet.UnsetWalletFlag(batch, WALLET_FLAG_BLANK_WALLET); + m_storage.UnsetBlankWalletFlag(batch); return true; } @@ -1331,12 +1423,14 @@ bool LegacyScriptPubKeyMan::TopUpKeyPool(unsigned int kpSize) return true; } +/* void LegacyScriptPubKeyMan::AddKeypoolPubkey(const CPubKey& pubkey, const bool internal) { WalletBatch batch(m_storage.GetDatabase()); AddKeypoolPubkeyWithDB(pubkey, internal, batch); NotifyCanGetAddressesChanged(); } +*/ void LegacyScriptPubKeyMan::AddKeypoolPubkeyWithDB(const CPubKey& pubkey, const bool internal, WalletBatch& batch) { @@ -1496,7 +1590,7 @@ bool LegacyScriptPubKeyMan::AddCScriptWithDB(WalletBatch& batch, const CScript& if (!FillableSigningProvider::AddCScript(redeemScript)) return false; if (batch.WriteCScript(Hash160(redeemScript), redeemScript)) { - m_wallet.UnsetWalletFlag(batch, WALLET_FLAG_BLANK_WALLET); + m_storage.UnsetBlankWalletFlag(batch); return true; } return false; @@ -1580,7 +1674,7 @@ bool LegacyScriptPubKeyMan::ImportPubKeys(const std::vector& ordered_pub return true; } -bool LegacyScriptPubKeyMan::ImportScriptPubKeys(const std::string& label, const std::set& script_pub_keys, const bool have_solving_data, const bool apply_label, const int64_t timestamp) +bool LegacyScriptPubKeyMan::ImportScriptPubKeys(const std::set& script_pub_keys, const bool have_solving_data, const int64_t timestamp) { WalletBatch batch(m_storage.GetDatabase()); for (const CScript& script : script_pub_keys) { @@ -1589,11 +1683,6 @@ bool LegacyScriptPubKeyMan::ImportScriptPubKeys(const std::string& label, const return false; } } - CTxDestination dest; - ExtractDestination(script, dest); - if (apply_label && IsValidDestination(dest)) { - m_wallet.SetAddressBookWithDB(batch, dest, label, "receive"); - } } return true; } diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h index 7e3255c434..359f8a2b2b 100644 --- a/src/wallet/scriptpubkeyman.h +++ b/src/wallet/scriptpubkeyman.h @@ -26,7 +26,7 @@ public: virtual const std::string GetDisplayName() const = 0; virtual WalletDatabase& GetDatabase() = 0; virtual bool IsWalletFlagSet(uint64_t) const = 0; - virtual void SetWalletFlag(uint64_t) = 0; + virtual void UnsetBlankWalletFlag(WalletBatch&) = 0; virtual bool CanSupportFeature(enum WalletFeature) const = 0; virtual void SetMinVersion(enum WalletFeature, WalletBatch* = nullptr, bool = false) = 0; virtual bool IsLocked(bool fForMixing = false) const = 0; @@ -35,6 +35,8 @@ public: //! Default for -keypool static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000; +std::vector GetAffectedKeys(const CScript& spk, const SigningProvider& provider); + /** A key from a CWallet's keypool * * The wallet holds several keypools. These are sets of keys that have not @@ -132,31 +134,86 @@ protected: public: ScriptPubKeyMan(WalletStorage& storage) : m_storage(storage) {} + + virtual ~ScriptPubKeyMan() {}; + virtual bool GetNewDestination(CTxDestination& dest, std::string& error) { return false; } + virtual isminetype IsMine(const CScript& script) const { return ISMINE_NO; } + virtual isminetype IsMine(const CTxDestination& dest) const { return ISMINE_NO; } + + virtual bool GetReservedDestination(bool internal, int64_t& index, CKeyPool& keypool) { return false; } + virtual void KeepDestination(int64_t index) {} + virtual void ReturnDestination(int64_t index, bool internal, const CPubKey& pubkey) {} + + virtual bool TopUp(unsigned int size = 0) { return false; } + + //! Mark unused addresses as being used + virtual void MarkUnusedAddresses(WalletBatch &batch, const CScript& script, const uint256& hashBlock) {} + + /* 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) { return false; } + + virtual bool HavePrivateKeys() const { return false; } + + //! The action to do when the DB needs rewrite + virtual void RewriteDB() {} + + virtual int64_t GetOldestKeyPoolTime() { return GetTime(); } + + virtual size_t KeypoolCountExternalKeys() { return 0; } + virtual size_t KeypoolCountInternalKeys() { return 0; } + virtual unsigned int GetKeyPoolSize() const { return 0; } + + virtual int64_t GetTimeFirstKey() const { return 0; } + + virtual const CKeyMetadata* GetMetadata(uint160 id) const { return nullptr; } }; class LegacyScriptPubKeyMan : public ScriptPubKeyMan, public FillableSigningProvider { private: - using CryptedKeyMap = std::map>>; using WatchOnlySet = std::set; using WatchKeyMap = std::map; using HDPubKeyMap = std::map; - //! will encrypt previously unencrypted keys - bool EncryptKeys(CKeyingMaterial& vMasterKeyIn); + + WalletBatch *encrypted_batch GUARDED_BY(cs_wallet) = nullptr; + + using CryptedKeyMap = std::map>>; CryptedKeyMap mapCryptedKeys GUARDED_BY(cs_KeyStore); WatchOnlySet setWatchOnly GUARDED_BY(cs_KeyStore); WatchKeyMap mapWatchKeys GUARDED_BY(cs_KeyStore); HDPubKeyMap mapHdPubKeys GUARDED_BY(cs_KeyStore); // &vchCryptedSecret); bool AddKeyPubKeyInner(const CKey& key, const CPubKey &pubkey); + bool AddCryptedKeyInner(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret); bool GetKeyInner(const CKeyID &address, CKey& keyOut) const; bool GetPubKeyInner(const CKeyID &address, CPubKey& vchPubKeyOut) const; - WalletBatch *encrypted_batch GUARDED_BY(cs_wallet) = nullptr; + /** + * 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_wallet); + bool AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + bool AddWatchOnlyInMem(const CScript &dest); + + + void AddKeypoolPubkeyWithDB(const CPubKey& pubkey, const bool internal, WalletBatch& batch); + + /** 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 GUARDED_BY(cs_KeyStore); @@ -170,105 +227,8 @@ private: int64_t m_max_keypool_index GUARDED_BY(cs_wallet) = 0; std::map m_pool_key_to_index; - int64_t nTimeFirstKey GUARDED_BY(cs_wallet) = 0; - - /** - * 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_wallet); - bool AddWatchOnlyInMem(const CScript &dest); - - /** Add a KeyOriginInfo to the wallet */ - bool AddKeyOriginWithDB(WalletBatch& batch, const CPubKey& pubkey, const KeyOriginInfo& info); - - void AddKeypoolPubkeyWithDB(const CPubKey& pubkey, const bool internal, WalletBatch& batch); - -public: - //! 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_wallet); - - //! 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_wallet); - - //! Adds a script to the store and saves it to disk - bool AddCScriptWithDB(WalletBatch& batch, const CScript& script); - - public: - void LoadKeyPool(int64_t nIndex, const CKeyPool &keypool) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - - // Map from Key ID to key metadata. - std::map mapKeyMetadata GUARDED_BY(cs_wallet); - - // Map from Script ID to key metadata (for watch-only keys). - std::map m_script_metadata GUARDED_BY(cs_wallet); - - bool WriteKeyMetadata(const CKeyMetadata& meta, const CPubKey& pubkey, bool overwrite); - - /** - * keystore implementation - * Generate a new key - */ - CPubKey GenerateNewKey(WalletBatch& batch, uint32_t nAccountIndex, bool fInternal /*= false*/) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - //! Adds a key to the store, and saves it to disk. - bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - //! Adds a key to the store, without saving it to disk (used by LoadWallet) - bool LoadKey(const CKey& key, const CPubKey &pubkey) { return AddKeyPubKeyInner(key, pubkey); } - //! Load metadata (used by LoadWallet) - void LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata &metadata) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - void LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata &metadata) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - //! Upgrade stored CKeyMetadata objects to store key origin info as KeyOriginInfo - void UpgradeKeyMetadata() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - void UpdateTimeFirstKey(int64_t nCreateTime) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - int64_t GetTimeFirstKey() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - - //! Adds an encrypted key to the store, and saves it to disk. - bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret); - //! Adds an encrypted key to the store, without saving it to disk (used by LoadWallet) - bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret); - //! GetKey implementation that can derive a HD private key on the fly - bool GetKey(const CKeyID &address, CKey& keyOut) const override; - //! GetPubKey implementation that also checks the mapHdPubKeys - bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override; - //! HaveKey implementation that also checks the mapHdPubKeys - bool HaveKey(const CKeyID &address) const override; - //! Adds a HDPubKey into the wallet(database) - bool AddHDPubKey(WalletBatch &batch, const CExtPubKey &extPubKey, bool fInternal); - //! loads a HDPubKey into the wallets memory - bool LoadHDPubKey(const CHDPubKey &hdPubKey) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - std::set GetKeys() const override; - bool AddCScript(const CScript& redeemScript) override; - bool LoadCScript(const CScript& redeemScript); - - //! Adds a watch-only address to the store, and saves it to disk. - bool AddWatchOnly(const CScript& dest, int64_t nCreateTime) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - bool AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - bool RemoveWatchOnly(const CScript &dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - //! 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; - //! Fetches a pubkey from mapWatchKeys if it exists there - bool GetWatchPubKey(const CKeyID &address, CPubKey &pubkey_out) const; - - bool ImportScripts(const std::set scripts, int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - bool ImportPrivKeys(const std::map& privkey_map, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - bool ImportPubKeys(const std::vector& ordered_pubkeys, const std::map& pubkey_map, const std::map>& key_origins, const bool add_keypool, const bool internal, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - bool ImportScriptPubKeys(const std::string& label, const std::set& script_pub_keys, const bool have_solving_data, const bool apply_label, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - - bool NewKeyPool(); - size_t KeypoolCountExternalKeys() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - size_t KeypoolCountInternalKeys() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - bool TopUpKeyPool(unsigned int kpSize = 0); - void AddKeypoolPubkey(const CPubKey& pubkey, const bool internal); - + //! Fetches a key from the keypool + bool GetKeyFromPool(CPubKey &key, bool fInternal /*= false*/); /** * Reserves a key from the keypool and sets nIndex to its index * @@ -284,19 +244,136 @@ public: * or external keypool */ bool ReserveKeyFromKeyPool(int64_t& nIndex, CKeyPool& keypool, bool fRequestedInternal); + void KeepKey(int64_t nIndex); void ReturnKey(int64_t nIndex, bool fInternal, const CPubKey& pubkey); - //! Fetches a key from the keypool - bool GetKeyFromPool(CPubKey &key, bool internal /* = false */); - int64_t GetOldestKeyPoolTime(); +public: + bool GetNewDestination(CTxDestination& dest, std::string& error) override; + isminetype IsMine(const CScript& script) const override; + isminetype IsMine(const CTxDestination& dest) const override; + + //! will encrypt previously unencrypted keys + bool EncryptKeys(CKeyingMaterial& vMasterKeyIn); + + bool GetReservedDestination(bool internal, int64_t& index, CKeyPool& keypool) override; + void KeepDestination(int64_t index) override; + void ReturnDestination(int64_t index, bool internal, const CPubKey& pubkey) override; + + bool TopUp(unsigned int size = 0) override; + + void MarkUnusedAddresses(WalletBatch &batch, const CScript& script, const uint256& hashBlock) override; + + //! Upgrade stored CKeyMetadata objects to store key origin info as KeyOriginInfo + void UpgradeKeyMetadata() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + + /* Returns true if HD is enabled */ + bool IsHDEnabled() const override; + + bool HavePrivateKeys() const override; + + void RewriteDB() override; + + int64_t GetOldestKeyPoolTime() override; + size_t KeypoolCountExternalKeys() override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + size_t KeypoolCountInternalKeys() override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + + unsigned int GetKeyPoolSize() const override; + + int64_t GetTimeFirstKey() const override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + + const CKeyMetadata* GetMetadata(uint160 id) const override; + + bool CanGetAddresses(bool internal = false) override; + + // Map from Key ID to key metadata. + std::map mapKeyMetadata GUARDED_BY(cs_wallet); + + // Map from Script ID to key metadata (for watch-only keys). + std::map m_script_metadata GUARDED_BY(cs_wallet); + + //! Adds a script to the store and saves it to disk + bool AddCScriptWithDB(WalletBatch& batch, const CScript& script); + + //! 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_wallet); + + //! Adds a key to the store, and saves it to disk. + bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + //! 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 &vchCryptedSecret); + //! Adds an encrypted key to the store, without saving it to disk (used by LoadWallet) + bool LoadCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret); + void UpdateTimeFirstKey(int64_t nCreateTime) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + //! Adds a CScript to the store + bool LoadCScript(const CScript& redeemScript); + //! Load metadata (used by LoadWallet) + void LoadKeyMetadata(const CKeyID& keyID, const CKeyMetadata &metadata) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + bool WriteKeyMetadata(const CKeyMetadata& meta, const CPubKey& pubkey, bool overwrite); + void LoadScriptMetadata(const CScriptID& script_id, const CKeyMetadata &metadata) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + //! Generate a new key + CPubKey GenerateNewKey(WalletBatch& batch, uint32_t nAccountIndex, bool fInternal /*= false*/) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + + /* Set the HD chain model (chain child index counters) */ + bool SetHDChain(WalletBatch &batch, const CHDChain& chain, bool memonly); + bool SetCryptedHDChain(WalletBatch &batch, const CHDChain& chain, bool memonly); /** - * Marks all keys in the keypool up to and including reserve_key as used. + * Set the HD chain model (chain child index counters) using temporary wallet db object + * which causes db flush every time these methods are used */ - void MarkReserveKeysAsUsed(int64_t keypool_id) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + bool SetHDChainSingle(const CHDChain& chain, bool memonly); + bool SetCryptedHDChainSingle(const CHDChain& chain, bool memonly); - isminetype IsMine(const CScript& script) const; - isminetype IsMine(const CTxDestination& dest) const; + //! 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) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + //! Adds a watch-only address to the store, and saves it to disk. + bool AddWatchOnly(const CScript& dest, int64_t nCreateTime) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + //! 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_wallet); + + //! Fetches a pubkey from mapWatchKeys if it exists there + bool GetWatchPubKey(const CKeyID &address, CPubKey &pubkey_out) const; + + /* SigningProvider overrides */ + //! HaveKey implementation that also checks the mapHdPubKeys + bool HaveKey(const CKeyID &address) const override; + //! GetKey implementation that can derive a HD private key on the fly + bool GetKey(const CKeyID &address, CKey& keyOut) const override; + //! GetPubKey implementation that also checks the mapHdPubKeys + bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override; + bool AddCScript(const CScript& redeemScript) override; + /** Implement lookup of key origin information through wallet key metadata. */ + bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override; + /** Add a KeyOriginInfo to the wallet */ + bool AddKeyOrigin(const CPubKey& pubkey, const KeyOriginInfo& info); + + void LoadKeyPool(int64_t nIndex, const CKeyPool &keypool) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + bool TopUpKeyPool(unsigned int kpSize = 0); + bool NewKeyPool(); + // Seems as not used now anywhere in code + // void AddKeypoolPubkey(const CPubKey& pubkey, const bool internal); + + bool ImportScripts(const std::set scripts, int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + + bool ImportPrivKeys(const std::map& privkey_map, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + bool ImportPubKeys(const std::vector& ordered_pubkeys, const std::map& pubkey_map, const std::map>& key_origins, const bool add_keypool, const bool internal, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + bool ImportScriptPubKeys(const std::set& script_pub_keys, const bool have_solving_data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + + /* Returns true if the wallet can generate new keys */ + bool CanGenerateKeys(); + + //! Adds a HDPubKey into the wallet(database) + bool AddHDPubKey(WalletBatch &batch, const CExtPubKey &extPubKey, bool fInternal); + //! loads a HDPubKey into the wallets memory + bool LoadHDPubKey(const CHDPubKey &hdPubKey) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); /** * HD Wallet Functions @@ -309,29 +386,10 @@ public: bool SetCryptedHDChain(const CHDChain& chain); bool GetDecryptedHDChain(CHDChain& hdChainRet); - /* Returns true if HD is enabled */ - bool IsHDEnabled() const; - - /* Returns true if the wallet can generate new keys */ - bool CanGenerateKeys(); - - /* Returns true if the wallet can give out new addresses. This means it has keys in the keypool or can generate new keys */ - bool CanGetAddresses(bool internal = false); - /* Generates a new HD chain */ void GenerateNewHDChain(const SecureString& secureMnemonic, const SecureString& secureMnemonicPassphrase); bool GenerateNewHDChainEncrypted(const SecureString& secureMnemonic, const SecureString& secureMnemonicPassphrase, const SecureString& secureWalletPassphrase); - /* Set the HD chain model (chain child index counters) */ - bool SetHDChain(WalletBatch &batch, const CHDChain& chain, bool memonly); - bool SetCryptedHDChain(WalletBatch &batch, const CHDChain& chain, bool memonly); - /** - * Set the HD chain model (chain child index counters) using temporary wallet db object - * which causes db flush every time these methods are used - */ - bool SetHDChainSingle(const CHDChain& chain, bool memonly); - bool SetCryptedHDChainSingle(const CHDChain& chain, bool memonly); - /** * 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 @@ -346,13 +404,13 @@ public: */ // void LearnAllRelatedScripts(const CPubKey& key); - /** Implement lookup of key origin information through wallet key metadata. */ - bool GetKeyOrigin(const CKeyID& keyid, KeyOriginInfo& info) const override; + /** + * Marks all keys in the keypool up to and including reserve_key as used. + */ + void MarkReserveKeysAsUsed(int64_t keypool_id) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); const std::map& GetAllReserveKeys() const { return m_pool_key_to_index; } - bool GetNewDestination(const std::string label, CTxDestination& dest, std::string& error); - /** Add a KeyOriginInfo to the wallet */ - bool AddKeyOrigin(const CPubKey& pubkey, const KeyOriginInfo& info); + std::set GetKeys() const override; // Temporary CWallet accessors and aliases. friend class CWallet; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index c2601a7292..ccfdc70b4f 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -337,8 +337,6 @@ std::string COutput::ToString() const return strprintf("COutput(%s, %d, %d) [%s]", tx->GetHash().ToString(), i, nDepth, FormatMoney(tx->tx->vout[i].nValue)); } -std::vector GetAffectedKeys(const CScript& spk, const SigningProvider& provider); - const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const { LOCK(cs_wallet); @@ -350,10 +348,15 @@ const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const void CWallet::UpgradeKeyMetadata() { + if (IsLocked() || IsWalletFlagSet(WALLET_FLAG_KEY_ORIGIN_METADATA)) { + return; + } + if (m_spk_man) { AssertLockHeld(m_spk_man->cs_wallet); m_spk_man->UpgradeKeyMetadata(); } + SetWalletFlag(WALLET_FLAG_KEY_ORIGIN_METADATA); } bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase) @@ -975,33 +978,8 @@ bool CWallet::AddToWalletIfInvolvingMe(const CTransactionRef& ptx, CWalletTx::Co WalletBatch batch(*database); // loop though all outputs for (const CTxOut& txout: tx.vout) { - // extract addresses, check if they match with an unused keypool key, update metadata if needed - if (m_spk_man == nullptr) continue; - AssertLockHeld(m_spk_man->cs_wallet); - for (const auto& keyid : GetAffectedKeys(txout.scriptPubKey, *m_spk_man)) { - std::map::const_iterator mi = m_spk_man->m_pool_key_to_index.find(keyid); - if (mi != m_spk_man->m_pool_key_to_index.end()) { - WalletLogPrintf("%s: Detected a used keypool key, mark all keypool key up to this key as used\n", __func__); - MarkReserveKeysAsUsed(mi->second); - - if (!m_spk_man->TopUpKeyPool()) { - WalletLogPrintf("%s: Topping up keypool failed (locked wallet)\n", __func__); - } - } - if (!confirm.hashBlock.IsNull()) { - int64_t block_time; - bool found_block = chain().findBlock(confirm.hashBlock, nullptr /* block */, &block_time); - assert(found_block); - if (mapKeyMetadata[keyid].nCreateTime > block_time) { - WalletLogPrintf("%s: Found a key which appears to be used earlier than we expected, updating metadata\n", __func__); - CPubKey vchPubKey; - bool res = m_spk_man->GetPubKey(keyid, vchPubKey); - assert(res); // this should never fail - mapKeyMetadata[keyid].nCreateTime = block_time; - batch.WriteKeyMetadata(mapKeyMetadata[keyid], vchPubKey, true); - m_spk_man->UpdateTimeFirstKey(block_time); - } - } + if (auto spk_man = m_spk_man.get()) { + spk_man->MarkUnusedAddresses(batch, txout.scriptPubKey, confirm.hashBlock); } } @@ -1581,10 +1559,10 @@ void CWallet::UnsetWalletFlag(uint64_t flag) { LOCK(cs_wallet); WalletBatch batch(*database); - UnsetWalletFlag(batch, flag); + UnsetWalletFlagWithDB(batch, flag); } -void CWallet::UnsetWalletFlag(WalletBatch& batch, uint64_t flag) +void CWallet::UnsetWalletFlagWithDB(WalletBatch& batch, uint64_t flag) { LOCK(cs_wallet); m_wallet_flags &= ~flag; @@ -1592,6 +1570,11 @@ void CWallet::UnsetWalletFlag(WalletBatch& batch, uint64_t flag) throw std::runtime_error(std::string(__func__) + ": writing wallet flags failed"); } +void CWallet::UnsetBlankWalletFlag(WalletBatch& batch) +{ + UnsetWalletFlagWithDB(batch, WALLET_FLAG_BLANK_WALLET); +} + bool CWallet::IsWalletFlagSet(uint64_t flag) const { return (m_wallet_flags & flag); @@ -1688,9 +1671,19 @@ bool CWallet::ImportScriptPubKeys(const std::string& label, const std::setcs_wallet); - if (!spk_man->ImportScriptPubKeys(label, script_pub_keys, have_solving_data, apply_label, timestamp)) { + if (!spk_man->ImportScriptPubKeys(script_pub_keys, have_solving_data, timestamp)) { return false; } + if (apply_label) { + WalletBatch batch(*database); + for (const CScript& script : script_pub_keys) { + CTxDestination dest; + ExtractDestination(script, dest); + if (IsValidDestination(dest)) { + SetAddressBookWithDB(batch, dest, label, "receive"); + } + } + } return true; } @@ -3574,13 +3567,10 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet) { if (database->Rewrite("\x04pool")) { - setInternalKeyPool.clear(); - setExternalKeyPool.clear(); + if (auto spk_man = m_spk_man.get()) { + spk_man->RewriteDB(); + } nKeysLeftSinceAutoBackup = 0; - m_spk_man->m_pool_key_to_index.clear(); - // Note: can't top-up keypool here, because wallet is locked. - // User will be prompted to unlock wallet the next operation - // that requires a new key. } } @@ -3645,12 +3635,9 @@ DBErrors CWallet::ZapSelectTx(std::vector& vHashIn, std::vectorRewrite("\x04pool")) { - setInternalKeyPool.clear(); - setExternalKeyPool.clear(); - m_spk_man->m_pool_key_to_index.clear(); - // Note: can't top-up keypool here, because wallet is locked. - // User will be prompted to unlock wallet the next operation - // that requires a new key. + if (auto spk_man = m_spk_man.get()) { + spk_man->RewriteDB(); + } } } @@ -3732,30 +3719,47 @@ size_t CWallet::KeypoolCountInternalKeys() return count; } +unsigned int CWallet::GetKeyPoolSize() const +{ + AssertLockHeld(cs_wallet); + + unsigned int count = 0; + if (auto spk_man = m_spk_man.get()) { + count += spk_man->GetKeyPoolSize(); + } + return count; +} + bool CWallet::TopUpKeyPool(unsigned int kpSize) { bool res = true; if (auto spk_man = m_spk_man.get()) { - res &= spk_man->TopUpKeyPool(kpSize); + res &= spk_man->TopUp(kpSize); } return res; } bool CWallet::GetNewDestination(const std::string label, CTxDestination& dest, std::string& error) { + LOCK(cs_wallet); error.clear(); bool result = false; auto spk_man = m_spk_man.get(); if (spk_man) { - result = spk_man->GetNewDestination(label, dest, error); + result = spk_man->GetNewDestination(dest, error); } + if (result) { + SetAddressBook(dest, label, "receive"); + } + return result; } bool CWallet::GetNewChangeDestination(CTxDestination& dest, std::string& error) { error.clear(); - m_spk_man->TopUpKeyPool(); + + m_spk_man->TopUp(); ReserveDestination reservedest(this); if (!reservedest.GetReservedDestination(dest, true)) { @@ -3928,7 +3932,7 @@ bool ReserveDestination::GetReservedDestination(CTxDestination& dest, bool fInte if (nIndex == -1) { CKeyPool keypool; - if (!m_spk_man->ReserveKeyFromKeyPool(nIndex, keypool, fInternalIn)) { + if (!m_spk_man->GetReservedDestination(fInternalIn, nIndex, keypool)) { return false; } vchPubKey = keypool.vchPubKey; @@ -3943,7 +3947,7 @@ bool ReserveDestination::GetReservedDestination(CTxDestination& dest, bool fInte void ReserveDestination::KeepDestination() { if (nIndex != -1) { - m_spk_man->KeepKey(nIndex); + m_spk_man->KeepDestination(nIndex); } nIndex = -1; vchPubKey = CPubKey(); @@ -3953,7 +3957,7 @@ void ReserveDestination::KeepDestination() void ReserveDestination::ReturnDestination() { if (nIndex != -1) { - m_spk_man->ReturnKey(nIndex, fInternal, vchPubKey); + m_spk_man->ReturnDestination(nIndex, fInternal, vchPubKey); } nIndex = -1; vchPubKey = CPubKey(); @@ -4341,7 +4345,7 @@ std::shared_ptr CWallet::CreateWalletFromFile(interfaces::Chain& chain, } // Otherwise, do not create a new HD chain // Top up the keypool - if (walletInstance->m_spk_man->CanGenerateKeys() && !walletInstance->TopUpKeyPool()) { + if (walletInstance->m_spk_man->CanGenerateKeys() && !walletInstance->m_spk_man->TopUp()) { return unload_wallet(_("Unable to generate initial keys")); } @@ -4359,9 +4363,10 @@ std::shared_ptr CWallet::CreateWalletFromFile(interfaces::Chain& chain, error = strprintf(_("Error loading %s: Private keys can only be disabled during creation"), walletFile); return NULL; } else if (walletInstance->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { - LOCK(walletInstance->cs_KeyStore); - if (!walletInstance->mapKeys.empty() || !walletInstance->mapCryptedKeys.empty()) { - warnings.push_back(strprintf(_("Warning: Private keys detected in wallet {%s} with disabled private keys"), walletFile)); + if (walletInstance->m_spk_man) { + if (walletInstance->m_spk_man->HavePrivateKeys()) { + warnings.push_back(strprintf(_("Warning: Private keys detected in wallet {%s} with disabled private keys"), walletFile)); + } } } else if (gArgs.IsArgSet("-usehd")) { @@ -4526,8 +4531,14 @@ std::shared_ptr CWallet::CreateWalletFromFile(interfaces::Chain& chain, // our wallet birthday (as adjusted for block time variability) // unless a full rescan was requested if (gArgs.GetArg("-rescan", 0) != 2) { - if (walletInstance->nTimeFirstKey) { - if (Optional first_block = chain.findFirstBlockWithTimeAndHeight(walletInstance->nTimeFirstKey - TIMESTAMP_WINDOW, rescan_height, nullptr)) { + Optional time_first_key; + if (auto spk_man = walletInstance->m_spk_man.get()) { + LOCK(spk_man->cs_wallet); + int64_t time = spk_man->GetTimeFirstKey(); + if (!time_first_key || time < *time_first_key) time_first_key = time; + } + if (time_first_key) { + if (Optional first_block = chain.findFirstBlockWithTimeAndHeight(*time_first_key - TIMESTAMP_WINDOW, rescan_height, nullptr)) { rescan_height = *first_block; } } @@ -4557,7 +4568,10 @@ std::shared_ptr CWallet::CreateWalletFromFile(interfaces::Chain& chain, walletInstance->WalletLogPrintf("setInternalKeyPool.size() = %u\n", walletInstance->KeypoolCountInternalKeys()); walletInstance->WalletLogPrintf("mapWallet.size() = %u\n", walletInstance->mapWallet.size()); walletInstance->WalletLogPrintf("mapAddressBook.size() = %u\n", walletInstance->mapAddressBook.size()); - walletInstance->WalletLogPrintf("nTimeFirstKey = %u\n", walletInstance->nTimeFirstKey); + if (auto spk_man = walletInstance->m_spk_man.get()) { + LOCK(spk_man->cs_wallet); + walletInstance->WalletLogPrintf("nTimeFirstKey = %u\n", spk_man->GetTimeFirstKey()); + } } return walletInstance; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index bfb5fed353..272299e397 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -730,6 +730,14 @@ private: std::atomic m_wallet_flags{0}; + bool SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& address, const std::string& strName, const std::string& strPurpose); + + //! Unsets a wallet flag and saves it to disk + void UnsetWalletFlagWithDB(WalletBatch& batch, uint64_t flag); + + //! Unset the blank wallet flag and saves it to disk + void UnsetBlankWalletFlag(WalletBatch& batch) override; + /** Interface for accessing chain state. */ interfaces::Chain* m_chain; @@ -1096,16 +1104,11 @@ public: void AutoLockMasternodeCollaterals(); DBErrors ZapSelectTx(std::vector& vHashIn, std::vector& vHashOut) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - bool SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& address, const std::string& strName, const std::string& strPurpose); bool SetAddressBook(const CTxDestination& address, const std::string& strName, const std::string& purpose); bool DelAddressBook(const CTxDestination& address); - unsigned int GetKeyPoolSize() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) - { - AssertLockHeld(cs_wallet); - return setInternalKeyPool.size() + setExternalKeyPool.size(); - } + unsigned int GetKeyPoolSize() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); //! signify that a particular wallet feature is now used. this may change nWalletVersion and nWalletMaxVersion if those are lower void SetMinVersion(enum WalletFeature, WalletBatch* batch_in = nullptr, bool fExplicit = false) override; @@ -1229,11 +1232,10 @@ public: void BlockUntilSyncedToCurrentChain() LOCKS_EXCLUDED(cs_main, cs_wallet); /** set a single wallet flag */ - void SetWalletFlag(uint64_t flags) override; + void SetWalletFlag(uint64_t flags); /** Unsets a single wallet flag */ void UnsetWalletFlag(uint64_t flag); - void UnsetWalletFlag(WalletBatch& batch, uint64_t flag); /** check if a certain wallet flag is set */ bool IsWalletFlagSet(uint64_t flag) const override; @@ -1284,12 +1286,6 @@ public: LegacyScriptPubKeyMan::WatchKeyMap& mapWatchKeys GUARDED_BY(cs_KeyStore) = m_spk_man->mapWatchKeys; LegacyScriptPubKeyMan::HDPubKeyMap& mapHdPubKeys GUARDED_BY(cs_KeyStore) = m_spk_man->mapHdPubKeys; WalletBatch*& encrypted_batch GUARDED_BY(cs_wallet) = m_spk_man->encrypted_batch; - std::set& setInternalKeyPool GUARDED_BY(cs_wallet) = m_spk_man->setInternalKeyPool; - std::set& setExternalKeyPool GUARDED_BY(cs_wallet) = m_spk_man->setExternalKeyPool; - int64_t& nTimeFirstKey GUARDED_BY(cs_wallet) = m_spk_man->nTimeFirstKey; - std::map& mapKeyMetadata GUARDED_BY(cs_wallet) = m_spk_man->mapKeyMetadata; - std::map& m_script_metadata GUARDED_BY(cs_wallet) = m_spk_man->m_script_metadata; - void MarkReserveKeysAsUsed(int64_t keypool_id) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { AssertLockHeld(m_spk_man->cs_wallet); m_spk_man->MarkReserveKeysAsUsed(keypool_id); } using CryptedKeyMap = LegacyScriptPubKeyMan::CryptedKeyMap; };