Browse Source

Remove vchDefaultKey and have better first run detection

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 will now also check for a valid defaultkey for backwards
compatibility reasons and to check for any corruption.

Keys will stil be generated on the first one, but there won't be
any shown in the address book as was previously done.
0.16
Andrew Chow 7 years ago
parent
commit
e53615b443
  1. 2
      src/wallet/crypter.h
  2. 26
      src/wallet/wallet.cpp
  3. 4
      src/wallet/wallet.h
  4. 17
      src/wallet/walletdb.cpp
  5. 2
      src/wallet/walletdb.h
  6. 2
      test/functional/keypool-topup.py
  7. 8
      test/functional/wallet-hd.py

2
src/wallet/crypter.h

@ -113,7 +113,6 @@ public:
class CCryptoKeyStore : public CBasicKeyStore class CCryptoKeyStore : public CBasicKeyStore
{ {
private: private:
CryptedKeyMap mapCryptedKeys;
CKeyingMaterial vMasterKey; CKeyingMaterial vMasterKey;
@ -131,6 +130,7 @@ protected:
bool EncryptKeys(CKeyingMaterial& vMasterKeyIn); bool EncryptKeys(CKeyingMaterial& vMasterKeyIn);
bool Unlock(const CKeyingMaterial& vMasterKeyIn); bool Unlock(const CKeyingMaterial& vMasterKeyIn);
CryptedKeyMap mapCryptedKeys;
public: public:
CCryptoKeyStore() : fUseCrypto(false), fDecryptionThoroughlyChecked(false) CCryptoKeyStore() : fUseCrypto(false), fDecryptionThoroughlyChecked(false)

26
src/wallet/wallet.cpp

@ -3114,9 +3114,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) if (nLoadWalletRet != DB_LOAD_OK)
return nLoadWalletRet; return nLoadWalletRet;
fFirstRunRet = !vchDefaultKey.IsValid();
uiInterface.LoadWallet(this); uiInterface.LoadWallet(this);
@ -3126,7 +3128,6 @@ DBErrors CWallet::LoadWallet(bool& fFirstRunRet)
DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut) DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256>& vHashOut)
{ {
AssertLockHeld(cs_wallet); // mapWallet AssertLockHeld(cs_wallet); // mapWallet
vchDefaultKey = CPubKey();
DBErrors nZapSelectTxRet = CWalletDB(*dbw,"cr+").ZapSelectTx(vHashIn, vHashOut); DBErrors nZapSelectTxRet = CWalletDB(*dbw,"cr+").ZapSelectTx(vHashIn, vHashOut);
for (uint256 hash : vHashOut) for (uint256 hash : vHashOut)
mapWallet.erase(hash); mapWallet.erase(hash);
@ -3155,7 +3156,6 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256
DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx) DBErrors CWallet::ZapWalletTx(std::vector<CWalletTx>& vWtx)
{ {
vchDefaultKey = CPubKey();
DBErrors nZapWalletTxRet = CWalletDB(*dbw,"cr+").ZapWalletTx(vWtx); DBErrors nZapWalletTxRet = CWalletDB(*dbw,"cr+").ZapWalletTx(vWtx);
if (nZapWalletTxRet == DB_NEED_REWRITE) if (nZapWalletTxRet == DB_NEED_REWRITE)
{ {
@ -3231,14 +3231,6 @@ const std::string& CWallet::GetAccountName(const CScript& scriptPubKey) const
return DEFAULT_ACCOUNT_NAME; 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, * Mark old keypool keys as used,
* and generate all new keys * and generate all new keys
@ -4014,13 +4006,11 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
if (!walletInstance->SetHDMasterKey(masterPubKey)) if (!walletInstance->SetHDMasterKey(masterPubKey))
throw std::runtime_error(std::string(__func__) + ": Storing master key failed"); throw std::runtime_error(std::string(__func__) + ": Storing master key failed");
} }
CPubKey newDefaultKey;
if (walletInstance->GetKeyFromPool(newDefaultKey, false)) { // Top up the keypool
walletInstance->SetDefaultKey(newDefaultKey); if (!walletInstance->TopUpKeyPool()) {
if (!walletInstance->SetAddressBook(walletInstance->vchDefaultKey.GetID(), "", "receive")) { InitError(_("Unable to generate initial keys") += "\n");
InitError(_("Cannot write default address") += "\n"); return NULL;
return nullptr;
}
} }
walletInstance->SetBestChain(chainActive.GetLocator()); walletInstance->SetBestChain(chainActive.GetLocator());

4
src/wallet/wallet.h

@ -807,8 +807,6 @@ public:
std::map<CTxDestination, CAddressBookData> mapAddressBook; std::map<CTxDestination, CAddressBookData> mapAddressBook;
CPubKey vchDefaultKey;
std::set<COutPoint> setLockedCoins; std::set<COutPoint> setLockedCoins;
const CWalletTx* GetWalletTx(const uint256& hash) const; const CWalletTx* GetWalletTx(const uint256& hash) const;
@ -1040,8 +1038,6 @@ public:
return setInternalKeyPool.size() + setExternalKeyPool.size(); 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 //! 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); bool SetMinVersion(enum WalletFeature, CWalletDB* pwalletdbIn = nullptr, bool fExplicit = false);

17
src/wallet/walletdb.cpp

@ -130,11 +130,6 @@ bool CWalletDB::WriteOrderPosNext(int64_t nOrderPosNext)
return WriteIC(std::string("orderposnext"), 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) bool CWalletDB::ReadPool(int64_t nPool, CKeyPool& keypool)
{ {
return batch.Read(std::make_pair(std::string("pool"), nPool), 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") 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") else if (strType == "pool")
{ {
@ -522,7 +524,6 @@ bool CWalletDB::IsKeyType(const std::string& strType)
DBErrors CWalletDB::LoadWallet(CWallet* pwallet) DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
{ {
pwallet->vchDefaultKey = CPubKey();
CWalletScanState wss; CWalletScanState wss;
bool fNoncriticalErrors = false; bool fNoncriticalErrors = false;
DBErrors result = DB_LOAD_OK; DBErrors result = DB_LOAD_OK;
@ -565,7 +566,7 @@ DBErrors CWalletDB::LoadWallet(CWallet* pwallet)
{ {
// losing keys is considered a catastrophic error, anything else // losing keys is considered a catastrophic error, anything else
// we assume the user can live with: // we assume the user can live with:
if (IsKeyType(strType)) if (IsKeyType(strType) || strType == "defaultkey")
result = DB_CORRUPT; result = DB_CORRUPT;
else else
{ {

2
src/wallet/walletdb.h

@ -191,8 +191,6 @@ public:
bool WriteOrderPosNext(int64_t nOrderPosNext); bool WriteOrderPosNext(int64_t nOrderPosNext);
bool WriteDefaultKey(const CPubKey& vchPubKey);
bool ReadPool(int64_t nPool, CKeyPool& keypool); bool ReadPool(int64_t nPool, CKeyPool& keypool);
bool WritePool(int64_t nPool, const CKeyPool& keypool); bool WritePool(int64_t nPool, const CKeyPool& keypool);
bool ErasePool(int64_t nPool); bool ErasePool(int64_t nPool);

2
test/functional/keypool-topup.py

@ -69,7 +69,7 @@ class KeypoolRestoreTest(BitcoinTestFramework):
assert_equal(self.nodes[1].listtransactions()[0]['category'], "receive") assert_equal(self.nodes[1].listtransactions()[0]['category'], "receive")
# Check that we have marked all keys up to the used keypool key as used # 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__': if __name__ == '__main__':
KeypoolRestoreTest().main() KeypoolRestoreTest().main()

8
test/functional/wallet-hd.py

@ -42,7 +42,7 @@ class WalletHDTest(BitcoinTestFramework):
non_hd_add = self.nodes[0].getnewaddress() non_hd_add = self.nodes[0].getnewaddress()
self.nodes[1].importprivkey(self.nodes[0].dumpprivkey(non_hd_add)) 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].backupwallet(tmpdir + "/hd.bak")
#self.nodes[1].dumpwallet(tmpdir + "/hd.dump") #self.nodes[1].dumpwallet(tmpdir + "/hd.dump")
@ -54,7 +54,7 @@ class WalletHDTest(BitcoinTestFramework):
for i in range(num_hd_adds): for i in range(num_hd_adds):
hd_add = self.nodes[1].getnewaddress() hd_add = self.nodes[1].getnewaddress()
hd_info = self.nodes[1].validateaddress(hd_add) 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) assert_equal(hd_info["hdmasterkeyid"], masterkeyid)
self.nodes[0].sendtoaddress(hd_add, 1) self.nodes[0].sendtoaddress(hd_add, 1)
self.nodes[0].generate(1) self.nodes[0].generate(1)
@ -83,7 +83,7 @@ class WalletHDTest(BitcoinTestFramework):
for _ in range(num_hd_adds): for _ in range(num_hd_adds):
hd_add_2 = self.nodes[1].getnewaddress() hd_add_2 = self.nodes[1].getnewaddress()
hd_info_2 = self.nodes[1].validateaddress(hd_add_2) 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_info_2["hdmasterkeyid"], masterkeyid)
assert_equal(hd_add, hd_add_2) assert_equal(hd_add, hd_add_2)
connect_nodes_bi(self.nodes, 0, 1) connect_nodes_bi(self.nodes, 0, 1)
@ -101,7 +101,7 @@ class WalletHDTest(BitcoinTestFramework):
for out in outs: for out in outs:
if out['value'] != 1: if out['value'] != 1:
keypath = self.nodes[1].validateaddress(out['scriptPubKey']['addresses'][0])['hdkeypath'] keypath = self.nodes[1].validateaddress(out['scriptPubKey']['addresses'][0])['hdkeypath']
assert_equal(keypath[0:7], "m/0'/1'") assert_equal(keypath[0:7], "m/0'/1'")
if __name__ == '__main__': if __name__ == '__main__':

Loading…
Cancel
Save