diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h --- a/src/wallet/scriptpubkeyman.h +++ b/src/wallet/scriptpubkeyman.h @@ -623,12 +623,23 @@ // Map of scripts to descriptor range index using ScriptPubKeyMap = std::map; + using CryptedKeyMap = + std::map>>; + using KeyMap = std::map; ScriptPubKeyMap m_map_script_pub_keys GUARDED_BY(cs_desc_man); OutputType m_address_type; bool m_internal; + 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; + public: DescriptorScriptPubKeyMan(WalletStorage &storage, WalletDescriptor &descriptor) @@ -694,6 +705,10 @@ 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 &crypted_key); }; #endif // BITCOIN_WALLET_SCRIPTPUBKEYMAN_H diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1677,3 +1677,21 @@ } } } + +bool DescriptorScriptPubKeyMan::AddKey(const CKeyID &key_id, const CKey &key) { + LOCK(cs_desc_man); + m_map_keys[key_id] = key; + return true; +} + +bool DescriptorScriptPubKeyMan::AddCryptedKey( + const CKeyID &key_id, const CPubKey &pubkey, + const std::vector &crypted_key) { + LOCK(cs_desc_man); + if (!m_map_keys.empty()) { + return false; + } + + m_map_crypted_keys[key_id] = make_pair(pubkey, crypted_key); + return true; +} diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -44,6 +44,8 @@ const std::string VERSION{"version"}; const std::string WALLETDESCRIPTOR{"walletdescriptor"}; const std::string WALLETDESCRIPTORCACHE{"walletdescriptorcache"}; +const std::string WALLETDESCRIPTORCKEY{"walletdescriptorckey"}; +const std::string WALLETDESCRIPTORKEY{"walletdescriptorkey"}; const std::string WATCHMETA{"watchmeta"}; const std::string WATCHS{"watchs"}; } // namespace DBKeys @@ -216,6 +218,10 @@ std::map m_active_external_spks; std::map m_active_internal_spks; std::map m_descriptor_caches; + std::map, CKey> m_descriptor_keys; + std::map, + std::pair>> + m_descriptor_crypt_keys; CWalletScanState() {} }; @@ -504,6 +510,58 @@ wss.m_descriptor_caches[desc_id].CacheDerivedExtPubKey( key_exp_index, der_index, xpub); } + } else if (strType == DBKeys::WALLETDESCRIPTORKEY) { + uint256 desc_id; + CPubKey pubkey; + ssKey >> desc_id; + ssKey >> pubkey; + if (!pubkey.IsValid()) { + strErr = "Error reading wallet database: CPubKey corrupt"; + return false; + } + CKey key; + CPrivKey pkey; + uint256 hash; + + wss.nKeys++; + ssValue >> pkey; + ssValue >> hash; + + // hash pubkey/privkey to accelerate wallet load + std::vector to_hash; + to_hash.reserve(pubkey.size() + pkey.size()); + to_hash.insert(to_hash.end(), pubkey.begin(), pubkey.end()); + to_hash.insert(to_hash.end(), pkey.begin(), pkey.end()); + + if (Hash(to_hash.begin(), to_hash.end()) != hash) { + strErr = + "Error reading wallet database: CPubKey/CPrivKey corrupt"; + return false; + } + + if (!key.Load(pkey, pubkey, true)) { + strErr = "Error reading wallet database: CPrivKey corrupt"; + return false; + } + wss.m_descriptor_keys.insert( + std::make_pair(std::make_pair(desc_id, pubkey.GetID()), key)); + } else if (strType == DBKeys::WALLETDESCRIPTORCKEY) { + uint256 desc_id; + CPubKey pubkey; + ssKey >> desc_id; + ssKey >> pubkey; + if (!pubkey.IsValid()) { + strErr = "Error reading wallet database: CPubKey corrupt"; + return false; + } + std::vector privkey; + ssValue >> privkey; + wss.nCKeys++; + + wss.m_descriptor_crypt_keys.insert( + std::make_pair(std::make_pair(desc_id, pubkey.GetID()), + std::make_pair(pubkey, privkey))); + wss.fIsEncrypted = true; } else if (strType != DBKeys::BESTBLOCK && strType != DBKeys::BESTBLOCK_NOMERKLE && strType != DBKeys::MINVERSION && @@ -620,6 +678,20 @@ ->SetCache(desc_cache_pair.second); } + // Set the descriptor keys + for (auto desc_key_pair : wss.m_descriptor_keys) { + auto spk_man = pwallet->GetScriptPubKeyMan(desc_key_pair.first.first); + ((DescriptorScriptPubKeyMan *)spk_man) + ->AddKey(desc_key_pair.first.second, desc_key_pair.second); + } + for (auto desc_key_pair : wss.m_descriptor_crypt_keys) { + auto spk_man = pwallet->GetScriptPubKeyMan(desc_key_pair.first.first); + ((DescriptorScriptPubKeyMan *)spk_man) + ->AddCryptedKey(desc_key_pair.first.second, + desc_key_pair.second.first, + desc_key_pair.second.second); + } + if (fNoncriticalErrors && result == DBErrors::LOAD_OK) { result = DBErrors::NONCRITICAL_ERROR; }