Merge pull request #2950 from pstratem/walletload

Walletload
This commit is contained in:
Gavin Andresen 2013-10-16 20:12:38 -07:00
commit 796e7b7aec
4 changed files with 67 additions and 9 deletions

View file

@ -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))
@ -411,6 +414,24 @@ 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;
if (fSkipCheck)
return true;
if (GetPubKey() != vchPubKey)
return false;
return true;
}
bool CPubKey::Verify(const uint256 &hash, const std::vector<unsigned char>& vchSig) const {
if (!IsValid())
return false;

View file

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

View file

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

View file

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