0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-02-08 10:31:50 -05:00

walletdb: Remove loading code where the database is iterated

Instead of iterating the database to load the wallet, we now load
particular kinds of records in an order that we want them to be loaded.
So it is no longer necessary to iterate the entire database to load the
wallet.
This commit is contained in:
Andrew Chow 2022-04-18 14:56:23 -04:00 committed by Andrew Chow
parent cd211b3b99
commit 2636844f53

View file

@ -298,13 +298,6 @@ bool WalletBatch::EraseLockedUTXO(const COutPoint& output)
return EraseIC(std::make_pair(DBKeys::LOCKED_UTXO, std::make_pair(output.hash, output.n)));
}
class CWalletScanState {
public:
unsigned int m_unknown_records{0};
CWalletScanState() = default;
};
bool LoadKey(CWallet* pwallet, DataStream& ssKey, DataStream& ssValue, std::string& strErr)
{
LOCK(pwallet->cs_wallet);
@ -453,61 +446,6 @@ bool LoadHDChain(CWallet* pwallet, DataStream& ssValue, std::string& strErr)
return true;
}
static bool
ReadKeyValue(CWallet* pwallet, DataStream& ssKey, CDataStream& ssValue,
CWalletScanState &wss, std::string& strType, std::string& strErr) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
{
try {
// Unserialize
// Taking advantage of the fact that pair serialization
// is just the two items serialized one after the other
ssKey >> strType;
if (pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS) && DBKeys::LEGACY_TYPES.count(strType) > 0) {
return true;
}
if (strType == DBKeys::NAME) {
} else if (strType == DBKeys::PURPOSE) {
} else if (strType == DBKeys::TX) {
} else if (strType == DBKeys::WATCHS) {
} else if (strType == DBKeys::KEY) {
} else if (strType == DBKeys::MASTER_KEY) {
} else if (strType == DBKeys::CRYPTED_KEY) {
} else if (strType == DBKeys::KEYMETA) {
} else if (strType == DBKeys::WATCHMETA) {
} else if (strType == DBKeys::DEFAULTKEY) {
} else if (strType == DBKeys::POOL) {
} else if (strType == DBKeys::CSCRIPT) {
} else if (strType == DBKeys::ORDERPOSNEXT) {
} else if (strType == DBKeys::DESTDATA) {
} else if (strType == DBKeys::HDCHAIN) {
} else if (strType == DBKeys::OLD_KEY) {
} else if (strType == DBKeys::ACTIVEEXTERNALSPK || strType == DBKeys::ACTIVEINTERNALSPK) {
} else if (strType == DBKeys::WALLETDESCRIPTOR) {
} else if (strType == DBKeys::WALLETDESCRIPTORCACHE) {
} else if (strType == DBKeys::WALLETDESCRIPTORLHCACHE) {
} else if (strType == DBKeys::WALLETDESCRIPTORKEY) {
} else if (strType == DBKeys::WALLETDESCRIPTORCKEY) {
} else if (strType == DBKeys::LOCKED_UTXO) {
} else if (strType != DBKeys::BESTBLOCK && strType != DBKeys::BESTBLOCK_NOMERKLE &&
strType != DBKeys::MINVERSION && strType != DBKeys::ACENTRY &&
strType != DBKeys::VERSION && strType != DBKeys::SETTINGS &&
strType != DBKeys::FLAGS) {
wss.m_unknown_records++;
}
} catch (const std::exception& e) {
if (strErr.empty()) {
strErr = e.what();
}
return false;
} catch (...) {
if (strErr.empty()) {
strErr = "Caught unknown exception in ReadKeyValue";
}
return false;
}
return true;
}
static DBErrors LoadMinVersion(CWallet* pwallet, DatabaseBatch& batch) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
{
AssertLockHeld(pwallet->cs_wallet);
@ -1198,8 +1136,6 @@ static DBErrors LoadDecryptionKeys(CWallet* pwallet, DatabaseBatch& batch) EXCLU
DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
{
CWalletScanState wss;
bool fNoncriticalErrors = false;
DBErrors result = DBErrors::LOAD_OK;
bool any_unordered = false;
std::vector<uint256> upgraded_txs;
@ -1246,49 +1182,12 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
// Load decryption keys
result = std::max(LoadDecryptionKeys(pwallet, *m_batch), result);
// Get cursor
std::unique_ptr<DatabaseCursor> cursor = m_batch->GetNewCursor();
if (!cursor)
{
pwallet->WalletLogPrintf("Error getting wallet database cursor\n");
return DBErrors::CORRUPT;
}
while (true)
{
// Read next record
DataStream ssKey{};
CDataStream ssValue(SER_DISK, CLIENT_VERSION);
DatabaseCursor::Status status = cursor->Next(ssKey, ssValue);
if (status == DatabaseCursor::Status::DONE) {
break;
} else if (status == DatabaseCursor::Status::FAIL) {
cursor.reset();
pwallet->WalletLogPrintf("Error reading next record from wallet database\n");
return DBErrors::CORRUPT;
}
// Try to be tolerant of single corrupt records:
std::string strType, strErr;
if (!ReadKeyValue(pwallet, ssKey, ssValue, wss, strType, strErr))
{
// Leave other errors alone, if we try to fix them we might make things worse.
fNoncriticalErrors = true; // ... but do warn the user there is something wrong.
}
if (!strErr.empty())
pwallet->WalletLogPrintf("%s\n", strErr);
}
} catch (...) {
// Exceptions that can be ignored or treated as non-critical are handled by the individual loading functions.
// Any uncaught exceptions will be caught here and treated as critical.
result = DBErrors::CORRUPT;
}
if (fNoncriticalErrors && result == DBErrors::LOAD_OK) {
result = DBErrors::NONCRITICAL_ERROR;
}
// Any wallet corruption at all: skip any rewriting or
// upgrading, we don't want to make it worse.
if (result != DBErrors::LOAD_OK)