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
This commit is contained in:
patrick s 2013-08-28 23:53:26 -07:00
parent ff33a3470d
commit 6e51b3bddf
4 changed files with 55 additions and 9 deletions

View File

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

View File

@ -261,6 +261,9 @@ public:
// Derive BIP32 child key. // Derive BIP32 child key.
bool Derive(CKey& keyChild, unsigned char ccChild[32], unsigned int nChild, const unsigned char cc[32]) const; 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 { struct CExtPubKey {

View File

@ -306,6 +306,8 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
} }
CKey key; CKey key;
CPrivKey pkey; CPrivKey pkey;
uint256 hash = 0;
if (strType == "key") if (strType == "key")
{ {
wss.nKeys++; wss.nKeys++;
@ -315,14 +317,34 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
ssValue >> wkey; ssValue >> wkey;
pkey = wkey.vchPrivKey; pkey = wkey.vchPrivKey;
} }
if (!key.SetPrivKey(pkey, vchPubKey.IsCompressed())) try
{ {
strErr = "Error reading wallet database: CPrivKey corrupt"; 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; return false;
} }
if (key.GetPubKey() != vchPubKey)
fSkipCheck = true;
}
if (!key.Load(pkey, vchPubKey, fSkipCheck))
{ {
strErr = "Error reading wallet database: CPrivKey pubkey inconsistency"; strErr = "Error reading wallet database: CPrivKey corrupt";
return false; return false;
} }
if (!pwallet->LoadKey(key, vchPubKey)) if (!pwallet->LoadKey(key, vchPubKey))

View File

@ -94,7 +94,13 @@ public:
keyMeta)) keyMeta))
return false; 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, bool WriteCryptedKey(const CPubKey& vchPubKey,