Skip to content

Commit abcc13d

Browse files
committed
walletdb: refactor address book loading
Instead of loading address book records as we come across them when iterating the database, load them explicitly Due to exception handling changes, deserialization errors are now treated as critical. The error message for noncritical errors has also been updated to reflect that there's more data that could be missing than just address book entries and tx data.
1 parent 405b4d9 commit abcc13d

File tree

2 files changed

+65
-33
lines changed

2 files changed

+65
-33
lines changed

src/wallet/wallet.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2929,7 +2929,7 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri
29292929
else if (nLoadWalletRet == DBErrors::NONCRITICAL_ERROR)
29302930
{
29312931
warnings.push_back(strprintf(_("Error reading %s! All keys read correctly, but transaction data"
2932-
" or address book entries might be missing or incorrect."),
2932+
" or address metadata may be missing or incorrect."),
29332933
walletFile));
29342934
}
29352935
else if (nLoadWalletRet == DBErrors::TOO_NEW) {

src/wallet/walletdb.cpp

Lines changed: 64 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -471,21 +471,7 @@ ReadKeyValue(CWallet* pwallet, DataStream& ssKey, CDataStream& ssValue,
471471
return true;
472472
}
473473
if (strType == DBKeys::NAME) {
474-
std::string strAddress;
475-
ssKey >> strAddress;
476-
std::string label;
477-
ssValue >> label;
478-
pwallet->m_address_book[DecodeDestination(strAddress)].SetLabel(label);
479474
} else if (strType == DBKeys::PURPOSE) {
480-
std::string strAddress;
481-
ssKey >> strAddress;
482-
std::string purpose_str;
483-
ssValue >> purpose_str;
484-
std::optional<AddressPurpose> purpose{PurposeFromString(purpose_str)};
485-
if (!purpose) {
486-
pwallet->WalletLogPrintf("Warning: nonstandard purpose string '%s' for address '%s'\n", purpose_str, strAddress);
487-
}
488-
pwallet->m_address_book[DecodeDestination(strAddress)].purpose = purpose;
489475
} else if (strType == DBKeys::TX) {
490476
uint256 hash;
491477
ssKey >> hash;
@@ -553,24 +539,6 @@ ReadKeyValue(CWallet* pwallet, DataStream& ssKey, CDataStream& ssValue,
553539
} else if (strType == DBKeys::ORDERPOSNEXT) {
554540
ssValue >> pwallet->nOrderPosNext;
555541
} else if (strType == DBKeys::DESTDATA) {
556-
std::string strAddress, strKey, strValue;
557-
ssKey >> strAddress;
558-
ssKey >> strKey;
559-
ssValue >> strValue;
560-
const CTxDestination& dest{DecodeDestination(strAddress)};
561-
if (strKey.compare("used") == 0) {
562-
// Load "used" key indicating if an IsMine address has
563-
// previously been spent from with avoid_reuse option enabled.
564-
// The strValue is not used for anything currently, but could
565-
// hold more information in the future. Current values are just
566-
// "1" or "p" for present (which was written prior to
567-
// f5ba424cd44619d9b9be88b8593d69a7ba96db26).
568-
pwallet->LoadAddressPreviouslySpent(dest);
569-
} else if (strKey.compare(0, 2, "rr") == 0) {
570-
// Load "rr##" keys where ## is a decimal number, and strValue
571-
// is a serialized RecentRequestEntry object.
572-
pwallet->LoadAddressReceiveRequest(dest, strKey.substr(2), strValue);
573-
}
574542
} else if (strType == DBKeys::HDCHAIN) {
575543
} else if (strType == DBKeys::OLD_KEY) {
576544
strErr = "Found unsupported 'wkey' record, try loading with version 0.18";
@@ -1083,6 +1051,67 @@ static DBErrors LoadDescriptorWalletRecords(CWallet* pwallet, DatabaseBatch& bat
10831051
return desc_res.m_result;
10841052
}
10851053

1054+
static DBErrors LoadAddressBookRecords(CWallet* pwallet, DatabaseBatch& batch) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
1055+
{
1056+
AssertLockHeld(pwallet->cs_wallet);
1057+
DBErrors result = DBErrors::LOAD_OK;
1058+
1059+
// Load name record
1060+
LoadResult name_res = LoadRecords(pwallet, batch, DBKeys::NAME,
1061+
[] (CWallet* pwallet, DataStream& key, CDataStream& value, std::string& err) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {
1062+
std::string strAddress;
1063+
key >> strAddress;
1064+
std::string label;
1065+
value >> label;
1066+
pwallet->m_address_book[DecodeDestination(strAddress)].SetLabel(label);
1067+
return DBErrors::LOAD_OK;
1068+
});
1069+
result = std::max(result, name_res.m_result);
1070+
1071+
// Load purpose record
1072+
LoadResult purpose_res = LoadRecords(pwallet, batch, DBKeys::PURPOSE,
1073+
[] (CWallet* pwallet, DataStream& key, CDataStream& value, std::string& err) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {
1074+
std::string strAddress;
1075+
key >> strAddress;
1076+
std::string purpose_str;
1077+
value >> purpose_str;
1078+
std::optional<AddressPurpose> purpose{PurposeFromString(purpose_str)};
1079+
if (!purpose) {
1080+
pwallet->WalletLogPrintf("Warning: nonstandard purpose string '%s' for address '%s'\n", purpose_str, strAddress);
1081+
}
1082+
pwallet->m_address_book[DecodeDestination(strAddress)].purpose = purpose;
1083+
return DBErrors::LOAD_OK;
1084+
});
1085+
result = std::max(result, purpose_res.m_result);
1086+
1087+
// Load destination data record
1088+
LoadResult dest_res = LoadRecords(pwallet, batch, DBKeys::DESTDATA,
1089+
[] (CWallet* pwallet, DataStream& key, CDataStream& value, std::string& err) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {
1090+
std::string strAddress, strKey, strValue;
1091+
key >> strAddress;
1092+
key >> strKey;
1093+
value >> strValue;
1094+
const CTxDestination& dest{DecodeDestination(strAddress)};
1095+
if (strKey.compare("used") == 0) {
1096+
// Load "used" key indicating if an IsMine address has
1097+
// previously been spent from with avoid_reuse option enabled.
1098+
// The strValue is not used for anything currently, but could
1099+
// hold more information in the future. Current values are just
1100+
// "1" or "p" for present (which was written prior to
1101+
// f5ba424cd44619d9b9be88b8593d69a7ba96db26).
1102+
pwallet->LoadAddressPreviouslySpent(dest);
1103+
} else if (strKey.compare(0, 2, "rr") == 0) {
1104+
// Load "rr##" keys where ## is a decimal number, and strValue
1105+
// is a serialized RecentRequestEntry object.
1106+
pwallet->LoadAddressReceiveRequest(dest, strKey.substr(2), strValue);
1107+
}
1108+
return DBErrors::LOAD_OK;
1109+
});
1110+
result = std::max(result, dest_res.m_result);
1111+
1112+
return result;
1113+
}
1114+
10861115
DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
10871116
{
10881117
CWalletScanState wss;
@@ -1121,6 +1150,9 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
11211150
// when in reality the wallet is simply too new.
11221151
if (result == DBErrors::UNKNOWN_DESCRIPTOR) return result;
11231152

1153+
// Load address book
1154+
result = std::max(LoadAddressBookRecords(pwallet, *m_batch), result);
1155+
11241156
// Get cursor
11251157
std::unique_ptr<DatabaseCursor> cursor = m_batch->GetNewCursor();
11261158
if (!cursor)

0 commit comments

Comments
 (0)