mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-10 20:03:34 -03:00
Merge #10952: [wallet] Remove vchDefaultKey and have better first run detection
e53615b
Remove vchDefaultKey and have better first run detection (Andrew Chow)
Pull request description:
Removes vchDefaultKey which was only used for first run detection. Improves wallet first run detection by checking to see if any keys were read from the database.
This also fixes a (rather contrived) case where an encrypted non-HD wallet has corruption such that the default key is no longer valid and is loaded into a Core version that supports HD wallets. This causes a runtime exception since a new hd master key is generated as the software believes the wallet file is newly created but cannot add the generated key to the wallet since it is encrypted. I was only able to replicate this error by creating a non-hd wallet, encrypting it, then editing the wallet using `db_dump` and `db_load` before loading the wallet with hd enabled. This problem has been reported by [two](https://bitcointalk.org/index.php?topic=1993244.0) [users](https://bitcointalk.org/index.php?topic=1746976.msg17511261#msg17511261) so it is something that can happen, although that raises the question of "what corrupted the default key".
~P.S. I don't know what's up with the whitespace changes. I think my text editor is doing something stupid but I don't think those are important enough to attempt undoing them.~ Undid those
Tree-SHA512: 63b485f356566e8ffa033ad9b7101f7f6b56372b29ec2a43b947b0eeb1ada4c2cfe24740515d013aedd5f51aa1890dfbe499d2c5c062fc1b5d272324728a7d55
This commit is contained in:
commit
262167393d
7 changed files with 23 additions and 38 deletions
|
@ -113,7 +113,6 @@ public:
|
|||
class CCryptoKeyStore : public CBasicKeyStore
|
||||
{
|
||||
private:
|
||||
CryptedKeyMap mapCryptedKeys;
|
||||
|
||||
CKeyingMaterial vMasterKey;
|
||||
|
||||
|
@ -131,6 +130,7 @@ protected:
|
|||
bool EncryptKeys(CKeyingMaterial& vMasterKeyIn);
|
||||
|
||||
bool Unlock(const CKeyingMaterial& vMasterKeyIn);
|
||||
CryptedKeyMap mapCryptedKeys;
|
||||
|
||||
public:
|
||||
CCryptoKeyStore() : fUseCrypto(false), fDecryptionThoroughlyChecked(false)
|
||||
|
|
|
@ -3123,9 +3123,11 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
|
|||
}
|
||||
}
|
||||
|
||||
// This wallet is in its first run if all of these are empty
|
||||
fFirstRunRet = mapKeys.empty() && mapCryptedKeys.empty() && mapWatchKeys.empty() && setWatchOnly.empty() && mapScripts.empty();
|
||||
|
||||
if (nLoadWalletRet != DB_LOAD_OK)
|
||||
return nLoadWalletRet;
|
||||
fFirstRunRet = !vchDefaultKey.IsValid();
|
||||
|
||||
uiInterface.LoadWallet(this);
|
||||
|
||||
|
@ -3135,7 +3137,6 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
|
|||
DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut)
|
||||
{
|
||||
AssertLockHeld(cs_wallet); // mapWallet
|
||||
vchDefaultKey = CPubKey();
|
||||
DBErrors nZapSelectTxRet = CWalletDB(*dbw,"cr+").ZapSelectTx(vHashIn, vHashOut);
|
||||
for (uint256 hash : vHashOut)
|
||||
mapWallet.erase(hash);
|
||||
|
@ -3164,7 +3165,6 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256
|
|||
|
||||
DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
|
||||
{
|
||||
vchDefaultKey = CPubKey();
|
||||
DBErrors nZapWalletTxRet = CWalletDB(*dbw,"cr+").ZapWalletTx(vWtx);
|
||||
if (nZapWalletTxRet == DB_NEED_REWRITE)
|
||||
{
|
||||
|
@ -3240,14 +3240,6 @@ const std::string& CWallet::GetAccountName(const CScript& scriptPubKey) const
|
|||
return DEFAULT_ACCOUNT_NAME;
|
||||
}
|
||||
|
||||
bool CWallet::SetDefaultKey(const CPubKey &vchPubKey)
|
||||
{
|
||||
if (!CWalletDB(*dbw).WriteDefaultKey(vchPubKey))
|
||||
return false;
|
||||
vchDefaultKey = vchPubKey;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark old keypool keys as used,
|
||||
* and generate all new keys
|
||||
|
@ -4019,13 +4011,11 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
|
|||
if (!walletInstance->SetHDMasterKey(masterPubKey))
|
||||
throw std::runtime_error(std::string(__func__) + ": Storing master key failed");
|
||||
}
|
||||
CPubKey newDefaultKey;
|
||||
if (walletInstance->GetKeyFromPool(newDefaultKey, false)) {
|
||||
walletInstance->SetDefaultKey(newDefaultKey);
|
||||
if (!walletInstance->SetAddressBook(walletInstance->vchDefaultKey.GetID(), "", "receive")) {
|
||||
InitError(_("Cannot write default address") += "\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Top up the keypool
|
||||
if (!walletInstance->TopUpKeyPool()) {
|
||||
InitError(_("Unable to generate initial keys") += "\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
walletInstance->SetBestChain(chainActive.GetLocator());
|
||||
|
|
|
@ -807,8 +807,6 @@ public:
|
|||
|
||||
std::map<CTxDestination, CAddressBookData> mapAddressBook;
|
||||
|
||||
CPubKey vchDefaultKey;
|
||||
|
||||
std::set<COutPoint> setLockedCoins;
|
||||
|
||||
const CWalletTx* GetWalletTx(const uint256& hash) const;
|
||||
|
@ -1038,8 +1036,6 @@ public:
|
|||
return setInternalKeyPool.size() + setExternalKeyPool.size();
|
||||
}
|
||||
|
||||
bool SetDefaultKey(const CPubKey &vchPubKey);
|
||||
|
||||
//! signify that a particular wallet feature is now used. this may change nWalletVersion and nWalletMaxVersion if those are lower
|
||||
bool SetMinVersion(enum WalletFeature, CWalletDB* pwalletdbIn = nullptr, bool fExplicit = false);
|
||||
|
||||
|
|
|
@ -130,11 +130,6 @@ bool CWalletDB::WriteOrderPosNext(int64_t nOrderPosNext)
|
|||
return WriteIC(std::string("orderposnext"), nOrderPosNext);
|
||||
}
|
||||
|
||||
bool CWalletDB::WriteDefaultKey(const CPubKey& vchPubKey)
|
||||
{
|
||||
return WriteIC(std::string("defaultkey"), vchPubKey);
|
||||
}
|
||||
|
||||
bool CWalletDB::ReadPool(int64_t nPool, CKeyPool& keypool)
|
||||
{
|
||||
return batch.Read(std::make_pair(std::string("pool"), nPool), keypool);
|
||||
|
@ -452,7 +447,14 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
|||
}
|
||||
else if (strType == "defaultkey")
|
||||
{
|
||||
ssValue >> pwallet->vchDefaultKey;
|
||||
// We don't want or need the default key, but if there is one set,
|
||||
// we want to make sure that it is valid so that we can detect corruption
|
||||
CPubKey vchPubKey;
|
||||
ssValue >> vchPubKey;
|
||||
if (!vchPubKey.IsValid()) {
|
||||
strErr = "Error reading wallet database: Default Key corrupt";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (strType == "pool")
|
||||
{
|
||||
|
@ -522,7 +524,6 @@ bool CWalletDB::IsKeyType(const std::string& strType)
|
|||
|
||||
DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
|
||||
{
|
||||
pwallet->vchDefaultKey = CPubKey();
|
||||
CWalletScanState wss;
|
||||
bool fNoncriticalErrors = false;
|
||||
DBErrors result = DB_LOAD_OK;
|
||||
|
@ -565,7 +566,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
|
|||
{
|
||||
// losing keys is considered a catastrophic error, anything else
|
||||
// we assume the user can live with:
|
||||
if (IsKeyType(strType))
|
||||
if (IsKeyType(strType) || strType == "defaultkey")
|
||||
result = DB_CORRUPT;
|
||||
else
|
||||
{
|
||||
|
|
|
@ -191,8 +191,6 @@ public:
|
|||
|
||||
bool WriteOrderPosNext(int64_t nOrderPosNext);
|
||||
|
||||
bool WriteDefaultKey(const CPubKey& vchPubKey);
|
||||
|
||||
bool ReadPool(int64_t nPool, CKeyPool& keypool);
|
||||
bool WritePool(int64_t nPool, const CKeyPool& keypool);
|
||||
bool ErasePool(int64_t nPool);
|
||||
|
|
|
@ -69,7 +69,7 @@ class KeypoolRestoreTest(BitcoinTestFramework):
|
|||
assert_equal(self.nodes[1].listtransactions()[0]['category'], "receive")
|
||||
|
||||
# Check that we have marked all keys up to the used keypool key as used
|
||||
assert_equal(self.nodes[1].validateaddress(self.nodes[1].getnewaddress())['hdkeypath'], "m/0'/0'/111'")
|
||||
assert_equal(self.nodes[1].validateaddress(self.nodes[1].getnewaddress())['hdkeypath'], "m/0'/0'/110'")
|
||||
|
||||
if __name__ == '__main__':
|
||||
KeypoolRestoreTest().main()
|
||||
|
|
|
@ -42,7 +42,7 @@ class WalletHDTest(BitcoinTestFramework):
|
|||
non_hd_add = self.nodes[0].getnewaddress()
|
||||
self.nodes[1].importprivkey(self.nodes[0].dumpprivkey(non_hd_add))
|
||||
|
||||
# This should be enough to keep the master key and the non-HD key
|
||||
# This should be enough to keep the master key and the non-HD key
|
||||
self.nodes[1].backupwallet(tmpdir + "/hd.bak")
|
||||
#self.nodes[1].dumpwallet(tmpdir + "/hd.dump")
|
||||
|
||||
|
@ -54,7 +54,7 @@ class WalletHDTest(BitcoinTestFramework):
|
|||
for i in range(num_hd_adds):
|
||||
hd_add = self.nodes[1].getnewaddress()
|
||||
hd_info = self.nodes[1].validateaddress(hd_add)
|
||||
assert_equal(hd_info["hdkeypath"], "m/0'/0'/"+str(i+1)+"'")
|
||||
assert_equal(hd_info["hdkeypath"], "m/0'/0'/"+str(i)+"'")
|
||||
assert_equal(hd_info["hdmasterkeyid"], masterkeyid)
|
||||
self.nodes[0].sendtoaddress(hd_add, 1)
|
||||
self.nodes[0].generate(1)
|
||||
|
@ -83,7 +83,7 @@ class WalletHDTest(BitcoinTestFramework):
|
|||
for _ in range(num_hd_adds):
|
||||
hd_add_2 = self.nodes[1].getnewaddress()
|
||||
hd_info_2 = self.nodes[1].validateaddress(hd_add_2)
|
||||
assert_equal(hd_info_2["hdkeypath"], "m/0'/0'/"+str(_+1)+"'")
|
||||
assert_equal(hd_info_2["hdkeypath"], "m/0'/0'/"+str(_)+"'")
|
||||
assert_equal(hd_info_2["hdmasterkeyid"], masterkeyid)
|
||||
assert_equal(hd_add, hd_add_2)
|
||||
connect_nodes_bi(self.nodes, 0, 1)
|
||||
|
@ -101,7 +101,7 @@ class WalletHDTest(BitcoinTestFramework):
|
|||
for out in outs:
|
||||
if out['value'] != 1:
|
||||
keypath = self.nodes[1].validateaddress(out['scriptPubKey']['addresses'][0])['hdkeypath']
|
||||
|
||||
|
||||
assert_equal(keypath[0:7], "m/0'/1'")
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
Loading…
Reference in a new issue