From 8f5b81e6edae9cb22559545de63f391d97c15701 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Thu, 6 Jun 2019 23:58:21 +0200 Subject: [PATCH] Remove CCryptoKeyStore and move all of it's functionality into CWallet Instead of having a separate CCryptoKeyStore that handles the encryption stuff, just roll it all into CWallet. --- src/interfaces/wallet.cpp | 2 +- src/wallet/crypter.cpp | 192 +---------------------------------- src/wallet/crypter.h | 54 +--------- src/wallet/wallet.cpp | 207 ++++++++++++++++++++++++++++++++++++-- src/wallet/wallet.h | 48 ++++++++- 5 files changed, 247 insertions(+), 256 deletions(-) diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp index 34c982e1e68..f4d25d1f90f 100644 --- a/src/interfaces/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -476,7 +476,7 @@ public: } std::unique_ptr handleStatusChanged(StatusChangedFn fn) override { - return MakeHandler(m_wallet->NotifyStatusChanged.connect([fn](CCryptoKeyStore*) { fn(); })); + return MakeHandler(m_wallet->NotifyStatusChanged.connect([fn](CWallet*) { fn(); })); } std::unique_ptr handleAddressBookChanged(AddressBookChangedFn fn) override { diff --git a/src/wallet/crypter.cpp b/src/wallet/crypter.cpp index 3070454b1b9..0b76c1a0eb5 100644 --- a/src/wallet/crypter.cpp +++ b/src/wallet/crypter.cpp @@ -107,8 +107,7 @@ bool CCrypter::Decrypt(const std::vector& vchCiphertext, CKeyingM return true; } - -static bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector &vchCiphertext) +bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector &vchCiphertext) { CCrypter cKeyCrypter; std::vector chIV(WALLET_CRYPTO_IV_SIZE); @@ -118,7 +117,7 @@ static bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMateri return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext); } -static bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext) +bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext) { CCrypter cKeyCrypter; std::vector chIV(WALLET_CRYPTO_IV_SIZE); @@ -128,7 +127,7 @@ static bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key) +bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key) { CKeyingMaterial vchSecret; if(!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret)) @@ -140,188 +139,3 @@ static bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector &vchCryptedSecret = (*mi).second.second; - CKey key; - if (!DecryptKey(vMasterKeyIn, vchCryptedSecret, vchPubKey, key)) - { - keyFail = true; - break; - } - keyPass = true; - if (fDecryptionThoroughlyChecked) - break; - } - if (keyPass && keyFail) - { - LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n"); - throw std::runtime_error("Error unlocking wallet: some keys decrypt but not all. Your wallet file may be corrupt."); - } - if (keyFail || (!keyPass && !accept_no_keys)) - return false; - vMasterKey = vMasterKeyIn; - fDecryptionThoroughlyChecked = true; - } - NotifyStatusChanged(this); - return true; -} - -bool CCryptoKeyStore::AddKeyPubKey(const CKey& key, const CPubKey &pubkey) -{ - LOCK(cs_KeyStore); - if (!IsCrypted()) { - return FillableSigningProvider::AddKeyPubKey(key, pubkey); - } - - if (IsLocked()) { - return false; - } - - std::vector vchCryptedSecret; - CKeyingMaterial vchSecret(key.begin(), key.end()); - if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret)) { - return false; - } - - if (!AddCryptedKey(pubkey, vchCryptedSecret)) { - return false; - } - return true; -} - - -bool CCryptoKeyStore::AddCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret) -{ - LOCK(cs_KeyStore); - if (!SetCrypted()) { - return false; - } - - mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret); - ImplicitlyLearnRelatedKeyScripts(vchPubKey); - return true; -} - -bool CCryptoKeyStore::HaveKey(const CKeyID &address) const -{ - LOCK(cs_KeyStore); - if (!IsCrypted()) { - return FillableSigningProvider::HaveKey(address); - } - return mapCryptedKeys.count(address) > 0; -} - -bool CCryptoKeyStore::GetKey(const CKeyID &address, CKey& keyOut) const -{ - LOCK(cs_KeyStore); - if (!IsCrypted()) { - return FillableSigningProvider::GetKey(address, keyOut); - } - - CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address); - if (mi != mapCryptedKeys.end()) - { - const CPubKey &vchPubKey = (*mi).second.first; - const std::vector &vchCryptedSecret = (*mi).second.second; - return DecryptKey(vMasterKey, vchCryptedSecret, vchPubKey, keyOut); - } - return false; -} - -bool CCryptoKeyStore::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const -{ - LOCK(cs_KeyStore); - if (!IsCrypted()) - return FillableSigningProvider::GetPubKey(address, vchPubKeyOut); - - CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address); - if (mi != mapCryptedKeys.end()) - { - vchPubKeyOut = (*mi).second.first; - return true; - } - // Check for watch-only pubkeys - return FillableSigningProvider::GetPubKey(address, vchPubKeyOut); -} - -std::set CCryptoKeyStore::GetKeys() const -{ - LOCK(cs_KeyStore); - if (!IsCrypted()) { - return FillableSigningProvider::GetKeys(); - } - std::set set_address; - for (const auto& mi : mapCryptedKeys) { - set_address.insert(mi.first); - } - return set_address; -} - -bool CCryptoKeyStore::EncryptKeys(CKeyingMaterial& vMasterKeyIn) -{ - LOCK(cs_KeyStore); - if (!mapCryptedKeys.empty() || IsCrypted()) - return false; - - fUseCrypto = true; - for (const KeyMap::value_type& mKey : mapKeys) - { - const CKey &key = mKey.second; - CPubKey vchPubKey = key.GetPubKey(); - CKeyingMaterial vchSecret(key.begin(), key.end()); - std::vector vchCryptedSecret; - if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret)) - return false; - if (!AddCryptedKey(vchPubKey, vchCryptedSecret)) - return false; - } - mapKeys.clear(); - return true; -} diff --git a/src/wallet/crypter.h b/src/wallet/crypter.h index 4cc40a8c6fa..17a4e9820ce 100644 --- a/src/wallet/crypter.h +++ b/src/wallet/crypter.h @@ -11,8 +11,6 @@ #include -#include - const unsigned int WALLET_CRYPTO_KEY_SIZE = 32; const unsigned int WALLET_CRYPTO_SALT_SIZE = 8; const unsigned int WALLET_CRYPTO_IV_SIZE = 16; @@ -111,54 +109,8 @@ public: } }; -/** Keystore which keeps the private keys encrypted. - * It derives from the basic key store, which is used if no encryption is active. - */ -class CCryptoKeyStore : public FillableSigningProvider -{ -private: - - CKeyingMaterial vMasterKey GUARDED_BY(cs_KeyStore); - - //! if fUseCrypto is true, mapKeys must be empty - //! if fUseCrypto is false, vMasterKey must be empty - std::atomic fUseCrypto; - - //! keeps track of whether Unlock has run a thorough check before - bool fDecryptionThoroughlyChecked; - -protected: - using CryptedKeyMap = std::map>>; - - bool SetCrypted(); - - //! will encrypt previously unencrypted keys - bool EncryptKeys(CKeyingMaterial& vMasterKeyIn); - - bool Unlock(const CKeyingMaterial& vMasterKeyIn, bool accept_no_keys = false); - CryptedKeyMap mapCryptedKeys GUARDED_BY(cs_KeyStore); - -public: - CCryptoKeyStore() : fUseCrypto(false), fDecryptionThoroughlyChecked(false) - { - } - - bool IsCrypted() const { return fUseCrypto; } - bool IsLocked() const; - bool Lock(); - - virtual bool AddCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret); - bool AddKeyPubKey(const CKey& key, const CPubKey &pubkey) override; - 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; - std::set GetKeys() const override; - - /** - * Wallet status (encrypted, locked) changed. - * Note: Called without locks held. - */ - boost::signals2::signal NotifyStatusChanged; -}; +bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector &vchCiphertext); +bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext); +bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key); #endif // BITCOIN_WALLET_CRYPTER_H diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 054123880b7..0a915ff9a11 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -294,14 +294,14 @@ bool CWallet::AddKeyPubKeyWithDB(WalletBatch& batch, const CKey& secret, const C // Make sure we aren't adding private keys to private key disabled wallets assert(!IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)); - // CCryptoKeyStore has no concept of wallet databases, but calls AddCryptedKey + // FillableSigningProvider has no concept of wallet databases, but calls AddCryptedKey // which is overridden below. To avoid flushes, the database handle is // tunneled through to it. bool needsDB = !encrypted_batch; if (needsDB) { encrypted_batch = &batch; } - if (!CCryptoKeyStore::AddKeyPubKey(secret, pubkey)) { + if (!AddKeyPubKeyInner(secret, pubkey)) { if (needsDB) encrypted_batch = nullptr; return false; } @@ -336,7 +336,7 @@ bool CWallet::AddKeyPubKey(const CKey& secret, const CPubKey &pubkey) bool CWallet::AddCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret) { - if (!CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret)) + if (!AddCryptedKeyInner(vchPubKey, vchCryptedSecret)) return false; { LOCK(cs_wallet); @@ -404,7 +404,7 @@ void CWallet::UpgradeKeyMetadata() bool CWallet::LoadCryptedKey(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret) { - return CCryptoKeyStore::AddCryptedKey(vchPubKey, vchCryptedSecret); + return AddCryptedKeyInner(vchPubKey, vchCryptedSecret); } /** @@ -431,7 +431,7 @@ bool CWallet::AddCScript(const CScript& redeemScript) bool CWallet::AddCScriptWithDB(WalletBatch& batch, const CScript& redeemScript) { - if (!CCryptoKeyStore::AddCScript(redeemScript)) + if (!FillableSigningProvider::AddCScript(redeemScript)) return false; if (batch.WriteCScript(Hash160(redeemScript), redeemScript)) { UnsetWalletFlagWithDB(batch, WALLET_FLAG_BLANK_WALLET); @@ -452,12 +452,12 @@ bool CWallet::LoadCScript(const CScript& redeemScript) return true; } - return CCryptoKeyStore::AddCScript(redeemScript); + return FillableSigningProvider::AddCScript(redeemScript); } bool CWallet::AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest) { - if (!CCryptoKeyStore::AddWatchOnly(dest)) + if (!FillableSigningProvider::AddWatchOnly(dest)) return false; const CKeyMetadata& meta = m_script_metadata[CScriptID(dest)]; UpdateTimeFirstKey(meta.nCreateTime); @@ -490,7 +490,7 @@ bool CWallet::AddWatchOnly(const CScript& dest, int64_t nCreateTime) bool CWallet::RemoveWatchOnly(const CScript &dest) { AssertLockHeld(cs_wallet); - if (!CCryptoKeyStore::RemoveWatchOnly(dest)) + if (!FillableSigningProvider::RemoveWatchOnly(dest)) return false; if (!HaveWatchOnly()) NotifyWatchonlyChanged(false); @@ -502,7 +502,7 @@ bool CWallet::RemoveWatchOnly(const CScript &dest) bool CWallet::LoadWatchOnly(const CScript &dest) { - return CCryptoKeyStore::AddWatchOnly(dest); + return FillableSigningProvider::AddWatchOnly(dest); } bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool accept_no_keys) @@ -518,7 +518,7 @@ bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool accept_no_key return false; if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey)) continue; // try another master key - if (CCryptoKeyStore::Unlock(_vMasterKey, accept_no_keys)) { + if (Unlock(_vMasterKey, accept_no_keys)) { // Now that we've unlocked, upgrade the key metadata UpgradeKeyMetadata(); return true; @@ -544,7 +544,7 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, return false; if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey)) return false; - if (CCryptoKeyStore::Unlock(_vMasterKey)) + if (Unlock(_vMasterKey)) { int64_t nStartTime = GetTimeMillis(); crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod); @@ -4588,3 +4588,188 @@ bool CWallet::AddKeyOriginWithDB(WalletBatch& batch, const CPubKey& pubkey, cons mapKeyMetadata[pubkey.GetID()].hdKeypath = WriteHDKeypath(info.path); return batch.WriteKeyMetadata(mapKeyMetadata[pubkey.GetID()], pubkey, true); } + +bool CWallet::SetCrypted() +{ + LOCK(cs_KeyStore); + if (fUseCrypto) + return true; + if (!mapKeys.empty()) + return false; + fUseCrypto = true; + return true; +} + +bool CWallet::IsLocked() const +{ + if (!IsCrypted()) { + return false; + } + LOCK(cs_KeyStore); + return vMasterKey.empty(); +} + +bool CWallet::Lock() +{ + if (!SetCrypted()) + return false; + + { + LOCK(cs_KeyStore); + vMasterKey.clear(); + } + + NotifyStatusChanged(this); + return true; +} + +bool CWallet::Unlock(const CKeyingMaterial& vMasterKeyIn, bool accept_no_keys) +{ + { + LOCK(cs_KeyStore); + if (!SetCrypted()) + return false; + + bool keyPass = mapCryptedKeys.empty(); // Always pass when there are no encrypted keys + bool keyFail = false; + CryptedKeyMap::const_iterator mi = mapCryptedKeys.begin(); + for (; mi != mapCryptedKeys.end(); ++mi) + { + const CPubKey &vchPubKey = (*mi).second.first; + const std::vector &vchCryptedSecret = (*mi).second.second; + CKey key; + if (!DecryptKey(vMasterKeyIn, vchCryptedSecret, vchPubKey, key)) + { + keyFail = true; + break; + } + keyPass = true; + if (fDecryptionThoroughlyChecked) + break; + } + if (keyPass && keyFail) + { + LogPrintf("The wallet is probably corrupted: Some keys decrypt but not all.\n"); + throw std::runtime_error("Error unlocking wallet: some keys decrypt but not all. Your wallet file may be corrupt."); + } + if (keyFail || (!keyPass && !accept_no_keys)) + return false; + vMasterKey = vMasterKeyIn; + fDecryptionThoroughlyChecked = true; + } + NotifyStatusChanged(this); + return true; +} + +bool CWallet::HaveKey(const CKeyID &address) const +{ + LOCK(cs_KeyStore); + if (!IsCrypted()) { + return FillableSigningProvider::HaveKey(address); + } + return mapCryptedKeys.count(address) > 0; +} + +bool CWallet::GetKey(const CKeyID &address, CKey& keyOut) const +{ + LOCK(cs_KeyStore); + if (!IsCrypted()) { + return FillableSigningProvider::GetKey(address, keyOut); + } + + CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address); + if (mi != mapCryptedKeys.end()) + { + const CPubKey &vchPubKey = (*mi).second.first; + const std::vector &vchCryptedSecret = (*mi).second.second; + return DecryptKey(vMasterKey, vchCryptedSecret, vchPubKey, keyOut); + } + return false; +} + +bool CWallet::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const +{ + LOCK(cs_KeyStore); + if (!IsCrypted()) + return FillableSigningProvider::GetPubKey(address, vchPubKeyOut); + + CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address); + if (mi != mapCryptedKeys.end()) + { + vchPubKeyOut = (*mi).second.first; + return true; + } + // Check for watch-only pubkeys + return FillableSigningProvider::GetPubKey(address, vchPubKeyOut); +} + +std::set CWallet::GetKeys() const +{ + LOCK(cs_KeyStore); + if (!IsCrypted()) { + return FillableSigningProvider::GetKeys(); + } + std::set set_address; + for (const auto& mi : mapCryptedKeys) { + set_address.insert(mi.first); + } + return set_address; +} + +bool CWallet::EncryptKeys(CKeyingMaterial& vMasterKeyIn) +{ + LOCK(cs_KeyStore); + if (!mapCryptedKeys.empty() || IsCrypted()) + return false; + + fUseCrypto = true; + for (const KeyMap::value_type& mKey : mapKeys) + { + const CKey &key = mKey.second; + CPubKey vchPubKey = key.GetPubKey(); + CKeyingMaterial vchSecret(key.begin(), key.end()); + std::vector vchCryptedSecret; + if (!EncryptSecret(vMasterKeyIn, vchSecret, vchPubKey.GetHash(), vchCryptedSecret)) + return false; + if (!AddCryptedKey(vchPubKey, vchCryptedSecret)) + return false; + } + mapKeys.clear(); + return true; +} + +bool CWallet::AddKeyPubKeyInner(const CKey& key, const CPubKey &pubkey) +{ + LOCK(cs_KeyStore); + if (!IsCrypted()) { + return FillableSigningProvider::AddKeyPubKey(key, pubkey); + } + + if (IsLocked()) { + return false; + } + + std::vector vchCryptedSecret; + CKeyingMaterial vchSecret(key.begin(), key.end()); + if (!EncryptSecret(vMasterKey, vchSecret, pubkey.GetHash(), vchCryptedSecret)) { + return false; + } + + if (!AddCryptedKey(pubkey, vchCryptedSecret)) { + return false; + } + return true; +} + + +bool CWallet::AddCryptedKeyInner(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret) +{ + LOCK(cs_KeyStore); + if (!SetCrypted()) { + return false; + } + + mapCryptedKeys[vchPubKey.GetID()] = make_pair(vchPubKey, vchCryptedSecret); + ImplicitlyLearnRelatedKeyScripts(vchPubKey); + return true; +} diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 3c1d998d19e..bd92147a599 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -35,6 +35,8 @@ #include #include +#include + //! Explicitly unload and delete the wallet. //! Blocks the current thread after signaling the unload intent so that all //! wallet clients release the wallet. @@ -709,9 +711,31 @@ class WalletRescanReserver; //forward declarations for ScanForWalletTransactions * A CWallet is an extension of a keystore, which also maintains a set of transactions and balances, * and provides the ability to create new transactions. */ -class CWallet final : public CCryptoKeyStore, private interfaces::Chain::Notifications +class CWallet final : public FillableSigningProvider, private interfaces::Chain::Notifications { private: + CKeyingMaterial vMasterKey GUARDED_BY(cs_KeyStore); + + //! if fUseCrypto is true, mapKeys must be empty + //! if fUseCrypto is false, vMasterKey must be empty + std::atomic fUseCrypto; + + //! keeps track of whether Unlock has run a thorough check before + bool fDecryptionThoroughlyChecked; + + using CryptedKeyMap = std::map>>; + + bool SetCrypted(); + + //! will encrypt previously unencrypted keys + bool EncryptKeys(CKeyingMaterial& vMasterKeyIn); + + bool Unlock(const CKeyingMaterial& vMasterKeyIn, bool accept_no_keys = false); + CryptedKeyMap mapCryptedKeys GUARDED_BY(cs_KeyStore); + + bool AddCryptedKeyInner(const CPubKey &vchPubKey, const std::vector &vchCryptedSecret); + bool AddKeyPubKeyInner(const CKey& key, const CPubKey &pubkey); + std::atomic fAbortRescan{false}; std::atomic fScanningWallet{false}; // controlled by WalletRescanReserver std::atomic m_scanning_start{0}; @@ -879,7 +903,9 @@ public: /** Construct wallet with specified name and database implementation. */ CWallet(interfaces::Chain* chain, const WalletLocation& location, std::unique_ptr database) - : m_chain(chain), + : fUseCrypto(false), + fDecryptionThoroughlyChecked(false), + m_chain(chain), m_location(location), database(std::move(database)) { @@ -893,6 +919,10 @@ public: encrypted_batch = nullptr; } + bool IsCrypted() const { return fUseCrypto; } + bool IsLocked() const; + bool Lock(); + std::map mapWallet GUARDED_BY(cs_wallet); typedef std::multimap TxItems; @@ -975,7 +1005,7 @@ public: //! 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 CCryptoKeyStore::AddKeyPubKey(key, pubkey); } + 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); @@ -986,9 +1016,13 @@ public: void UpdateTimeFirstKey(int64_t nCreateTime) 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) override; + 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); + bool GetKey(const CKeyID &address, CKey& keyOut) const override; + bool GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const override; + bool HaveKey(const CKeyID &address) const override; + std::set GetKeys() const override; bool AddCScript(const CScript& redeemScript) override; bool LoadCScript(const CScript& redeemScript); @@ -1232,6 +1266,12 @@ public: /** Keypool has new keys */ boost::signals2::signal NotifyCanGetAddressesChanged; + /** + * Wallet status (encrypted, locked) changed. + * Note: Called without locks held. + */ + boost::signals2::signal NotifyStatusChanged; + /** Inquire whether this wallet broadcasts transactions. */ bool GetBroadcastTransactions() const { return fBroadcastTransactions; } /** Set whether this wallet broadcasts transactions. */