From 2b9279b50a3682ab97308888b4f272d3ae379811 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Tue, 24 Oct 2023 17:45:01 -0400 Subject: [PATCH] wallet: Remove unused encryption keys from watchonly wallets Due to a bug in earlier versions, some wallets without private keys may have an encryption key. This encryption key is unused and can lead to confusing behavior elsewhere. When such wallets are detected, those encryption keys will now be deleted from the wallet. For safety, we only do this to wallets which have private keys disabled, have encryption keys, and definitely do not have encrypted keys. --- src/wallet/walletdb.cpp | 20 ++++++++++++++++++++ src/wallet/walletdb.h | 1 + 2 files changed, 21 insertions(+) diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 597a4ef9a4c..82e73fc2130 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -154,6 +154,11 @@ bool WalletBatch::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey) return WriteIC(std::make_pair(DBKeys::MASTER_KEY, nID), kMasterKey, true); } +bool WalletBatch::EraseMasterKey(unsigned int id) +{ + return EraseIC(std::make_pair(DBKeys::MASTER_KEY, id)); +} + bool WalletBatch::WriteCScript(const uint160& hash, const CScript& redeemScript) { return WriteIC(std::make_pair(DBKeys::CSCRIPT, hash), redeemScript, false); @@ -1241,6 +1246,21 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet) result = DBErrors::CORRUPT; } + // Since it was accidentally possible to "encrypt" a wallet with private keys disabled, we should check if this is + // such a wallet and remove the encryption key records to avoid any future issues. + // Although wallets without private keys should not have *ckey records, we should double check that. + // Removing the mkey records is only safe if there are no *ckey records. + if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && pwallet->HasEncryptionKeys() && !pwallet->HaveCryptedKeys()) { + pwallet->WalletLogPrintf("Detected extraneous encryption keys in this wallet without private keys. Removing extraneous encryption keys.\n"); + for (const auto& [id, _] : pwallet->mapMasterKeys) { + if (!EraseMasterKey(id)) { + pwallet->WalletLogPrintf("Error: Unable to remove extraneous encryption key '%u'. Wallet corrupt.\n", id); + return DBErrors::CORRUPT; + } + } + pwallet->mapMasterKeys.clear(); + } + return result; } diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index bffcc87202a..08054f42bae 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -238,6 +238,7 @@ public: bool WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata &keyMeta); bool WriteCryptedKey(const CPubKey& vchPubKey, const std::vector& vchCryptedSecret, const CKeyMetadata &keyMeta); bool WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey); + bool EraseMasterKey(unsigned int id); bool WriteCScript(const uint160& hash, const CScript& redeemScript);