diff options
-rw-r--r-- | src/script/signingprovider.cpp | 61 | ||||
-rw-r--r-- | src/script/signingprovider.h | 9 | ||||
-rw-r--r-- | src/wallet/wallet.cpp | 78 | ||||
-rw-r--r-- | src/wallet/wallet.h | 15 |
4 files changed, 84 insertions, 79 deletions
diff --git a/src/script/signingprovider.cpp b/src/script/signingprovider.cpp index a859a41c50..01757e2f65 100644 --- a/src/script/signingprovider.cpp +++ b/src/script/signingprovider.cpp @@ -73,8 +73,6 @@ void FillableSigningProvider::ImplicitlyLearnRelatedKeyScripts(const CPubKey& pu { AssertLockHeld(cs_KeyStore); CKeyID key_id = pubkey.GetID(); - // We must actually know about this key already. - assert(HaveKey(key_id) || mapWatchKeys.count(key_id)); // This adds the redeemscripts necessary to detect P2WPKH and P2SH-P2WPKH // outputs. Technically P2WPKH outputs don't have a redeemscript to be // spent. However, our current IsMine logic requires the corresponding @@ -98,12 +96,6 @@ bool FillableSigningProvider::GetPubKey(const CKeyID &address, CPubKey &vchPubKe { CKey key; if (!GetKey(address, key)) { - LOCK(cs_KeyStore); - WatchKeyMap::const_iterator it = mapWatchKeys.find(address); - if (it != mapWatchKeys.end()) { - vchPubKeyOut = it->second; - return true; - } return false; } vchPubKeyOut = key.GetPubKey(); @@ -183,59 +175,6 @@ bool FillableSigningProvider::GetCScript(const CScriptID &hash, CScript& redeemS return false; } -static bool ExtractPubKey(const CScript &dest, CPubKey& pubKeyOut) -{ - //TODO: Use Solver to extract this? - CScript::const_iterator pc = dest.begin(); - opcodetype opcode; - std::vector<unsigned char> vch; - if (!dest.GetOp(pc, opcode, vch) || !CPubKey::ValidSize(vch)) - return false; - pubKeyOut = CPubKey(vch); - if (!pubKeyOut.IsFullyValid()) - return false; - if (!dest.GetOp(pc, opcode, vch) || opcode != OP_CHECKSIG || dest.GetOp(pc, opcode, vch)) - return false; - return true; -} - -bool FillableSigningProvider::AddWatchOnly(const CScript &dest) -{ - LOCK(cs_KeyStore); - setWatchOnly.insert(dest); - CPubKey pubKey; - if (ExtractPubKey(dest, pubKey)) { - mapWatchKeys[pubKey.GetID()] = pubKey; - ImplicitlyLearnRelatedKeyScripts(pubKey); - } - return true; -} - -bool FillableSigningProvider::RemoveWatchOnly(const CScript &dest) -{ - LOCK(cs_KeyStore); - setWatchOnly.erase(dest); - CPubKey pubKey; - if (ExtractPubKey(dest, pubKey)) { - mapWatchKeys.erase(pubKey.GetID()); - } - // Related CScripts are not removed; having superfluous scripts around is - // harmless (see comment in ImplicitlyLearnRelatedKeyScripts). - return true; -} - -bool FillableSigningProvider::HaveWatchOnly(const CScript &dest) const -{ - LOCK(cs_KeyStore); - return setWatchOnly.count(dest) > 0; -} - -bool FillableSigningProvider::HaveWatchOnly() const -{ - LOCK(cs_KeyStore); - return (!setWatchOnly.empty()); -} - CKeyID GetKeyForDestination(const SigningProvider& store, const CTxDestination& dest) { // Only supports destinations which map to single public keys, i.e. P2PKH, diff --git a/src/script/signingprovider.h b/src/script/signingprovider.h index 5ead763826..4eec2311d4 100644 --- a/src/script/signingprovider.h +++ b/src/script/signingprovider.h @@ -66,14 +66,10 @@ protected: mutable CCriticalSection cs_KeyStore; using KeyMap = std::map<CKeyID, CKey>; - using WatchKeyMap = std::map<CKeyID, CPubKey>; using ScriptMap = std::map<CScriptID, CScript>; - using WatchOnlySet = std::set<CScript>; KeyMap mapKeys GUARDED_BY(cs_KeyStore); - WatchKeyMap mapWatchKeys GUARDED_BY(cs_KeyStore); ScriptMap mapScripts GUARDED_BY(cs_KeyStore); - WatchOnlySet setWatchOnly GUARDED_BY(cs_KeyStore); void ImplicitlyLearnRelatedKeyScripts(const CPubKey& pubkey) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); @@ -88,11 +84,6 @@ public: virtual bool HaveCScript(const CScriptID &hash) const override; virtual std::set<CScriptID> GetCScripts() const; virtual bool GetCScript(const CScriptID &hash, CScript& redeemScriptOut) const override; - - virtual bool AddWatchOnly(const CScript &dest); - virtual bool RemoveWatchOnly(const CScript &dest); - virtual bool HaveWatchOnly(const CScript &dest) const; - virtual bool HaveWatchOnly() const; }; /** Return the CKeyID of the key involved in a script (if there is a unique one). */ diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 0a915ff9a1..f4472d5bf4 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -455,9 +455,37 @@ bool CWallet::LoadCScript(const CScript& redeemScript) return FillableSigningProvider::AddCScript(redeemScript); } +static bool ExtractPubKey(const CScript &dest, CPubKey& pubKeyOut) +{ + //TODO: Use Solver to extract this? + CScript::const_iterator pc = dest.begin(); + opcodetype opcode; + std::vector<unsigned char> vch; + if (!dest.GetOp(pc, opcode, vch) || !CPubKey::ValidSize(vch)) + return false; + pubKeyOut = CPubKey(vch); + if (!pubKeyOut.IsFullyValid()) + return false; + if (!dest.GetOp(pc, opcode, vch) || opcode != OP_CHECKSIG || dest.GetOp(pc, opcode, vch)) + return false; + return true; +} + +bool CWallet::AddWatchOnlyInMem(const CScript &dest) +{ + LOCK(cs_KeyStore); + setWatchOnly.insert(dest); + CPubKey pubKey; + if (ExtractPubKey(dest, pubKey)) { + mapWatchKeys[pubKey.GetID()] = pubKey; + ImplicitlyLearnRelatedKeyScripts(pubKey); + } + return true; +} + bool CWallet::AddWatchOnlyWithDB(WalletBatch &batch, const CScript& dest) { - if (!FillableSigningProvider::AddWatchOnly(dest)) + if (!AddWatchOnlyInMem(dest)) return false; const CKeyMetadata& meta = m_script_metadata[CScriptID(dest)]; UpdateTimeFirstKey(meta.nCreateTime); @@ -490,8 +518,17 @@ bool CWallet::AddWatchOnly(const CScript& dest, int64_t nCreateTime) bool CWallet::RemoveWatchOnly(const CScript &dest) { AssertLockHeld(cs_wallet); - if (!FillableSigningProvider::RemoveWatchOnly(dest)) - return false; + { + LOCK(cs_KeyStore); + setWatchOnly.erase(dest); + CPubKey pubKey; + if (ExtractPubKey(dest, pubKey)) { + mapWatchKeys.erase(pubKey.GetID()); + } + // Related CScripts are not removed; having superfluous scripts around is + // harmless (see comment in ImplicitlyLearnRelatedKeyScripts). + } + if (!HaveWatchOnly()) NotifyWatchonlyChanged(false); if (!WalletBatch(*database).EraseWatchOnly(dest)) @@ -502,7 +539,19 @@ bool CWallet::RemoveWatchOnly(const CScript &dest) bool CWallet::LoadWatchOnly(const CScript &dest) { - return FillableSigningProvider::AddWatchOnly(dest); + return AddWatchOnlyInMem(dest); +} + +bool CWallet::HaveWatchOnly(const CScript &dest) const +{ + LOCK(cs_KeyStore); + return setWatchOnly.count(dest) > 0; +} + +bool CWallet::HaveWatchOnly() const +{ + LOCK(cs_KeyStore); + return (!setWatchOnly.empty()); } bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool accept_no_keys) @@ -4687,11 +4736,26 @@ bool CWallet::GetKey(const CKeyID &address, CKey& keyOut) const return false; } +bool CWallet::GetWatchPubKey(const CKeyID &address, CPubKey &pubkey_out) const +{ + LOCK(cs_KeyStore); + WatchKeyMap::const_iterator it = mapWatchKeys.find(address); + if (it != mapWatchKeys.end()) { + pubkey_out = it->second; + return true; + } + return false; +} + bool CWallet::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const { LOCK(cs_KeyStore); - if (!IsCrypted()) - return FillableSigningProvider::GetPubKey(address, vchPubKeyOut); + if (!IsCrypted()) { + if (!FillableSigningProvider::GetPubKey(address, vchPubKeyOut)) { + return GetWatchPubKey(address, vchPubKeyOut); + } + return true; + } CryptedKeyMap::const_iterator mi = mapCryptedKeys.find(address); if (mi != mapCryptedKeys.end()) @@ -4700,7 +4764,7 @@ bool CWallet::GetPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const return true; } // Check for watch-only pubkeys - return FillableSigningProvider::GetPubKey(address, vchPubKeyOut); + return GetWatchPubKey(address, vchPubKeyOut); } std::set<CKeyID> CWallet::GetKeys() const diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index bd92147a59..80fb128f80 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -724,6 +724,8 @@ private: bool fDecryptionThoroughlyChecked; using CryptedKeyMap = std::map<CKeyID, std::pair<CPubKey, std::vector<unsigned char>>>; + using WatchOnlySet = std::set<CScript>; + using WatchKeyMap = std::map<CKeyID, CPubKey>; bool SetCrypted(); @@ -732,6 +734,8 @@ private: bool Unlock(const CKeyingMaterial& vMasterKeyIn, bool accept_no_keys = false); CryptedKeyMap mapCryptedKeys GUARDED_BY(cs_KeyStore); + WatchOnlySet setWatchOnly GUARDED_BY(cs_KeyStore); + WatchKeyMap mapWatchKeys GUARDED_BY(cs_KeyStore); bool AddCryptedKeyInner(const CPubKey &vchPubKey, const std::vector<unsigned char> &vchCryptedSecret); bool AddKeyPubKeyInner(const CKey& key, const CPubKey &pubkey); @@ -818,8 +822,9 @@ private: * of the other AddWatchOnly which accepts a timestamp and sets * nTimeFirstKey more intelligently for more efficient rescans. */ - bool AddWatchOnly(const CScript& dest) override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + 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); /** Add a KeyOriginInfo to the wallet */ bool AddKeyOriginWithDB(WalletBatch& batch, const CPubKey& pubkey, const KeyOriginInfo& info); @@ -1039,9 +1044,15 @@ public: //! 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 RemoveWatchOnly(const CScript &dest) override 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; //! Holds a timestamp at which point the wallet is scheduled (externally) to be relocked. Caller must arrange for actual relocking to occur via Lock(). int64_t nRelockTime = 0; |