mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-25 10:43:19 -03:00
Merge #18192: Bugfix: Wallet: Safely deal with change in the address book
b5795a7886
Wallet: Add warning comments and assert to CWallet::DelAddressBook (Luke Dashjr)6d2905f57a
Wallet: Avoid unnecessary/redundant m_address_book lookups (Luke Dashjr)c751d886f4
Wallet: Avoid treating change-in-the-addressbook as non-change everywhere (Luke Dashjr)8e64b8c84b
Wallet: New FindAddressBookEntry method to filter out change entries (and skip ->second everywhere) (Luke Dashjr)65b6bdc2b1
Wallet: Add CAddressBookData::IsChange which returns true iff label has never been set (Luke Dashjr)144b2f85da
Wallet: Require usage of new CAddressBookData::setLabel to change label (Luke Dashjr)b86cd155f6
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 ACKb5795a7886
. Pretty clever and nicely implemented fix! jonatack: ACKb5795a7886
nice improvements -- code review, built/ran tests rebased on current masterff53433fe4
and tested manually with rpc/cli jnewbery: Good fix. utACKb5795a788
. Tree-SHA512: 40525185a0bcc1723f602243c269499ec86ecb298fecb5ef24d626bbdd5e3efece86cdb1084ad7eebf7eeaf251db4a6e056bcd25bc8457b417fcbb53d032ebf0
This commit is contained in:
commit
c5966a87d1
9 changed files with 93 additions and 53 deletions
|
@ -151,8 +151,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) {
|
||||
|
@ -170,7 +170,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;
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -97,7 +97,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.
|
||||
|
|
|
@ -60,12 +60,13 @@ static bool GetWalletAddressesForKey(LegacyScriptPubKeyMan* spk_man, const CWall
|
|||
CKey key;
|
||||
spk_man->GetKey(keyid, key);
|
||||
for (const auto& dest : GetAllDestinationsForKey(key.GetPubKey())) {
|
||||
if (pwallet->mapAddressBook.count(dest)) {
|
||||
const auto* address_book_entry = pwallet->FindAddressBookEntry(dest);
|
||||
if (address_book_entry) {
|
||||
if (!strAddr.empty()) {
|
||||
strAddr += ",";
|
||||
}
|
||||
strAddr += EncodeDestination(dest);
|
||||
strLabel = EncodeDumpString(pwallet->mapAddressBook.at(dest).name);
|
||||
strLabel = EncodeDumpString(address_book_entry->name);
|
||||
fLabelFound = true;
|
||||
}
|
||||
}
|
||||
|
@ -168,7 +169,7 @@ UniValue importprivkey(const JSONRPCRequest& request)
|
|||
// label all new addresses, and label existing addresses if a
|
||||
// label was passed.
|
||||
for (const auto& dest : GetAllDestinationsForKey(pubkey)) {
|
||||
if (!request.params[1].isNull() || pwallet->mapAddressBook.count(dest) == 0) {
|
||||
if (!request.params[1].isNull() || !pwallet->FindAddressBookEntry(dest)) {
|
||||
pwallet->SetAddressBook(dest, strLabel, "receive");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -499,8 +499,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);
|
||||
|
@ -1092,13 +1093,13 @@ static UniValue ListReceived(interfaces::Chain::Lock& locked_chain, const CWalle
|
|||
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);
|
||||
}
|
||||
|
@ -1106,6 +1107,7 @@ static UniValue ListReceived(interfaces::Chain::Lock& locked_chain, const CWalle
|
|||
|
||||
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);
|
||||
|
@ -1307,8 +1309,9 @@ static void ListTransactions(interfaces::Chain::Lock& locked_chain, const CWalle
|
|||
MaybePushAddress(entry, s.destination);
|
||||
entry.pushKV("category", "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));
|
||||
|
@ -1324,8 +1327,9 @@ static void ListTransactions(interfaces::Chain::Lock& locked_chain, const CWalle
|
|||
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;
|
||||
|
@ -1349,7 +1353,7 @@ static void ListTransactions(interfaces::Chain::Lock& locked_chain, const CWalle
|
|||
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);
|
||||
|
@ -2957,9 +2961,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);
|
||||
|
@ -3816,8 +3820,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));
|
||||
|
@ -3840,14 +3845,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));
|
||||
|
@ -3891,10 +3895,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<const 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;
|
||||
|
@ -3955,7 +3960,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<const 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);
|
||||
}
|
||||
|
|
|
@ -1242,8 +1242,9 @@ bool CWallet::IsChange(const CScript& script) const
|
|||
return true;
|
||||
|
||||
LOCK(cs_wallet);
|
||||
if (!mapAddressBook.count(address))
|
||||
if (!FindAddressBookEntry(address)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -3196,11 +3197,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) );
|
||||
|
@ -3217,16 +3218,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);
|
||||
|
@ -3462,8 +3468,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)
|
||||
|
@ -3666,26 +3673,26 @@ bool CWallet::AddDestData(WalletBatch& batch, const CTxDestination &dest, const
|
|||
if (boost::get<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())
|
||||
|
@ -3701,7 +3708,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);
|
||||
|
@ -4103,12 +4110,22 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
|
|||
{
|
||||
walletInstance->WalletLogPrintf("setKeyPool.size() = %u\n", walletInstance->GetKeyPoolSize());
|
||||
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());
|
||||
}
|
||||
|
||||
return walletInstance;
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
auto locked_chain = chain().lock();
|
||||
|
|
|
@ -181,14 +181,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
|
||||
|
@ -775,7 +784,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);
|
||||
|
||||
|
@ -842,7 +852,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);
|
||||
|
|
|
@ -206,11 +206,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;
|
||||
|
|
|
@ -99,7 +99,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…
Add table
Reference in a new issue