Browse Source

improve wallet load time by removing duplicated calls to EC_KEY_check_key and adding a hash for vchPubKey/vchPrivKey entries in wallet.dat

backwards compatible with previous wallet.dat format
0.10
patrick s 11 years ago
parent
commit
6e51b3bddf
  1. 17
      src/key.cpp
  2. 3
      src/key.h
  3. 32
      src/walletdb.cpp
  4. 10
      src/walletdb.h

17
src/key.cpp

@ -166,9 +166,12 @@ public: @@ -166,9 +166,12 @@ public:
assert(nSize == nSize2);
}
bool SetPrivKey(const CPrivKey &privkey) {
bool SetPrivKey(const CPrivKey &privkey, bool fSkipCheck=false) {
const unsigned char* pbegin = &privkey[0];
if (d2i_ECPrivateKey(&pkey, &pbegin, privkey.size())) {
if(fSkipCheck)
return true;
// d2i_ECPrivateKey returns true if parsing succeeds.
// This doesn't necessarily mean the key is valid.
if (EC_KEY_check_key(pkey))
@ -409,6 +412,18 @@ bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig) @@ -409,6 +412,18 @@ bool CKey::SignCompact(const uint256 &hash, std::vector<unsigned char>& vchSig)
return true;
}
bool CKey::Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck=false) {
CECKey key;
if (!key.SetPrivKey(privkey, fSkipCheck))
return false;
key.GetSecretBytes(vch);
fCompressed = vchPubKey.IsCompressed();
fValid = true;
return true;
}
bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const {
if (!IsValid())
return false;

3
src/key.h

@ -261,6 +261,9 @@ public: @@ -261,6 +261,9 @@ public:
// Derive BIP32 child key.
bool Derive(CKey& keyChild, unsigned char ccChild[32], unsigned int nChild, const unsigned char cc[32]) const;
// Load private key and check that public key matches.
bool Load(CPrivKey &privkey, CPubKey &vchPubKey, bool fSkipCheck);
};
struct CExtPubKey {

32
src/walletdb.cpp

@ -306,6 +306,8 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, @@ -306,6 +306,8 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
}
CKey key;
CPrivKey pkey;
uint256 hash = 0;
if (strType == "key")
{
wss.nKeys++;
@ -315,14 +317,34 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, @@ -315,14 +317,34 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
ssValue >> wkey;
pkey = wkey.vchPrivKey;
}
if (!key.SetPrivKey(pkey, vchPubKey.IsCompressed()))
try
{
strErr = "Error reading wallet database: CPrivKey corrupt";
return false;
ssValue >> hash;
}
catch(...){}
bool fSkipCheck = false;
if (hash != 0)
{
// hash pubkey/privkey to accelerate wallet load
std::vector<unsigned char> vchKey;
vchKey.reserve(vchPubKey.size() + pkey.size());
vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
vchKey.insert(vchKey.end(), pkey.begin(), pkey.end());
if (Hash(vchKey.begin(), vchKey.end()) != hash)
{
strErr = "Error reading wallet database: CPubKey/CPrivKey corrupt";
return false;
}
fSkipCheck = true;
}
if (key.GetPubKey() != vchPubKey)
if (!key.Load(pkey, vchPubKey, fSkipCheck))
{
strErr = "Error reading wallet database: CPrivKey pubkey inconsistency";
strErr = "Error reading wallet database: CPrivKey corrupt";
return false;
}
if (!pwallet->LoadKey(key, vchPubKey))

10
src/walletdb.h

@ -93,8 +93,14 @@ public: @@ -93,8 +93,14 @@ public:
if (!Write(std::make_pair(std::string("keymeta"), vchPubKey),
keyMeta))
return false;
return Write(std::make_pair(std::string("key"), vchPubKey), vchPrivKey, false);
// hash pubkey/privkey to accelerate wallet load
std::vector<unsigned char> vchKey;
vchKey.reserve(vchPubKey.size() + vchPrivKey.size());
vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
vchKey.insert(vchKey.end(), vchPrivKey.begin(), vchPrivKey.end());
return Write(std::make_pair(std::string("key"), vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey.begin(), vchKey.end())), false);
}
bool WriteCryptedKey(const CPubKey& vchPubKey,

Loading…
Cancel
Save