From dcd0b0775ef63ac9e067d9eb67012332f1a72bd7 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 29 Aug 2013 16:19:43 +0200 Subject: [PATCH] qt: Handle address purpose in incremental updates Correctly use the purpose of addresses that are added after the start of the client. Addresses with purpose "refund" and "change" should not be visible in the GUI. This is now handled correctly. --- src/qt/addresstablemodel.cpp | 40 +++++++++++++++++++------------- src/qt/addresstablemodel.h | 2 +- src/qt/transactiontablemodel.cpp | 10 ++++---- src/qt/walletmodel.cpp | 17 +++++++++----- src/qt/walletmodel.h | 2 +- src/wallet.cpp | 8 +++++-- src/wallet.h | 8 +++++-- 7 files changed, 54 insertions(+), 33 deletions(-) diff --git a/src/qt/addresstablemodel.cpp b/src/qt/addresstablemodel.cpp index 03517c657..69355febe 100644 --- a/src/qt/addresstablemodel.cpp +++ b/src/qt/addresstablemodel.cpp @@ -15,7 +15,8 @@ struct AddressTableEntry { enum Type { Sending, - Receiving + Receiving, + Hidden /* QSortFilterProxyModel will filter these out */ }; Type type; @@ -43,6 +44,20 @@ struct AddressTableEntryLessThan } }; +/* Determine address type from address purpose */ +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. + if (strPurpose == "send") + addressType = AddressTableEntry::Sending; + else if (strPurpose == "receive") + addressType = AddressTableEntry::Receiving; + else if (strPurpose == "unknown" || strPurpose == "") // if purpose not set, guess + addressType = (isMine ? AddressTableEntry::Receiving : AddressTableEntry::Sending); + return addressType; +} + // Private implementation class AddressTablePriv { @@ -62,17 +77,9 @@ public: BOOST_FOREACH(const PAIRTYPE(CTxDestination, CAddressBookData)& item, wallet->mapAddressBook) { const CBitcoinAddress& address = item.first; - - AddressTableEntry::Type addressType; - const std::string& strPurpose = item.second.purpose; - if (strPurpose == "send") addressType = AddressTableEntry::Sending; - else if (strPurpose == "receive") addressType = AddressTableEntry::Receiving; - else if (strPurpose == "unknown") { - bool fMine = IsMine(*wallet, address.Get()); - addressType = (fMine ? AddressTableEntry::Receiving : AddressTableEntry::Sending); - } - else continue; // "refund" addresses aren't shown, and change addresses aren't in mapAddressBook at all. - + bool fMine = IsMine(*wallet, address.Get()); + AddressTableEntry::Type addressType = translateTransactionType( + QString::fromStdString(item.second.purpose), fMine); const std::string& strName = item.second.name; cachedAddressTable.append(AddressTableEntry(addressType, QString::fromStdString(strName), @@ -83,7 +90,7 @@ public: qSort(cachedAddressTable.begin(), cachedAddressTable.end(), AddressTableEntryLessThan()); } - void updateEntry(const QString &address, const QString &label, bool isMine, int status) + void updateEntry(const QString &address, const QString &label, bool isMine, const QString &purpose, int status) { // Find address / label in model QList::iterator lower = qLowerBound( @@ -93,7 +100,7 @@ public: int lowerIndex = (lower - cachedAddressTable.begin()); int upperIndex = (upper - cachedAddressTable.begin()); bool inModel = (lower != upper); - AddressTableEntry::Type newEntryType = isMine ? AddressTableEntry::Receiving : AddressTableEntry::Sending; + AddressTableEntry::Type newEntryType = translateTransactionType(purpose, isMine); switch(status) { @@ -322,10 +329,11 @@ QModelIndex AddressTableModel::index(int row, int column, const QModelIndex &par } } -void AddressTableModel::updateEntry(const QString &address, const QString &label, bool isMine, int status) +void AddressTableModel::updateEntry(const QString &address, + const QString &label, bool isMine, const QString &purpose, int status) { // Update address book model from Bitcoin core - priv->updateEntry(address, label, isMine, status); + priv->updateEntry(address, label, isMine, purpose, status); } QString AddressTableModel::addRow(const QString &type, const QString &label, const QString &address) diff --git a/src/qt/addresstablemodel.h b/src/qt/addresstablemodel.h index 48baff5e5..6f532087f 100644 --- a/src/qt/addresstablemodel.h +++ b/src/qt/addresstablemodel.h @@ -85,7 +85,7 @@ signals: public slots: /* Update address list from core. */ - void updateEntry(const QString &address, const QString &label, bool isMine, int status); + void updateEntry(const QString &address, const QString &label, bool isMine, const QString &purpose, int status); friend class AddressTablePriv; }; diff --git a/src/qt/transactiontablemodel.cpp b/src/qt/transactiontablemodel.cpp index baf1e1648..977e56a2b 100644 --- a/src/qt/transactiontablemodel.cpp +++ b/src/qt/transactiontablemodel.cpp @@ -20,11 +20,11 @@ // Amount column is right-aligned it contains numbers static int column_alignments[] = { - Qt::AlignLeft|Qt::AlignVCenter, - Qt::AlignLeft|Qt::AlignVCenter, - Qt::AlignLeft|Qt::AlignVCenter, - Qt::AlignLeft|Qt::AlignVCenter, - Qt::AlignRight|Qt::AlignVCenter + Qt::AlignLeft|Qt::AlignVCenter, /* status */ + Qt::AlignLeft|Qt::AlignVCenter, /* date */ + Qt::AlignLeft|Qt::AlignVCenter, /* type */ + Qt::AlignLeft|Qt::AlignVCenter, /* address */ + Qt::AlignRight|Qt::AlignVCenter /* amount */ }; // Comparison operator for sort/binary search of model tx list diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 61357647b..82dc075a7 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -112,10 +112,11 @@ void WalletModel::updateTransaction(const QString &hash, int status) } } -void WalletModel::updateAddressBook(const QString &address, const QString &label, bool isMine, int status) +void WalletModel::updateAddressBook(const QString &address, const QString &label, + bool isMine, const QString &purpose, int status) { if(addressTableModel) - addressTableModel->updateEntry(address, label, isMine, status); + addressTableModel->updateEntry(address, label, isMine, purpose, status); } bool WalletModel::validateAddress(const QString &address) @@ -351,13 +352,17 @@ static void NotifyKeyStoreStatusChanged(WalletModel *walletmodel, CCryptoKeyStor QMetaObject::invokeMethod(walletmodel, "updateStatus", Qt::QueuedConnection); } -static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet, const CTxDestination &address, const std::string &label, bool isMine, ChangeType status) +static void NotifyAddressBookChanged(WalletModel *walletmodel, CWallet *wallet, + const CTxDestination &address, const std::string &label, bool isMine, + const std::string &purpose, ChangeType status) { - OutputDebugStringF("NotifyAddressBookChanged %s %s isMine=%i status=%i\n", CBitcoinAddress(address).ToString().c_str(), label.c_str(), isMine, status); + OutputDebugStringF("NotifyAddressBookChanged %s %s isMine=%i purpose=%s status=%i\n", + CBitcoinAddress(address).ToString().c_str(), label.c_str(), isMine, purpose.c_str(), status); QMetaObject::invokeMethod(walletmodel, "updateAddressBook", Qt::QueuedConnection, Q_ARG(QString, QString::fromStdString(CBitcoinAddress(address).ToString())), Q_ARG(QString, QString::fromStdString(label)), Q_ARG(bool, isMine), + Q_ARG(QString, QString::fromStdString(purpose)), Q_ARG(int, status)); } @@ -373,7 +378,7 @@ void WalletModel::subscribeToCoreSignals() { // Connect signals to wallet wallet->NotifyStatusChanged.connect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1)); - wallet->NotifyAddressBookChanged.connect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5)); + wallet->NotifyAddressBookChanged.connect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5, _6)); wallet->NotifyTransactionChanged.connect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3)); } @@ -381,7 +386,7 @@ void WalletModel::unsubscribeFromCoreSignals() { // Disconnect signals from wallet wallet->NotifyStatusChanged.disconnect(boost::bind(&NotifyKeyStoreStatusChanged, this, _1)); - wallet->NotifyAddressBookChanged.disconnect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5)); + wallet->NotifyAddressBookChanged.disconnect(boost::bind(NotifyAddressBookChanged, this, _1, _2, _3, _4, _5, _6)); wallet->NotifyTransactionChanged.disconnect(boost::bind(NotifyTransactionChanged, this, _1, _2, _3)); } diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 8cba10f5d..ff7ded7b4 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -165,7 +165,7 @@ public slots: /* New transaction, or transaction changed status */ void updateTransaction(const QString &hash, int status); /* New, updated or removed address book entry */ - void updateAddressBook(const QString &address, const QString &label, bool isMine, int status); + void updateAddressBook(const QString &address, const QString &label, bool isMine, const QString &purpose, int status); /* Current, immature or unconfirmed balance might have changed - emit 'balanceChanged' if so */ void pollBalanceChanged(); }; diff --git a/src/wallet.cpp b/src/wallet.cpp index 7a3855c02..54ede12a5 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -1461,7 +1461,11 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const string& strNam { std::map::iterator mi = mapAddressBook.find(address); mapAddressBook[address].name = strName; - NotifyAddressBookChanged(this, address, strName, ::IsMine(*this, address), (mi == mapAddressBook.end()) ? CT_NEW : CT_UPDATED); + if (!strPurpose.empty()) /* update purpose only if requested */ + mapAddressBook[address].purpose = strPurpose; + NotifyAddressBookChanged(this, address, strName, ::IsMine(*this, address), + mapAddressBook[address].purpose, + (mi == mapAddressBook.end()) ? CT_NEW : CT_UPDATED); if (!fFileBacked) return false; if (!strPurpose.empty() && !CWalletDB(strWalletFile).WritePurpose(CBitcoinAddress(address).ToString(), strPurpose)) @@ -1472,7 +1476,7 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const string& strNam bool CWallet::DelAddressBook(const CTxDestination& address) { mapAddressBook.erase(address); - NotifyAddressBookChanged(this, address, "", ::IsMine(*this, address), CT_DELETED); + NotifyAddressBookChanged(this, address, "", ::IsMine(*this, address), "", CT_DELETED); if (!fFileBacked) return false; CWalletDB(strWalletFile).ErasePurpose(CBitcoinAddress(address).ToString()); diff --git a/src/wallet.h b/src/wallet.h index d61548433..b529d5f28 100644 --- a/src/wallet.h +++ b/src/wallet.h @@ -335,12 +335,16 @@ public: /** Address book entry changed. * @note called with lock cs_wallet held. */ - boost::signals2::signal NotifyAddressBookChanged; + boost::signals2::signal NotifyAddressBookChanged; /** Wallet transaction added, removed or updated. * @note called with lock cs_wallet held. */ - boost::signals2::signal NotifyTransactionChanged; + boost::signals2::signal NotifyTransactionChanged; }; /** A key allocated from the key pool. */