Skip to content

Commit 68f0ab2

Browse files
committed
Merge #19805: wallet: Avoid deserializing unused records when salvaging
0bbe26a wallet: filter for keys only before record deser in salvage (Andrew Chow) 544e12a walletdb: Add KeyFilterFn to ReadKeyValue (Andrew Chow) Pull request description: When salvaging a wallet, the only things that matter are the private keys. It is not necessary to attempt to deserialize any other records, especially if those records are corrupted too. This PR adds a `KeyFilterFn` function callback to `ReadKeyValue` that salvage uses to filter for only the records that it wants. Of course doing it this way also lets us do other filters in the future from other places should we so desire. ACKs for top commit: ryanofsky: Code review ACK 0bbe26a. Looks great! This should make the recovery code more robust. Normally it'd be good to have a test case for the problem this fixes, but Marco already wrote one in #19078, so I think we're covered laanwj: Code review ACK 0bbe26a Tree-SHA512: 8e3ee283a22a79273915711c4fb751f3c9b02ce94e6bf08dc468f1cfdf9fac35c693bbfd2435ce43c3a06c601b9b0a67e209621f6814bedfe3bc7a7ccc37bb01
2 parents 136fe4c + 0bbe26a commit 68f0ab2

File tree

3 files changed

+18
-6
lines changed

3 files changed

+18
-6
lines changed

src/wallet/salvage.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ static const char *HEADER_END = "HEADER=END";
1616
static const char *DATA_END = "DATA=END";
1717
typedef std::pair<std::vector<unsigned char>, std::vector<unsigned char> > KeyValPair;
1818

19+
static bool KeyFilter(const std::string& type)
20+
{
21+
return WalletBatch::IsKeyType(type) || type == DBKeys::HDCHAIN;
22+
}
23+
1924
bool RecoverDatabaseFile(const fs::path& file_path, bilingual_str& error, std::vector<bilingual_str>& warnings)
2025
{
2126
std::string filename;
@@ -129,9 +134,9 @@ bool RecoverDatabaseFile(const fs::path& file_path, bilingual_str& error, std::v
129134
{
130135
// Required in LoadKeyMetadata():
131136
LOCK(dummyWallet.cs_wallet);
132-
fReadOK = ReadKeyValue(&dummyWallet, ssKey, ssValue, strType, strErr);
137+
fReadOK = ReadKeyValue(&dummyWallet, ssKey, ssValue, strType, strErr, KeyFilter);
133138
}
134-
if (!WalletBatch::IsKeyType(strType) && strType != DBKeys::HDCHAIN) {
139+
if (!KeyFilter(strType)) {
135140
continue;
136141
}
137142
if (!fReadOK)

src/wallet/walletdb.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -263,13 +263,17 @@ class CWalletScanState {
263263

264264
static bool
265265
ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
266-
CWalletScanState &wss, std::string& strType, std::string& strErr) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
266+
CWalletScanState &wss, std::string& strType, std::string& strErr, const KeyFilterFn& filter_fn = nullptr) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
267267
{
268268
try {
269269
// Unserialize
270270
// Taking advantage of the fact that pair serialization
271271
// is just the two items serialized one after the other
272272
ssKey >> strType;
273+
// If we have a filter, check if this matches the filter
274+
if (filter_fn && !filter_fn(strType)) {
275+
return true;
276+
}
273277
if (strType == DBKeys::NAME) {
274278
std::string strAddress;
275279
ssKey >> strAddress;
@@ -668,11 +672,11 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
668672
return true;
669673
}
670674

671-
bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, std::string& strType, std::string& strErr)
675+
bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, std::string& strType, std::string& strErr, const KeyFilterFn& filter_fn)
672676
{
673677
CWalletScanState dummy_wss;
674678
LOCK(pwallet->cs_wallet);
675-
return ReadKeyValue(pwallet, ssKey, ssValue, dummy_wss, strType, strErr);
679+
return ReadKeyValue(pwallet, ssKey, ssValue, dummy_wss, strType, strErr, filter_fn);
676680
}
677681

678682
bool WalletBatch::IsKeyType(const std::string& strType)

src/wallet/walletdb.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,8 +279,11 @@ class WalletBatch
279279
//! Compacts BDB state so that wallet.dat is self-contained (if there are changes)
280280
void MaybeCompactWalletDB();
281281

282+
//! Callback for filtering key types to deserialize in ReadKeyValue
283+
using KeyFilterFn = std::function<bool(const std::string&)>;
284+
282285
//! Unserialize a given Key-Value pair and load it into the wallet
283-
bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, std::string& strType, std::string& strErr);
286+
bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, std::string& strType, std::string& strErr, const KeyFilterFn& filter_fn = nullptr);
284287

285288
/** Return whether a wallet database is currently loaded. */
286289
bool IsWalletLoaded(const fs::path& wallet_path);

0 commit comments

Comments
 (0)