Skip to content

Commit 7be10ad

Browse files
committed
walletdb: Refactor key reading and loading to its own function
1 parent 52932c5 commit 7be10ad

File tree

2 files changed

+69
-53
lines changed

2 files changed

+69
-53
lines changed

src/wallet/walletdb.cpp

Lines changed: 67 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,72 @@ class CWalletScanState {
320320
CWalletScanState() = default;
321321
};
322322

323+
bool LoadKey(CWallet* pwallet, DataStream& ssKey, DataStream& ssValue, std::string& strErr)
324+
{
325+
LOCK(pwallet->cs_wallet);
326+
try {
327+
CPubKey vchPubKey;
328+
ssKey >> vchPubKey;
329+
if (!vchPubKey.IsValid())
330+
{
331+
strErr = "Error reading wallet database: CPubKey corrupt";
332+
return false;
333+
}
334+
CKey key;
335+
CPrivKey pkey;
336+
uint256 hash;
337+
338+
ssValue >> pkey;
339+
340+
// Old wallets store keys as DBKeys::KEY [pubkey] => [privkey]
341+
// ... which was slow for wallets with lots of keys, because the public key is re-derived from the private key
342+
// using EC operations as a checksum.
343+
// Newer wallets store keys as DBKeys::KEY [pubkey] => [privkey][hash(pubkey,privkey)], which is much faster while
344+
// remaining backwards-compatible.
345+
try
346+
{
347+
ssValue >> hash;
348+
}
349+
catch (const std::ios_base::failure&) {}
350+
351+
bool fSkipCheck = false;
352+
353+
if (!hash.IsNull())
354+
{
355+
// hash pubkey/privkey to accelerate wallet load
356+
std::vector<unsigned char> vchKey;
357+
vchKey.reserve(vchPubKey.size() + pkey.size());
358+
vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
359+
vchKey.insert(vchKey.end(), pkey.begin(), pkey.end());
360+
361+
if (Hash(vchKey) != hash)
362+
{
363+
strErr = "Error reading wallet database: CPubKey/CPrivKey corrupt";
364+
return false;
365+
}
366+
367+
fSkipCheck = true;
368+
}
369+
370+
if (!key.Load(pkey, vchPubKey, fSkipCheck))
371+
{
372+
strErr = "Error reading wallet database: CPrivKey corrupt";
373+
return false;
374+
}
375+
if (!pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadKey(key, vchPubKey))
376+
{
377+
strErr = "Error reading wallet database: LegacyScriptPubKeyMan::LoadKey failed";
378+
return false;
379+
}
380+
} catch (const std::exception& e) {
381+
if (strErr.empty()) {
382+
strErr = e.what();
383+
}
384+
return false;
385+
}
386+
return true;
387+
}
388+
323389
static bool
324390
ReadKeyValue(CWallet* pwallet, DataStream& ssKey, CDataStream& ssValue,
325391
CWalletScanState &wss, std::string& strType, std::string& strErr, const KeyFilterFn& filter_fn = nullptr) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
@@ -410,60 +476,8 @@ ReadKeyValue(CWallet* pwallet, DataStream& ssKey, CDataStream& ssValue,
410476
pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadWatchOnly(script);
411477
}
412478
} else if (strType == DBKeys::KEY) {
413-
CPubKey vchPubKey;
414-
ssKey >> vchPubKey;
415-
if (!vchPubKey.IsValid())
416-
{
417-
strErr = "Error reading wallet database: CPubKey corrupt";
418-
return false;
419-
}
420-
CKey key;
421-
CPrivKey pkey;
422-
uint256 hash;
423-
424479
wss.nKeys++;
425-
ssValue >> pkey;
426-
427-
// Old wallets store keys as DBKeys::KEY [pubkey] => [privkey]
428-
// ... which was slow for wallets with lots of keys, because the public key is re-derived from the private key
429-
// using EC operations as a checksum.
430-
// Newer wallets store keys as DBKeys::KEY [pubkey] => [privkey][hash(pubkey,privkey)], which is much faster while
431-
// remaining backwards-compatible.
432-
try
433-
{
434-
ssValue >> hash;
435-
}
436-
catch (const std::ios_base::failure&) {}
437-
438-
bool fSkipCheck = false;
439-
440-
if (!hash.IsNull())
441-
{
442-
// hash pubkey/privkey to accelerate wallet load
443-
std::vector<unsigned char> vchKey;
444-
vchKey.reserve(vchPubKey.size() + pkey.size());
445-
vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end());
446-
vchKey.insert(vchKey.end(), pkey.begin(), pkey.end());
447-
448-
if (Hash(vchKey) != hash)
449-
{
450-
strErr = "Error reading wallet database: CPubKey/CPrivKey corrupt";
451-
return false;
452-
}
453-
454-
fSkipCheck = true;
455-
}
456-
457-
if (!key.Load(pkey, vchPubKey, fSkipCheck))
458-
{
459-
strErr = "Error reading wallet database: CPrivKey corrupt";
460-
return false;
461-
}
462-
if (!pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadKey(key, vchPubKey))
463-
{
464-
strErr = "Error reading wallet database: LegacyScriptPubKeyMan::LoadKey failed";
465-
return false;
466-
}
480+
if (!LoadKey(pwallet, ssKey, ssValue, strErr)) return false;
467481
} else if (strType == DBKeys::MASTER_KEY) {
468482
// Master encryption key is loaded into only the wallet and not any of the ScriptPubKeyMans.
469483
unsigned int nID;

src/wallet/walletdb.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,8 @@ using KeyFilterFn = std::function<bool(const std::string&)>;
305305

306306
//! Unserialize a given Key-Value pair and load it into the wallet
307307
bool ReadKeyValue(CWallet* pwallet, DataStream& ssKey, CDataStream& ssValue, std::string& strType, std::string& strErr, const KeyFilterFn& filter_fn = nullptr);
308+
309+
bool LoadKey(CWallet* pwallet, DataStream& ssKey, DataStream& ssValue, std::string& strErr);
308310
} // namespace wallet
309311

310312
#endif // BITCOIN_WALLET_WALLETDB_H

0 commit comments

Comments
 (0)