Skip to content

Commit c5966a8

Browse files
author
MarcoFalke
committed
Merge #18192: Bugfix: Wallet: Safely deal with change in the address book
b5795a7 Wallet: Add warning comments and assert to CWallet::DelAddressBook (Luke Dashjr) 6d2905f Wallet: Avoid unnecessary/redundant m_address_book lookups (Luke Dashjr) c751d88 Wallet: Avoid treating change-in-the-addressbook as non-change everywhere (Luke Dashjr) 8e64b8c Wallet: New FindAddressBookEntry method to filter out change entries (and skip ->second everywhere) (Luke Dashjr) 65b6bdc Wallet: Add CAddressBookData::IsChange which returns true iff label has never been set (Luke Dashjr) 144b2f8 Wallet: Require usage of new CAddressBookData::setLabel to change label (Luke Dashjr) b86cd15 scripted-diff: Wallet: Rename mapAddressBook to m_address_book (Luke Dashjr) Pull request description: In many places, our code assumes that presence in the address book indicates a non-change key, and absence of an entry in mapAddressBook indicates change. This no longer holds true after #13756 (first released in 0.19) since it added a "used" DestData populated even for change addresses. Only avoid-reuse wallets should be affected by this issue. Thankfully, populating DestData does not write a label to the database, so we can retroactively fix this (so long as the user didn't see the change address and manually assign it a real label). Fixing it is accomplished by: * Adding a new bool to CAddressBookData to track if the label has ever been assigned, either by loading one from the database, or by assigning one at runtime. * `CAddressBookData::IsChange` and `CWallet::FindAddressBookEntry` are new methods to assist in excluding change from code that doesn't expect to see them. * For safety in merging, `CAddressBookData::name` has been made read-only (the actual data is stored in `m_label`, a new private member, and can be changed only with `setLabel` which updates the `m_change` flag), and `mapAddressBook` has been renamed to `m_address_book` (to force old code to be rebased to compile). A final commit also does some minor optimisation, avoiding redundant lookups in `m_address_book` when we already have a pointer to the `CAddressBookData`. ACKs for top commit: ryanofsky: Code review ACK b5795a7. Pretty clever and nicely implemented fix! jonatack: ACK b5795a7 nice improvements -- code review, built/ran tests rebased on current master ff53433 and tested manually with rpc/cli jnewbery: Good fix. utACK b5795a7. Tree-SHA512: 40525185a0bcc1723f602243c269499ec86ecb298fecb5ef24d626bbdd5e3efece86cdb1084ad7eebf7eeaf251db4a6e056bcd25bc8457b417fcbb53d032ebf0
2 parents c31bcaf + b5795a7 commit c5966a8

File tree

9 files changed

+93
-53
lines changed

9 files changed

+93
-53
lines changed

src/interfaces/wallet.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,8 @@ class WalletImpl : public Wallet
151151
std::string* purpose) override
152152
{
153153
LOCK(m_wallet->cs_wallet);
154-
auto it = m_wallet->mapAddressBook.find(dest);
155-
if (it == m_wallet->mapAddressBook.end()) {
154+
auto it = m_wallet->m_address_book.find(dest);
155+
if (it == m_wallet->m_address_book.end() || it->second.IsChange()) {
156156
return false;
157157
}
158158
if (name) {
@@ -170,7 +170,8 @@ class WalletImpl : public Wallet
170170
{
171171
LOCK(m_wallet->cs_wallet);
172172
std::vector<WalletAddress> result;
173-
for (const auto& item : m_wallet->mapAddressBook) {
173+
for (const auto& item : m_wallet->m_address_book) {
174+
if (item.second.IsChange()) continue;
174175
result.emplace_back(item.first, m_wallet->IsMine(item.first), item.second.name, item.second.purpose);
175176
}
176177
return result;

src/qt/addresstablemodel.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ struct AddressTableEntryLessThan
5555
static AddressTableEntry::Type translateTransactionType(const QString &strPurpose, bool isMine)
5656
{
5757
AddressTableEntry::Type addressType = AddressTableEntry::Hidden;
58-
// "refund" addresses aren't shown, and change addresses aren't in mapAddressBook at all.
58+
// "refund" addresses aren't shown, and change addresses aren't returned by getAddresses at all.
5959
if (strPurpose == "send")
6060
addressType = AddressTableEntry::Sending;
6161
else if (strPurpose == "receive")

src/qt/test/addressbooktests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ void TestAddAddressesToSendBook(interfaces::Node& node)
9797

9898
auto check_addbook_size = [&wallet](int expected_size) {
9999
LOCK(wallet->cs_wallet);
100-
QCOMPARE(static_cast<int>(wallet->mapAddressBook.size()), expected_size);
100+
QCOMPARE(static_cast<int>(wallet->m_address_book.size()), expected_size);
101101
};
102102

103103
// We should start with the two addresses we added earlier and nothing else.

src/wallet/rpcdump.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,13 @@ static bool GetWalletAddressesForKey(LegacyScriptPubKeyMan* spk_man, const CWall
6060
CKey key;
6161
spk_man->GetKey(keyid, key);
6262
for (const auto& dest : GetAllDestinationsForKey(key.GetPubKey())) {
63-
if (pwallet->mapAddressBook.count(dest)) {
63+
const auto* address_book_entry = pwallet->FindAddressBookEntry(dest);
64+
if (address_book_entry) {
6465
if (!strAddr.empty()) {
6566
strAddr += ",";
6667
}
6768
strAddr += EncodeDestination(dest);
68-
strLabel = EncodeDumpString(pwallet->mapAddressBook.at(dest).name);
69+
strLabel = EncodeDumpString(address_book_entry->name);
6970
fLabelFound = true;
7071
}
7172
}
@@ -168,7 +169,7 @@ UniValue importprivkey(const JSONRPCRequest& request)
168169
// label all new addresses, and label existing addresses if a
169170
// label was passed.
170171
for (const auto& dest : GetAllDestinationsForKey(pubkey)) {
171-
if (!request.params[1].isNull() || pwallet->mapAddressBook.count(dest) == 0) {
172+
if (!request.params[1].isNull() || !pwallet->FindAddressBookEntry(dest)) {
172173
pwallet->SetAddressBook(dest, strLabel, "receive");
173174
}
174175
}

src/wallet/rpcwallet.cpp

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -499,8 +499,9 @@ static UniValue listaddressgroupings(const JSONRPCRequest& request)
499499
addressInfo.push_back(EncodeDestination(address));
500500
addressInfo.push_back(ValueFromAmount(balances[address]));
501501
{
502-
if (pwallet->mapAddressBook.find(address) != pwallet->mapAddressBook.end()) {
503-
addressInfo.push_back(pwallet->mapAddressBook.find(address)->second.name);
502+
const auto* address_book_entry = pwallet->FindAddressBookEntry(address);
503+
if (address_book_entry) {
504+
addressInfo.push_back(address_book_entry->name);
504505
}
505506
}
506507
jsonGrouping.push_back(addressInfo);
@@ -1092,20 +1093,21 @@ static UniValue ListReceived(interfaces::Chain::Lock& locked_chain, const CWalle
10921093
UniValue ret(UniValue::VARR);
10931094
std::map<std::string, tallyitem> label_tally;
10941095

1095-
// Create mapAddressBook iterator
1096+
// Create m_address_book iterator
10961097
// If we aren't filtering, go from begin() to end()
1097-
auto start = pwallet->mapAddressBook.begin();
1098-
auto end = pwallet->mapAddressBook.end();
1098+
auto start = pwallet->m_address_book.begin();
1099+
auto end = pwallet->m_address_book.end();
10991100
// If we are filtering, find() the applicable entry
11001101
if (has_filtered_address) {
1101-
start = pwallet->mapAddressBook.find(filtered_address);
1102+
start = pwallet->m_address_book.find(filtered_address);
11021103
if (start != end) {
11031104
end = std::next(start);
11041105
}
11051106
}
11061107

11071108
for (auto item_it = start; item_it != end; ++item_it)
11081109
{
1110+
if (item_it->second.IsChange()) continue;
11091111
const CTxDestination& address = item_it->first;
11101112
const std::string& label = item_it->second.name;
11111113
auto it = mapTally.find(address);
@@ -1307,8 +1309,9 @@ static void ListTransactions(interfaces::Chain::Lock& locked_chain, const CWalle
13071309
MaybePushAddress(entry, s.destination);
13081310
entry.pushKV("category", "send");
13091311
entry.pushKV("amount", ValueFromAmount(-s.amount));
1310-
if (pwallet->mapAddressBook.count(s.destination)) {
1311-
entry.pushKV("label", pwallet->mapAddressBook.at(s.destination).name);
1312+
const auto* address_book_entry = pwallet->FindAddressBookEntry(s.destination);
1313+
if (address_book_entry) {
1314+
entry.pushKV("label", address_book_entry->name);
13121315
}
13131316
entry.pushKV("vout", s.vout);
13141317
entry.pushKV("fee", ValueFromAmount(-nFee));
@@ -1324,8 +1327,9 @@ static void ListTransactions(interfaces::Chain::Lock& locked_chain, const CWalle
13241327
for (const COutputEntry& r : listReceived)
13251328
{
13261329
std::string label;
1327-
if (pwallet->mapAddressBook.count(r.destination)) {
1328-
label = pwallet->mapAddressBook.at(r.destination).name;
1330+
const auto* address_book_entry = pwallet->FindAddressBookEntry(r.destination);
1331+
if (address_book_entry) {
1332+
label = address_book_entry->name;
13291333
}
13301334
if (filter_label && label != *filter_label) {
13311335
continue;
@@ -1349,7 +1353,7 @@ static void ListTransactions(interfaces::Chain::Lock& locked_chain, const CWalle
13491353
entry.pushKV("category", "receive");
13501354
}
13511355
entry.pushKV("amount", ValueFromAmount(r.amount));
1352-
if (pwallet->mapAddressBook.count(r.destination)) {
1356+
if (address_book_entry) {
13531357
entry.pushKV("label", label);
13541358
}
13551359
entry.pushKV("vout", r.vout);
@@ -2957,9 +2961,9 @@ static UniValue listunspent(const JSONRPCRequest& request)
29572961
if (fValidAddress) {
29582962
entry.pushKV("address", EncodeDestination(address));
29592963

2960-
auto i = pwallet->mapAddressBook.find(address);
2961-
if (i != pwallet->mapAddressBook.end()) {
2962-
entry.pushKV("label", i->second.name);
2964+
const auto* address_book_entry = pwallet->FindAddressBookEntry(address);
2965+
if (address_book_entry) {
2966+
entry.pushKV("label", address_book_entry->name);
29632967
}
29642968

29652969
std::unique_ptr<SigningProvider> provider = pwallet->GetSolvingProvider(scriptPubKey);
@@ -3816,8 +3820,9 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
38163820
// DEPRECATED: Return label field if existing. Currently only one label can
38173821
// be associated with an address, so the label should be equivalent to the
38183822
// value of the name key/value pair in the labels array below.
3819-
if ((pwallet->chain().rpcEnableDeprecated("label")) && (pwallet->mapAddressBook.count(dest))) {
3820-
ret.pushKV("label", pwallet->mapAddressBook.at(dest).name);
3823+
const auto* address_book_entry = pwallet->FindAddressBookEntry(dest);
3824+
if (pwallet->chain().rpcEnableDeprecated("label") && address_book_entry) {
3825+
ret.pushKV("label", address_book_entry->name);
38213826
}
38223827

38233828
ret.pushKV("ischange", pwallet->IsChange(scriptPubKey));
@@ -3840,14 +3845,13 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
38403845
// stable if we allow multiple labels to be associated with an address in
38413846
// the future.
38423847
UniValue labels(UniValue::VARR);
3843-
std::map<CTxDestination, CAddressBookData>::const_iterator mi = pwallet->mapAddressBook.find(dest);
3844-
if (mi != pwallet->mapAddressBook.end()) {
3848+
if (address_book_entry) {
38453849
// DEPRECATED: The previous behavior of returning an array containing a
38463850
// JSON object of `name` and `purpose` key/value pairs is deprecated.
38473851
if (pwallet->chain().rpcEnableDeprecated("labelspurpose")) {
3848-
labels.push_back(AddressBookDataToJSON(mi->second, true));
3852+
labels.push_back(AddressBookDataToJSON(*address_book_entry, true));
38493853
} else {
3850-
labels.push_back(mi->second.name);
3854+
labels.push_back(address_book_entry->name);
38513855
}
38523856
}
38533857
ret.pushKV("labels", std::move(labels));
@@ -3891,10 +3895,11 @@ static UniValue getaddressesbylabel(const JSONRPCRequest& request)
38913895
// Find all addresses that have the given label
38923896
UniValue ret(UniValue::VOBJ);
38933897
std::set<std::string> addresses;
3894-
for (const std::pair<const CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) {
3898+
for (const std::pair<const CTxDestination, CAddressBookData>& item : pwallet->m_address_book) {
3899+
if (item.second.IsChange()) continue;
38953900
if (item.second.name == label) {
38963901
std::string address = EncodeDestination(item.first);
3897-
// CWallet::mapAddressBook is not expected to contain duplicate
3902+
// CWallet::m_address_book is not expected to contain duplicate
38983903
// address strings, but build a separate set as a precaution just in
38993904
// case it does.
39003905
bool unique = addresses.emplace(address).second;
@@ -3955,7 +3960,8 @@ static UniValue listlabels(const JSONRPCRequest& request)
39553960

39563961
// Add to a set to sort by label name, then insert into Univalue array
39573962
std::set<std::string> label_set;
3958-
for (const std::pair<const CTxDestination, CAddressBookData>& entry : pwallet->mapAddressBook) {
3963+
for (const std::pair<const CTxDestination, CAddressBookData>& entry : pwallet->m_address_book) {
3964+
if (entry.second.IsChange()) continue;
39593965
if (purpose.empty() || entry.second.purpose == purpose) {
39603966
label_set.insert(entry.second.name);
39613967
}

src/wallet/wallet.cpp

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1242,8 +1242,9 @@ bool CWallet::IsChange(const CScript& script) const
12421242
return true;
12431243

12441244
LOCK(cs_wallet);
1245-
if (!mapAddressBook.count(address))
1245+
if (!FindAddressBookEntry(address)) {
12461246
return true;
1247+
}
12471248
}
12481249
return false;
12491250
}
@@ -3196,11 +3197,11 @@ bool CWallet::SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& add
31963197
bool fUpdated = false;
31973198
{
31983199
LOCK(cs_wallet);
3199-
std::map<CTxDestination, CAddressBookData>::iterator mi = mapAddressBook.find(address);
3200-
fUpdated = mi != mapAddressBook.end();
3201-
mapAddressBook[address].name = strName;
3200+
std::map<CTxDestination, CAddressBookData>::iterator mi = m_address_book.find(address);
3201+
fUpdated = (mi != m_address_book.end() && !mi->second.IsChange());
3202+
m_address_book[address].SetLabel(strName);
32023203
if (!strPurpose.empty()) /* update purpose only if requested */
3203-
mapAddressBook[address].purpose = strPurpose;
3204+
m_address_book[address].purpose = strPurpose;
32043205
}
32053206
NotifyAddressBookChanged(this, address, strName, IsMine(address) != ISMINE_NO,
32063207
strPurpose, (fUpdated ? CT_UPDATED : CT_NEW) );
@@ -3217,16 +3218,21 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& s
32173218

32183219
bool CWallet::DelAddressBook(const CTxDestination& address)
32193220
{
3221+
// If we want to delete receiving addresses, we need to take care that DestData "used" (and possibly newer DestData) gets preserved (and the "deleted" address transformed into a change entry instead of actually being deleted)
3222+
// NOTE: This isn't a problem for sending addresses because they never have any DestData yet!
3223+
// When adding new DestData, it should be considered here whether to retain or delete it (or move it?).
3224+
assert(!IsMine(address));
3225+
32203226
{
32213227
LOCK(cs_wallet);
32223228

32233229
// Delete destdata tuples associated with address
32243230
std::string strAddress = EncodeDestination(address);
3225-
for (const std::pair<const std::string, std::string> &item : mapAddressBook[address].destdata)
3231+
for (const std::pair<const std::string, std::string> &item : m_address_book[address].destdata)
32263232
{
32273233
WalletBatch(*database).EraseDestData(strAddress, item.first);
32283234
}
3229-
mapAddressBook.erase(address);
3235+
m_address_book.erase(address);
32303236
}
32313237

32323238
NotifyAddressBookChanged(this, address, "", IsMine(address) != ISMINE_NO, "", CT_DELETED);
@@ -3462,8 +3468,9 @@ std::set<CTxDestination> CWallet::GetLabelAddresses(const std::string& label) co
34623468
{
34633469
LOCK(cs_wallet);
34643470
std::set<CTxDestination> result;
3465-
for (const std::pair<const CTxDestination, CAddressBookData>& item : mapAddressBook)
3471+
for (const std::pair<const CTxDestination, CAddressBookData>& item : m_address_book)
34663472
{
3473+
if (item.second.IsChange()) continue;
34673474
const CTxDestination& address = item.first;
34683475
const std::string& strName = item.second.name;
34693476
if (strName == label)
@@ -3666,26 +3673,26 @@ bool CWallet::AddDestData(WalletBatch& batch, const CTxDestination &dest, const
36663673
if (boost::get<CNoDestination>(&dest))
36673674
return false;
36683675

3669-
mapAddressBook[dest].destdata.insert(std::make_pair(key, value));
3676+
m_address_book[dest].destdata.insert(std::make_pair(key, value));
36703677
return batch.WriteDestData(EncodeDestination(dest), key, value);
36713678
}
36723679

36733680
bool CWallet::EraseDestData(WalletBatch& batch, const CTxDestination &dest, const std::string &key)
36743681
{
3675-
if (!mapAddressBook[dest].destdata.erase(key))
3682+
if (!m_address_book[dest].destdata.erase(key))
36763683
return false;
36773684
return batch.EraseDestData(EncodeDestination(dest), key);
36783685
}
36793686

36803687
void CWallet::LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value)
36813688
{
3682-
mapAddressBook[dest].destdata.insert(std::make_pair(key, value));
3689+
m_address_book[dest].destdata.insert(std::make_pair(key, value));
36833690
}
36843691

36853692
bool CWallet::GetDestData(const CTxDestination &dest, const std::string &key, std::string *value) const
36863693
{
3687-
std::map<CTxDestination, CAddressBookData>::const_iterator i = mapAddressBook.find(dest);
3688-
if(i != mapAddressBook.end())
3694+
std::map<CTxDestination, CAddressBookData>::const_iterator i = m_address_book.find(dest);
3695+
if(i != m_address_book.end())
36893696
{
36903697
CAddressBookData::StringMap::const_iterator j = i->second.destdata.find(key);
36913698
if(j != i->second.destdata.end())
@@ -3701,7 +3708,7 @@ bool CWallet::GetDestData(const CTxDestination &dest, const std::string &key, st
37013708
std::vector<std::string> CWallet::GetDestValues(const std::string& prefix) const
37023709
{
37033710
std::vector<std::string> values;
3704-
for (const auto& address : mapAddressBook) {
3711+
for (const auto& address : m_address_book) {
37053712
for (const auto& data : address.second.destdata) {
37063713
if (!data.first.compare(0, prefix.size(), prefix)) {
37073714
values.emplace_back(data.second);
@@ -4103,12 +4110,22 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
41034110
{
41044111
walletInstance->WalletLogPrintf("setKeyPool.size() = %u\n", walletInstance->GetKeyPoolSize());
41054112
walletInstance->WalletLogPrintf("mapWallet.size() = %u\n", walletInstance->mapWallet.size());
4106-
walletInstance->WalletLogPrintf("mapAddressBook.size() = %u\n", walletInstance->mapAddressBook.size());
4113+
walletInstance->WalletLogPrintf("m_address_book.size() = %u\n", walletInstance->m_address_book.size());
41074114
}
41084115

41094116
return walletInstance;
41104117
}
41114118

4119+
const CAddressBookData* CWallet::FindAddressBookEntry(const CTxDestination& dest, bool allow_change) const
4120+
{
4121+
const auto& address_book_it = m_address_book.find(dest);
4122+
if (address_book_it == m_address_book.end()) return nullptr;
4123+
if ((!allow_change) && address_book_it->second.IsChange()) {
4124+
return nullptr;
4125+
}
4126+
return &address_book_it->second;
4127+
}
4128+
41124129
void CWallet::postInitProcess()
41134130
{
41144131
auto locked_chain = chain().lock();

src/wallet/wallet.h

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -181,14 +181,23 @@ class ReserveDestination
181181
/** Address book data */
182182
class CAddressBookData
183183
{
184+
private:
185+
bool m_change{true};
186+
std::string m_label;
184187
public:
185-
std::string name;
188+
const std::string& name;
186189
std::string purpose;
187190

188-
CAddressBookData() : purpose("unknown") {}
191+
CAddressBookData() : name(m_label), purpose("unknown") {}
189192

190193
typedef std::map<std::string, std::string> StringMap;
191194
StringMap destdata;
195+
196+
bool IsChange() const { return m_change; }
197+
void SetLabel(const std::string& label) {
198+
m_change = false;
199+
m_label = label;
200+
}
192201
};
193202

194203
struct CRecipient
@@ -775,7 +784,8 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
775784
int64_t nOrderPosNext GUARDED_BY(cs_wallet) = 0;
776785
uint64_t nAccountingEntryNumber = 0;
777786

778-
std::map<CTxDestination, CAddressBookData> mapAddressBook GUARDED_BY(cs_wallet);
787+
std::map<CTxDestination, CAddressBookData> m_address_book GUARDED_BY(cs_wallet);
788+
const CAddressBookData* FindAddressBookEntry(const CTxDestination&, bool allow_change = false) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
779789

780790
std::set<COutPoint> setLockedCoins GUARDED_BY(cs_wallet);
781791

@@ -842,7 +852,10 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
842852

843853
bool LoadMinVersion(int nVersion) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { AssertLockHeld(cs_wallet); nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; }
844854

845-
//! Adds a destination data tuple to the store, and saves it to disk
855+
/**
856+
* Adds a destination data tuple to the store, and saves it to disk
857+
* When adding new fields, take care to consider how DelAddressBook should handle it!
858+
*/
846859
bool AddDestData(WalletBatch& batch, const CTxDestination& dest, const std::string& key, const std::string& value) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
847860
//! Erases a destination data tuple in the store and on disk
848861
bool EraseDestData(WalletBatch& batch, const CTxDestination& dest, const std::string& key) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);

src/wallet/walletdb.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,11 +206,13 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
206206
if (strType == DBKeys::NAME) {
207207
std::string strAddress;
208208
ssKey >> strAddress;
209-
ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].name;
209+
std::string label;
210+
ssValue >> label;
211+
pwallet->m_address_book[DecodeDestination(strAddress)].SetLabel(label);
210212
} else if (strType == DBKeys::PURPOSE) {
211213
std::string strAddress;
212214
ssKey >> strAddress;
213-
ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].purpose;
215+
ssValue >> pwallet->m_address_book[DecodeDestination(strAddress)].purpose;
214216
} else if (strType == DBKeys::TX) {
215217
uint256 hash;
216218
ssKey >> hash;

0 commit comments

Comments
 (0)