Skip to content

Commit 052e7fc

Browse files
PastaPastaPastalaanwjUdjinM6
authored
Merge bitcoin#10952: [wallet] Remove vchDefaultKey and have better first run… (#3319)
* Merge bitcoin#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 * Update src/wallet/wallet.cpp Co-Authored-By: UdjinM6 <UdjinM6@users.noreply.github.com> Co-authored-by: Wladimir J. van der Laan <laanwj@gmail.com> Co-authored-by: UdjinM6 <UdjinM6@users.noreply.github.com>
1 parent 0294caa commit 052e7fc

File tree

7 files changed

+20
-36
lines changed

7 files changed

+20
-36
lines changed

src/wallet/crypter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,6 @@ bool DecryptAES256(const SecureString& sKey, const std::string& sCiphertext, con
119119
class CCryptoKeyStore : public CBasicKeyStore
120120
{
121121
private:
122-
CryptedKeyMap mapCryptedKeys;
123122
CHDChain cryptedHDChain;
124123

125124
CKeyingMaterial vMasterKey;
@@ -146,6 +145,7 @@ class CCryptoKeyStore : public CBasicKeyStore
146145
bool SetCryptedHDChain(const CHDChain& chain);
147146

148147
bool Unlock(const CKeyingMaterial& vMasterKeyIn, bool fForMixingOnly = false);
148+
CryptedKeyMap mapCryptedKeys;
149149

150150
public:
151151
CCryptoKeyStore() : fUseCrypto(false), fDecryptionThoroughlyChecked(false), fOnlyMixingAllowed(false)

src/wallet/wallet.cpp

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4077,6 +4077,9 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
40774077
}
40784078
}
40794079

4080+
// This wallet is in its first run if all of these are empty
4081+
fFirstRunRet = mapKeys.empty() && mapHdPubKeys.empty() && mapCryptedKeys.empty() && mapWatchKeys.empty() && setWatchOnly.empty() && mapScripts.empty();
4082+
40804083
{
40814084
LOCK2(cs_main, cs_wallet);
40824085
for (auto& pair : mapWallet) {
@@ -4090,7 +4093,6 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
40904093

40914094
if (nLoadWalletRet != DB_LOAD_OK)
40924095
return nLoadWalletRet;
4093-
fFirstRunRet = !vchDefaultKey.IsValid();
40944096

40954097
uiInterface.LoadWallet(this);
40964098

@@ -4118,7 +4120,6 @@ void CWallet::AutoLockMasternodeCollaterals()
41184120
DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut)
41194121
{
41204122
AssertLockHeld(cs_wallet); // mapWallet
4121-
vchDefaultKey = CPubKey();
41224123
DBErrors nZapSelectTxRet = CWalletDB(*dbw,"cr+").ZapSelectTx(vHashIn, vHashOut);
41234124
for (uint256 hash : vHashOut)
41244125
mapWallet.erase(hash);
@@ -4147,7 +4148,6 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256
41474148

41484149
DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
41494150
{
4150-
vchDefaultKey = CPubKey();
41514151
DBErrors nZapWalletTxRet = CWalletDB(*dbw,"cr+").ZapWalletTx(vWtx);
41524152
if (nZapWalletTxRet == DB_NEED_REWRITE)
41534153
{
@@ -4224,14 +4224,6 @@ const std::string& CWallet::GetAccountName(const CScript& scriptPubKey) const
42244224
return DEFAULT_ACCOUNT_NAME;
42254225
}
42264226

4227-
bool CWallet::SetDefaultKey(const CPubKey &vchPubKey)
4228-
{
4229-
if (!CWalletDB(*dbw).WriteDefaultKey(vchPubKey))
4230-
return false;
4231-
vchDefaultKey = vchPubKey;
4232-
return true;
4233-
}
4234-
42354227
/**
42364228
* Mark old keypool keys as used,
42374229
* and generate all new keys
@@ -5011,13 +5003,10 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
50115003
walletInstance->SetMinVersion(FEATURE_HD);
50125004
}
50135005

5014-
CPubKey newDefaultKey;
5015-
if (walletInstance->GetKeyFromPool(newDefaultKey, false)) {
5016-
walletInstance->SetDefaultKey(newDefaultKey);
5017-
if (!walletInstance->SetAddressBook(walletInstance->vchDefaultKey.GetID(), "", "receive")) {
5018-
InitError(_("Cannot write default address") += "\n");
5019-
return nullptr;
5020-
}
5006+
// Top up the keypool
5007+
if (!walletInstance->TopUpKeyPool()) {
5008+
InitError(_("Unable to generate initial keys") += "\n");
5009+
return nullptr;
50215010
}
50225011

50235012
walletInstance->SetBestChain(chainActive.GetLocator());

src/wallet/wallet.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -869,8 +869,6 @@ class CWallet final : public CCryptoKeyStore, public CValidationInterface
869869

870870
std::map<CTxDestination, CAddressBookData> mapAddressBook;
871871

872-
CPubKey vchDefaultKey;
873-
874872
std::set<COutPoint> setLockedCoins;
875873

876874
int64_t nKeysLeftSinceAutoBackup;
@@ -1139,8 +1137,6 @@ class CWallet final : public CCryptoKeyStore, public CValidationInterface
11391137
return setInternalKeyPool.size() + setExternalKeyPool.size();
11401138
}
11411139

1142-
bool SetDefaultKey(const CPubKey &vchPubKey);
1143-
11441140
//! signify that a particular wallet feature is now used. this may change nWalletVersion and nWalletMaxVersion if those are lower
11451141
bool SetMinVersion(enum WalletFeature, CWalletDB* pwalletdbIn = nullptr, bool fExplicit = false);
11461142

src/wallet/walletdb.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -132,11 +132,6 @@ bool CWalletDB::WriteOrderPosNext(int64_t nOrderPosNext)
132132
return WriteIC(std::string("orderposnext"), nOrderPosNext);
133133
}
134134

135-
bool CWalletDB::WriteDefaultKey(const CPubKey& vchPubKey)
136-
{
137-
return WriteIC(std::string("defaultkey"), vchPubKey);
138-
}
139-
140135
bool CWalletDB::ReadPool(int64_t nPool, CKeyPool& keypool)
141136
{
142137
return batch.Read(std::make_pair(std::string("pool"), nPool), keypool);
@@ -454,7 +449,14 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
454449
}
455450
else if (strType == "defaultkey")
456451
{
457-
ssValue >> pwallet->vchDefaultKey;
452+
// We don't want or need the default key, but if there is one set,
453+
// we want to make sure that it is valid so that we can detect corruption
454+
CPubKey vchPubKey;
455+
ssValue >> vchPubKey;
456+
if (!vchPubKey.IsValid()) {
457+
strErr = "Error reading wallet database: Default Key corrupt";
458+
return false;
459+
}
458460
}
459461
else if (strType == "pool")
460462
{
@@ -553,7 +555,6 @@ bool CWalletDB::IsKeyType(const std::string& strType)
553555

554556
DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
555557
{
556-
pwallet->vchDefaultKey = CPubKey();
557558
CWalletScanState wss;
558559
bool fNoncriticalErrors = false;
559560
DBErrors result = DB_LOAD_OK;
@@ -596,7 +597,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
596597
{
597598
// losing keys is considered a catastrophic error, anything else
598599
// we assume the user can live with:
599-
if (IsKeyType(strType))
600+
if (IsKeyType(strType) || strType == "defaultkey")
600601
result = DB_CORRUPT;
601602
else
602603
{

src/wallet/walletdb.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,6 @@ class CWalletDB
148148

149149
bool WriteOrderPosNext(int64_t nOrderPosNext);
150150

151-
bool WriteDefaultKey(const CPubKey& vchPubKey);
152-
153151
bool ReadPool(int64_t nPool, CKeyPool& keypool);
154152
bool WritePool(int64_t nPool, const CKeyPool& keypool);
155153
bool ErasePool(int64_t nPool);

test/functional/keypool-topup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def run_test(self):
7070
assert_equal(self.nodes[1].listtransactions()[0]['category'], "receive")
7171

7272
# Check that we have marked all keys up to the used keypool key as used
73-
assert_equal(self.nodes[1].validateaddress(self.nodes[1].getnewaddress())['hdkeypath'], "m/44'/1'/0'/0/111")
73+
assert_equal(self.nodes[1].validateaddress(self.nodes[1].getnewaddress())['hdkeypath'], "m/44'/1'/0'/0/110")
7474

7575
if __name__ == '__main__':
7676
KeypoolRestoreTest().main()

test/functional/wallet-hd.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def run_test (self):
5555
for i in range(num_hd_adds):
5656
hd_add = self.nodes[1].getnewaddress()
5757
hd_info = self.nodes[1].validateaddress(hd_add)
58-
assert_equal(hd_info["hdkeypath"], "m/44'/1'/0'/0/"+str(i+1))
58+
assert_equal(hd_info["hdkeypath"], "m/44'/1'/0'/0/"+str(i))
5959
assert_equal(hd_info["hdchainid"], chainid)
6060
self.nodes[0].sendtoaddress(hd_add, 1)
6161
self.nodes[0].generate(1)
@@ -86,7 +86,7 @@ def run_test (self):
8686
for _ in range(num_hd_adds):
8787
hd_add_2 = self.nodes[1].getnewaddress()
8888
hd_info_2 = self.nodes[1].validateaddress(hd_add_2)
89-
assert_equal(hd_info_2["hdkeypath"], "m/44'/1'/0'/0/"+str(_+1))
89+
assert_equal(hd_info_2["hdkeypath"], "m/44'/1'/0'/0/"+str(_))
9090
assert_equal(hd_info_2["hdchainid"], chainid)
9191
assert_equal(hd_add, hd_add_2)
9292
connect_nodes_bi(self.nodes, 0, 1)

0 commit comments

Comments
 (0)