Browse Source

Merge pull request #2950 from pstratem/walletload

Walletload
0.10
Gavin Andresen 11 years ago
parent
commit
796e7b7aec
  1. 23
      src/key.cpp
  2. 3
      src/key.h
  3. 36
      src/walletdb.cpp
  4. 8
      src/walletdb.h

23
src/key.cpp

@ -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))
@ -411,6 +414,24 @@ 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;
if (fSkipCheck)
return true;
if (GetPubKey() != vchPubKey)
return false;
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;

3
src/key.h

@ -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 {

36
src/walletdb.cpp

@ -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,40 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
ssValue >> wkey; ssValue >> wkey;
pkey = wkey.vchPrivKey; pkey = wkey.vchPrivKey;
} }
if (!key.SetPrivKey(pkey, vchPubKey.IsCompressed()))
// Old wallets store keys as "key" [pubkey] => [privkey]
// ... which was slow for wallets with lots of keys, because the public key is re-derived from the private key
// using EC operations as a checksum.
// Newer wallets store keys as "key"[pubkey] => [privkey][hash(pubkey,privkey)], which is much faster while
// remaining backwards-compatible.
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))

8
src/walletdb.h

@ -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,

Loading…
Cancel
Save