mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 03:52:49 +01:00
Merge #18192: Bugfix: Wallet: Safely deal with change in the address book
b5795a788639305bab86a8b3f6b75d6ce81be083 Wallet: Add warning comments and assert to CWallet::DelAddressBook (Luke Dashjr) 6d2905f57aaeb3ec3b63d31043f7673ca10003f2 Wallet: Avoid unnecessary/redundant m_address_book lookups (Luke Dashjr) c751d886f499257627b308b11ffaa51c22db6cc0 Wallet: Avoid treating change-in-the-addressbook as non-change everywhere (Luke Dashjr) 8e64b8c84bcbd63caea06f3af087af1f0609eaf5 Wallet: New FindAddressBookEntry method to filter out change entries (and skip ->second everywhere) (Luke Dashjr) 65b6bdc2b164343ec3cc3d32a0297daff9e24fec Wallet: Add CAddressBookData::IsChange which returns true iff label has never been set (Luke Dashjr) 144b2f85da4d51bf7d72b987888ddcaf5b429eed Wallet: Require usage of new CAddressBookData::setLabel to change label (Luke Dashjr) b86cd155f6f661052042048aa7cfc2a397afe4f7 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 b5795a788639305bab86a8b3f6b75d6ce81be083. Pretty clever and nicely implemented fix! jonatack: ACK b5795a788639305bab86a8b3f6b75d6ce81be083 nice improvements -- code review, built/ran tests rebased on current master ff53433fe4ed06893d7c4 and tested manually with rpc/cli jnewbery: Good fix. utACK b5795a788. Tree-SHA512: 40525185a0bcc1723f602243c269499ec86ecb298fecb5ef24d626bbdd5e3efece86cdb1084ad7eebf7eeaf251db4a6e056bcd25bc8457b417fcbb53d032ebf0
This commit is contained in:
parent
984aae497d
commit
cedb78e157
@ -55,7 +55,7 @@ struct AddressTableEntryLessThan
|
||||
static AddressTableEntry::Type translateTransactionType(const QString &strPurpose, bool isMine)
|
||||
{
|
||||
AddressTableEntry::Type addressType = AddressTableEntry::Hidden;
|
||||
// "refund" addresses aren't shown, and change addresses aren't in mapAddressBook at all.
|
||||
// "refund" addresses aren't shown, and change addresses aren't returned by getAddresses at all.
|
||||
if (strPurpose == "send")
|
||||
addressType = AddressTableEntry::Sending;
|
||||
else if (strPurpose == "receive")
|
||||
|
@ -98,7 +98,7 @@ void TestAddAddressesToSendBook(interfaces::Node& node)
|
||||
|
||||
auto check_addbook_size = [wallet](int expected_size) {
|
||||
LOCK(wallet->cs_wallet);
|
||||
QCOMPARE(static_cast<int>(wallet->mapAddressBook.size()), expected_size);
|
||||
QCOMPARE(static_cast<int>(wallet->m_address_book.size()), expected_size);
|
||||
};
|
||||
|
||||
// We should start with the two addresses we added earlier and nothing else.
|
||||
|
@ -240,8 +240,8 @@ public:
|
||||
std::string* purpose) override
|
||||
{
|
||||
LOCK(m_wallet->cs_wallet);
|
||||
auto it = m_wallet->mapAddressBook.find(dest);
|
||||
if (it == m_wallet->mapAddressBook.end()) {
|
||||
auto it = m_wallet->m_address_book.find(dest);
|
||||
if (it == m_wallet->m_address_book.end() || it->second.IsChange()) {
|
||||
return false;
|
||||
}
|
||||
if (name) {
|
||||
@ -259,7 +259,8 @@ public:
|
||||
{
|
||||
LOCK(m_wallet->cs_wallet);
|
||||
std::vector<WalletAddress> result;
|
||||
for (const auto& item : m_wallet->mapAddressBook) {
|
||||
for (const auto& item : m_wallet->m_address_book) {
|
||||
if (item.second.IsChange()) continue;
|
||||
result.emplace_back(item.first, m_wallet->IsMine(item.first), item.second.name, item.second.purpose);
|
||||
}
|
||||
return result;
|
||||
|
@ -142,7 +142,7 @@ UniValue importprivkey(const JSONRPCRequest& request)
|
||||
{
|
||||
pwallet->MarkDirty();
|
||||
|
||||
if (!request.params[1].isNull() || pwallet->mapAddressBook.count(vchAddress) == 0) {
|
||||
if (!request.params[1].isNull() || !pwallet->FindAddressBookEntry(vchAddress)) {
|
||||
pwallet->SetAddressBook(vchAddress, strLabel, "receive");
|
||||
}
|
||||
|
||||
@ -1011,8 +1011,9 @@ UniValue dumpwallet(const JSONRPCRequest& request)
|
||||
CKey key;
|
||||
if (spk_man.GetKey(keyid, key)) {
|
||||
file << strprintf("%s %s ", EncodeSecret(key), strTime);
|
||||
if (pwallet->mapAddressBook.count(pkhash)) {
|
||||
file << strprintf("label=%s", EncodeDumpString(pwallet->mapAddressBook.at(pkhash).name));
|
||||
const auto* address_book_entry = pwallet->FindAddressBookEntry(pkhash);
|
||||
if (address_book_entry) {
|
||||
file << strprintf("label=%s", EncodeDumpString(address_book_entry->name));
|
||||
} else if (mapKeyPool.count(keyid)) {
|
||||
file << "reserve=1";
|
||||
} else {
|
||||
|
@ -500,8 +500,9 @@ static UniValue listaddressgroupings(const JSONRPCRequest& request)
|
||||
addressInfo.push_back(EncodeDestination(address));
|
||||
addressInfo.push_back(ValueFromAmount(balances[address]));
|
||||
{
|
||||
if (pwallet->mapAddressBook.find(address) != pwallet->mapAddressBook.end()) {
|
||||
addressInfo.push_back(pwallet->mapAddressBook.find(address)->second.name);
|
||||
const auto* address_book_entry = pwallet->FindAddressBookEntry(address);
|
||||
if (address_book_entry) {
|
||||
addressInfo.push_back(address_book_entry->name);
|
||||
}
|
||||
}
|
||||
jsonGrouping.push_back(addressInfo);
|
||||
@ -1114,13 +1115,13 @@ static UniValue ListReceived(const CWallet * const pwallet, const UniValue& para
|
||||
UniValue ret(UniValue::VARR);
|
||||
std::map<std::string, tallyitem> label_tally;
|
||||
|
||||
// Create mapAddressBook iterator
|
||||
// Create m_address_book iterator
|
||||
// If we aren't filtering, go from begin() to end()
|
||||
auto start = pwallet->mapAddressBook.begin();
|
||||
auto end = pwallet->mapAddressBook.end();
|
||||
auto start = pwallet->m_address_book.begin();
|
||||
auto end = pwallet->m_address_book.end();
|
||||
// If we are filtering, find() the applicable entry
|
||||
if (has_filtered_address) {
|
||||
start = pwallet->mapAddressBook.find(filtered_address);
|
||||
start = pwallet->m_address_book.find(filtered_address);
|
||||
if (start != end) {
|
||||
end = std::next(start);
|
||||
}
|
||||
@ -1128,6 +1129,7 @@ static UniValue ListReceived(const CWallet * const pwallet, const UniValue& para
|
||||
|
||||
for (auto item_it = start; item_it != end; ++item_it)
|
||||
{
|
||||
if (item_it->second.IsChange()) continue;
|
||||
const CTxDestination& address = item_it->first;
|
||||
const std::string& label = item_it->second.name;
|
||||
auto it = mapTally.find(address);
|
||||
@ -1330,8 +1332,9 @@ static void ListTransactions(const CWallet* const pwallet, const CWalletTx& wtx,
|
||||
std::map<std::string, std::string>::const_iterator it = wtx.mapValue.find("DS");
|
||||
entry.pushKV("category", (it != wtx.mapValue.end() && it->second == "1") ? "coinjoin" : "send");
|
||||
entry.pushKV("amount", ValueFromAmount(-s.amount));
|
||||
if (pwallet->mapAddressBook.count(s.destination)) {
|
||||
entry.pushKV("label", pwallet->mapAddressBook.at(s.destination).name);
|
||||
const auto* address_book_entry = pwallet->FindAddressBookEntry(s.destination);
|
||||
if (address_book_entry) {
|
||||
entry.pushKV("label", address_book_entry->name);
|
||||
}
|
||||
entry.pushKV("vout", s.vout);
|
||||
entry.pushKV("fee", ValueFromAmount(-nFee));
|
||||
@ -1348,8 +1351,9 @@ static void ListTransactions(const CWallet* const pwallet, const CWalletTx& wtx,
|
||||
for (const COutputEntry& r : listReceived)
|
||||
{
|
||||
std::string label;
|
||||
if (pwallet->mapAddressBook.count(r.destination)) {
|
||||
label = pwallet->mapAddressBook.at(r.destination).name;
|
||||
const auto* address_book_entry = pwallet->FindAddressBookEntry(r.destination);
|
||||
if (address_book_entry) {
|
||||
label = address_book_entry->name;
|
||||
}
|
||||
if (filter_label && label != *filter_label) {
|
||||
continue;
|
||||
@ -1373,7 +1377,7 @@ static void ListTransactions(const CWallet* const pwallet, const CWalletTx& wtx,
|
||||
entry.pushKV("category", "receive");
|
||||
}
|
||||
entry.pushKV("amount", ValueFromAmount(r.amount));
|
||||
if (pwallet->mapAddressBook.count(r.destination)) {
|
||||
if (address_book_entry) {
|
||||
entry.pushKV("label", label);
|
||||
}
|
||||
entry.pushKV("vout", r.vout);
|
||||
@ -3152,9 +3156,9 @@ static UniValue listunspent(const JSONRPCRequest& request)
|
||||
if (fValidAddress) {
|
||||
entry.pushKV("address", EncodeDestination(address));
|
||||
|
||||
auto i = pwallet->mapAddressBook.find(address);
|
||||
if (i != pwallet->mapAddressBook.end()) {
|
||||
entry.pushKV("label", i->second.name);
|
||||
const auto* address_book_entry = pwallet->FindAddressBookEntry(address);
|
||||
if (address_book_entry) {
|
||||
entry.pushKV("label", address_book_entry->name);
|
||||
}
|
||||
|
||||
std::unique_ptr<SigningProvider> provider = pwallet->GetSolvingProvider(scriptPubKey);
|
||||
@ -3713,8 +3717,9 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
|
||||
// DEPRECATED: Return label field if existing. Currently only one label can
|
||||
// be associated with an address, so the label should be equivalent to the
|
||||
// value of the name key/value pair in the labels array below.
|
||||
if ((pwallet->chain().rpcEnableDeprecated("label")) && (pwallet->mapAddressBook.count(dest))) {
|
||||
ret.pushKV("label", pwallet->mapAddressBook.at(dest).name);
|
||||
const auto* address_book_entry = pwallet->FindAddressBookEntry(dest);
|
||||
if (pwallet->chain().rpcEnableDeprecated("label") && address_book_entry) {
|
||||
ret.pushKV("label", address_book_entry->name);
|
||||
}
|
||||
|
||||
ret.pushKV("ischange", pwallet->IsChange(scriptPubKey));
|
||||
@ -3744,14 +3749,13 @@ UniValue getaddressinfo(const JSONRPCRequest& request)
|
||||
// stable if we allow multiple labels to be associated with an address in
|
||||
// the future.
|
||||
UniValue labels(UniValue::VARR);
|
||||
std::map<CTxDestination, CAddressBookData>::const_iterator mi = pwallet->mapAddressBook.find(dest);
|
||||
if (mi != pwallet->mapAddressBook.end()) {
|
||||
if (address_book_entry) {
|
||||
// DEPRECATED: The previous behavior of returning an array containing a
|
||||
// JSON object of `name` and `purpose` key/value pairs is deprecated.
|
||||
if (pwallet->chain().rpcEnableDeprecated("labelspurpose")) {
|
||||
labels.push_back(AddressBookDataToJSON(mi->second, true));
|
||||
labels.push_back(AddressBookDataToJSON(*address_book_entry, true));
|
||||
} else {
|
||||
labels.push_back(mi->second.name);
|
||||
labels.push_back(address_book_entry->name);
|
||||
}
|
||||
}
|
||||
ret.pushKV("labels", std::move(labels));
|
||||
@ -3792,10 +3796,11 @@ static UniValue getaddressesbylabel(const JSONRPCRequest& request)
|
||||
// Find all addresses that have the given label
|
||||
UniValue ret(UniValue::VOBJ);
|
||||
std::set<std::string> addresses;
|
||||
for (const std::pair<CTxDestination, CAddressBookData> item : pwallet->mapAddressBook) {
|
||||
for (const std::pair<const CTxDestination, CAddressBookData>& item : pwallet->m_address_book) {
|
||||
if (item.second.IsChange()) continue;
|
||||
if (item.second.name == label) {
|
||||
std::string address = EncodeDestination(item.first);
|
||||
// CWallet::mapAddressBook is not expected to contain duplicate
|
||||
// CWallet::m_address_book is not expected to contain duplicate
|
||||
// address strings, but build a separate set as a precaution just in
|
||||
// case it does.
|
||||
bool unique = addresses.emplace(address).second;
|
||||
@ -3853,7 +3858,8 @@ static UniValue listlabels(const JSONRPCRequest& request)
|
||||
|
||||
// Add to a set to sort by label name, then insert into Univalue array
|
||||
std::set<std::string> label_set;
|
||||
for (const std::pair<CTxDestination, CAddressBookData> entry : pwallet->mapAddressBook) {
|
||||
for (const std::pair<const CTxDestination, CAddressBookData>& entry : pwallet->m_address_book) {
|
||||
if (entry.second.IsChange()) continue;
|
||||
if (purpose.empty() || entry.second.purpose == purpose) {
|
||||
label_set.insert(entry.second.name);
|
||||
}
|
||||
|
@ -1501,8 +1501,9 @@ bool CWallet::IsChange(const CScript& script) const
|
||||
return true;
|
||||
|
||||
LOCK(cs_wallet);
|
||||
if (!mapAddressBook.count(address))
|
||||
if (!FindAddressBookEntry(address)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -3905,11 +3906,11 @@ bool CWallet::SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& add
|
||||
bool fUpdated = false;
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
std::map<CTxDestination, CAddressBookData>::iterator mi = mapAddressBook.find(address);
|
||||
fUpdated = mi != mapAddressBook.end();
|
||||
mapAddressBook[address].name = strName;
|
||||
std::map<CTxDestination, CAddressBookData>::iterator mi = m_address_book.find(address);
|
||||
fUpdated = (mi != m_address_book.end() && !mi->second.IsChange());
|
||||
m_address_book[address].SetLabel(strName);
|
||||
if (!strPurpose.empty()) /* update purpose only if requested */
|
||||
mapAddressBook[address].purpose = strPurpose;
|
||||
m_address_book[address].purpose = strPurpose;
|
||||
}
|
||||
NotifyAddressBookChanged(this, address, strName, IsMine(address) != ISMINE_NO,
|
||||
strPurpose, (fUpdated ? CT_UPDATED : CT_NEW) );
|
||||
@ -3926,16 +3927,21 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& s
|
||||
|
||||
bool CWallet::DelAddressBook(const CTxDestination& address)
|
||||
{
|
||||
// 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)
|
||||
// NOTE: This isn't a problem for sending addresses because they never have any DestData yet!
|
||||
// When adding new DestData, it should be considered here whether to retain or delete it (or move it?).
|
||||
assert(!IsMine(address));
|
||||
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
|
||||
// Delete destdata tuples associated with address
|
||||
std::string strAddress = EncodeDestination(address);
|
||||
for (const std::pair<const std::string, std::string> &item : mapAddressBook[address].destdata)
|
||||
for (const std::pair<const std::string, std::string> &item : m_address_book[address].destdata)
|
||||
{
|
||||
WalletBatch(*database).EraseDestData(strAddress, item.first);
|
||||
}
|
||||
mapAddressBook.erase(address);
|
||||
m_address_book.erase(address);
|
||||
}
|
||||
|
||||
NotifyAddressBookChanged(this, address, "", IsMine(address) != ISMINE_NO, "", CT_DELETED);
|
||||
@ -4172,8 +4178,9 @@ std::set<CTxDestination> CWallet::GetLabelAddresses(const std::string& label) co
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
std::set<CTxDestination> result;
|
||||
for (const std::pair<const CTxDestination, CAddressBookData>& item : mapAddressBook)
|
||||
for (const std::pair<const CTxDestination, CAddressBookData>& item : m_address_book)
|
||||
{
|
||||
if (item.second.IsChange()) continue;
|
||||
const CTxDestination& address = item.first;
|
||||
const std::string& strName = item.second.name;
|
||||
if (strName == label)
|
||||
@ -4406,26 +4413,26 @@ bool CWallet::AddDestData(WalletBatch& batch, const CTxDestination &dest, const
|
||||
if (std::get_if<CNoDestination>(&dest))
|
||||
return false;
|
||||
|
||||
mapAddressBook[dest].destdata.insert(std::make_pair(key, value));
|
||||
m_address_book[dest].destdata.insert(std::make_pair(key, value));
|
||||
return batch.WriteDestData(EncodeDestination(dest), key, value);
|
||||
}
|
||||
|
||||
bool CWallet::EraseDestData(WalletBatch& batch, const CTxDestination &dest, const std::string &key)
|
||||
{
|
||||
if (!mapAddressBook[dest].destdata.erase(key))
|
||||
if (!m_address_book[dest].destdata.erase(key))
|
||||
return false;
|
||||
return batch.EraseDestData(EncodeDestination(dest), key);
|
||||
}
|
||||
|
||||
void CWallet::LoadDestData(const CTxDestination &dest, const std::string &key, const std::string &value)
|
||||
{
|
||||
mapAddressBook[dest].destdata.insert(std::make_pair(key, value));
|
||||
m_address_book[dest].destdata.insert(std::make_pair(key, value));
|
||||
}
|
||||
|
||||
bool CWallet::GetDestData(const CTxDestination &dest, const std::string &key, std::string *value) const
|
||||
{
|
||||
std::map<CTxDestination, CAddressBookData>::const_iterator i = mapAddressBook.find(dest);
|
||||
if(i != mapAddressBook.end())
|
||||
std::map<CTxDestination, CAddressBookData>::const_iterator i = m_address_book.find(dest);
|
||||
if(i != m_address_book.end())
|
||||
{
|
||||
CAddressBookData::StringMap::const_iterator j = i->second.destdata.find(key);
|
||||
if(j != i->second.destdata.end())
|
||||
@ -4441,7 +4448,7 @@ bool CWallet::GetDestData(const CTxDestination &dest, const std::string &key, st
|
||||
std::vector<std::string> CWallet::GetDestValues(const std::string& prefix) const
|
||||
{
|
||||
std::vector<std::string> values;
|
||||
for (const auto& address : mapAddressBook) {
|
||||
for (const auto& address : m_address_book) {
|
||||
for (const auto& data : address.second.destdata) {
|
||||
if (!data.first.compare(0, prefix.size(), prefix)) {
|
||||
values.emplace_back(data.second);
|
||||
@ -4801,7 +4808,7 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain& chain, const std::st
|
||||
walletInstance->WalletLogPrintf("setExternalKeyPool.size() = %u\n", walletInstance->KeypoolCountExternalKeys());
|
||||
walletInstance->WalletLogPrintf("setInternalKeyPool.size() = %u\n", walletInstance->KeypoolCountInternalKeys());
|
||||
walletInstance->WalletLogPrintf("mapWallet.size() = %u\n", walletInstance->mapWallet.size());
|
||||
walletInstance->WalletLogPrintf("mapAddressBook.size() = %u\n", walletInstance->mapAddressBook.size());
|
||||
walletInstance->WalletLogPrintf("m_address_book.size() = %u\n", walletInstance->m_address_book.size());
|
||||
for (auto spk_man : walletInstance->GetAllScriptPubKeyMans()) {
|
||||
walletInstance->WalletLogPrintf("nTimeFirstKey = %u\n", spk_man->GetTimeFirstKey());
|
||||
}
|
||||
@ -4831,6 +4838,16 @@ bool CWallet::UpgradeWallet(int version, bilingual_str& error, std::vector<bilin
|
||||
return true;
|
||||
}
|
||||
|
||||
const CAddressBookData* CWallet::FindAddressBookEntry(const CTxDestination& dest, bool allow_change) const
|
||||
{
|
||||
const auto& address_book_it = m_address_book.find(dest);
|
||||
if (address_book_it == m_address_book.end()) return nullptr;
|
||||
if ((!allow_change) && address_book_it->second.IsChange()) {
|
||||
return nullptr;
|
||||
}
|
||||
return &address_book_it->second;
|
||||
}
|
||||
|
||||
void CWallet::postInitProcess()
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
|
@ -187,14 +187,23 @@ public:
|
||||
/** Address book data */
|
||||
class CAddressBookData
|
||||
{
|
||||
private:
|
||||
bool m_change{true};
|
||||
std::string m_label;
|
||||
public:
|
||||
std::string name;
|
||||
const std::string& name;
|
||||
std::string purpose;
|
||||
|
||||
CAddressBookData() : purpose("unknown") {}
|
||||
CAddressBookData() : name(m_label), purpose("unknown") {}
|
||||
|
||||
typedef std::map<std::string, std::string> StringMap;
|
||||
StringMap destdata;
|
||||
|
||||
bool IsChange() const { return m_change; }
|
||||
void SetLabel(const std::string& label) {
|
||||
m_change = false;
|
||||
m_label = label;
|
||||
}
|
||||
};
|
||||
|
||||
struct CRecipient
|
||||
@ -847,7 +856,8 @@ public:
|
||||
int64_t nOrderPosNext GUARDED_BY(cs_wallet) = 0;
|
||||
uint64_t nAccountingEntryNumber = 0;
|
||||
|
||||
std::map<CTxDestination, CAddressBookData> mapAddressBook GUARDED_BY(cs_wallet);
|
||||
std::map<CTxDestination, CAddressBookData> m_address_book GUARDED_BY(cs_wallet);
|
||||
const CAddressBookData* FindAddressBookEntry(const CTxDestination&, bool allow_change = false) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
|
||||
std::set<COutPoint> setLockedCoins GUARDED_BY(cs_wallet);
|
||||
|
||||
@ -933,7 +943,10 @@ public:
|
||||
|
||||
bool LoadMinVersion(int nVersion) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { AssertLockHeld(cs_wallet); nWalletVersion = nVersion; nWalletMaxVersion = std::max(nWalletMaxVersion, nVersion); return true; }
|
||||
|
||||
//! Adds a destination data tuple to the store, and saves it to disk
|
||||
/**
|
||||
* Adds a destination data tuple to the store, and saves it to disk
|
||||
* When adding new fields, take care to consider how DelAddressBook should handle it!
|
||||
*/
|
||||
bool AddDestData(WalletBatch& batch, const CTxDestination& dest, const std::string& key, const std::string& value) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
//! Erases a destination data tuple in the store and on disk
|
||||
bool EraseDestData(WalletBatch& batch, const CTxDestination& dest, const std::string& key) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
|
||||
|
@ -243,11 +243,13 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
|
||||
if (strType == DBKeys::NAME) {
|
||||
std::string strAddress;
|
||||
ssKey >> strAddress;
|
||||
ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].name;
|
||||
std::string label;
|
||||
ssValue >> label;
|
||||
pwallet->m_address_book[DecodeDestination(strAddress)].SetLabel(label);
|
||||
} else if (strType == DBKeys::PURPOSE) {
|
||||
std::string strAddress;
|
||||
ssKey >> strAddress;
|
||||
ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].purpose;
|
||||
ssValue >> pwallet->m_address_book[DecodeDestination(strAddress)].purpose;
|
||||
} else if (strType == DBKeys::TX) {
|
||||
uint256 hash;
|
||||
ssKey >> hash;
|
||||
|
@ -101,7 +101,7 @@ static void WalletShowInfo(CWallet* wallet_instance)
|
||||
tfm::format(std::cout, "HD (hd seed available): %s\n", wallet_instance->IsHDEnabled() ? "yes" : "no");
|
||||
tfm::format(std::cout, "Keypool Size: %u\n", wallet_instance->GetKeyPoolSize());
|
||||
tfm::format(std::cout, "Transactions: %zu\n", wallet_instance->mapWallet.size());
|
||||
tfm::format(std::cout, "Address Book: %zu\n", wallet_instance->mapAddressBook.size());
|
||||
tfm::format(std::cout, "Address Book: %zu\n", wallet_instance->m_address_book.size());
|
||||
}
|
||||
|
||||
bool ExecuteWalletToolFunc(const std::string& command, const std::string& name)
|
||||
|
Loading…
Reference in New Issue
Block a user