Skip to content

Conversation

za-kk
Copy link
Contributor

@za-kk za-kk commented Nov 2, 2019

Implements issue #17174, to grey out used addresses in the address book when the wallet has the avoid_reuse flag set.

this commit brings the IsUsedDestination method into the Wallet.h interface. It is then called in addresstablemodel.cpp to determine whether the address has been used or not whilst setting the font colour

master
Screenshot 2019-11-02 at 17 36 51

pr
Screenshot 2019-11-02 at 17 33 41

@za-kk za-kk changed the title Grey out used address in address book gui: grey out used address in address book Nov 2, 2019
@fanquake fanquake added the GUI label Nov 2, 2019
@luke-jr
Copy link
Member

luke-jr commented Nov 2, 2019

Addresses are used when they receive. Not when the UTXO created is later spent.

@za-kk
Copy link
Contributor Author

za-kk commented Nov 4, 2019

Addresses are used when they receive. Not when the UTXO created is later spent.

Understood, I can update it to grey out just addresses that have received (Used) and not ones that have received and been spent if desired?

@luke-jr
Copy link
Member

luke-jr commented Nov 4, 2019

Understood, I can update it to grey out just addresses that have received (Used) and not ones that have received and been spent if desired?

Yes (it would be meaningless/erroneous to grey out addresses based on actions of the UTXOs created when they receive).

@jonasschnelli
Copy link
Contributor

Agree with @luke-jr. This is currently conceptual wrong.

@maflcko
Copy link
Member

maflcko commented Nov 4, 2019

So if the existing used-flag is supposed to do what it does (indicate true when the coin sent to that destination has been spent), it could make sense to add a new flag (indicate true when a tx has been received that has the destination in one of its outputs).

@luke-jr
Copy link
Member

luke-jr commented Nov 4, 2019

See also #15987, but I'm not sure it's the best approach to use here. If we're going to check every address (as this does), we should probably save a flag in the wallet/address book when we see an address used...

@za-kk za-kk closed this Feb 10, 2020
@za-kk za-kk reopened this Feb 11, 2020
@za-kk
Copy link
Contributor Author

za-kk commented Feb 11, 2020

Revisiting this pr...

I have now re-implemented by saving a flag in the address book (address_used) when we see an address used. I took the same approach as the IsUsedDestination methods and therefor this will only work when the avoid_reuse flag is set on the wallet.

This essentially checks the outputs when a transaction is added to the wallet (AddToWallet) and if it belongs to us, sets a flag in the address book (SetUsedAddressState). It will then grey out any addresses with this flag set when viewing them in the 'Receiving Addresses' dialog box.

@dannmat
Copy link

dannmat commented Feb 11, 2020

ack

@DrahtBot
Copy link
Contributor

DrahtBot commented Feb 11, 2020

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Conflicts

Reviewers, this pull request conflicts with the following ones:

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

@luke-jr
Copy link
Member

luke-jr commented Feb 23, 2020

IMO this should work for all wallets, and when loading an old wallet (or one that has been loaded by an older version since the last use of a supporting version), should populate the flag as necessary.

@za-kk
Copy link
Contributor Author

za-kk commented Feb 24, 2020

IMO this should work for all wallets, and when loading an old wallet (or one that has been loaded by an older version since the last use of a supporting version), should populate the flag as necessary.

@luke-jr I would be inclined to agree with you on this, it was only initially constrained to avoid_reuse wallets as IsUsedDestination was used in the first integration (although wrongly used due to confusion). So pivoting back to working for all wallets would make sense.

Would like to get others opinions on this before progressing with making the changes, thoughts @MarcoFalke @jonasschnelli @promag?

@za-kk
Copy link
Contributor Author

za-kk commented May 26, 2020

Rebased with master and squashed commits.

Thinking of picking this back up if it is still a desirable change/feature? Currently it's limited to watch only wallets but as @luke-jr mentioned, this may be desirable to all wallet types

@jonasschnelli
Copy link
Contributor

Concept ACK on how this works today. Slightly reviewed the code and it looks good.

Can you please review @luke-jr, @promag?

@za-kk
Copy link
Contributor Author

za-kk commented Jul 4, 2021

This should now be ready for review again, I have implemented the suggested changes made by @promag.

@za-kk za-kk requested review from jonatack and promag July 4, 2021 17:24
@ghost
Copy link

ghost commented Jul 4, 2021

Concept ACK

nit: grey if used once and red if used twice or more would have been better

Will test by tomorrow

Copy link
Member

@jonatack jonatack left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for updating! This is a bit of a drive-by review as the hour is late, but I was unable to build (with clang 11 on debian) after rebasing on current master at 7a49fdc :

wallet/wallet.cpp:878:15: error: out-of-line definition of 'SetUsedAddressState' does not match any declaration in 'CWallet'
void CWallet::SetUsedAddressState(WalletBatch& batch, const CTxOut& cout, const uint256& hash)
              ^~~~~~~~~~~~~~~~~~~
./wallet/wallet.h:460:70: note: type of 3rd parameter of member declaration does not match definition ('uint256' vs 'const uint256 &')
    void SetUsedAddressState(WalletBatch& batch, const CTxOut& cout, uint256 hash) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
                                                                     ^
wallet/wallet.cpp:883:9: error: use of undeclared identifier 'AddDestData'
        AddDestData(batch, dst, "first_txid", hash.ToString());
        ^
wallet/wallet.cpp:884:9: error: no matching function for call to object of type 'boost::signals2::signal<void (const CTxDestination &, const std::string &, bool, const std::string &, ChangeType)>' (aka 'signal<void (const variant<CNoDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, WitnessUnknown> &, const basic_string<char> &, bool, const basic_string<char> &, ChangeType)>')
        NotifyAddressBookChanged(this, dst, m_address_book[dst].GetLabel(), IsMine(dst) != ISMINE_NO, "receive", CT_UPDATED );
        ^~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/boost/signals2/detail/signal_template.hpp:720:19: note: candidate function not viable: requires 5 arguments, but 6 were provided
      result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS))
                  ^
/usr/include/boost/signals2/detail/signal_template.hpp:724:19: note: candidate function not viable: requires 5 arguments, but 6 were provided
      result_type operator ()(BOOST_SIGNALS2_SIGNATURE_FULL_ARGS(BOOST_SIGNALS2_NUM_ARGS)) const
                  ^
wallet/wallet.cpp:891:12: error: use of undeclared identifier 'GetDestData'
    return GetDestData(dst, "first_txid", nullptr);
           ^
4 errors generated.

@za-kk
Copy link
Contributor Author

za-kk commented Jul 5, 2021

Thanks for taking a look @jonatack! seems that some latest merges to master has resulted in changes to destdata (#21353) which was causing the build issues. I have now refactored the code to deal with this (bb47908)

Copy link

@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tACK bb47908 There are few issues which should be fixed as mentioned in #17355 (review) and confirmed below

@ghost
Copy link

ghost commented Jul 5, 2021

Compiled successfully on Linux (Pop!_OS). Works as expected. Addresses were greyed out once I sent bitcoin to first 2 addresses from the 'receiving addresses':

image

Although if a user cares about privacy, should never open 'received addresses' for using. Once a receiving address is created, it should be considered used. Best practice is to create a new address every time you need an address for receiving bitcoin.

Copy link
Member

@jonatack jonatack left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some comments for your consideration. The pull doesn't necessarily need to be done in one commit depending on how you organise the changes and provided they are hygienic, but the "fix up to make it build" commit probably should be squashed into the relevant changes. Don't hesitate to run clang-format on your changes.

CTxDestination dst;
if (ExtractDestination(cout.scriptPubKey, dst) && IsMine(dst)) {

m_address_book[dst].destdata.insert(std::make_pair("first_txid", hash.ToString()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
m_address_book[dst].destdata.insert(std::make_pair("first_txid", hash.ToString()));
m_address_book[dst].destdata.emplace(std::make_pair("first_txid", hash.ToString()));

@@ -231,6 +234,16 @@ QVariant AddressTableModel::data(const QModelIndex &index, int role) const
} // no default case, so the compiler can warn about missing cases
assert(false);
}
else if (role == Qt::ForegroundRole) {
if (rec->is_used == true) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (rec->is_used == true) {
if (rec->is_used) {

}
}
else if (role == Qt::ToolTipRole) {
if (rec->is_used == true) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (rec->is_used == true) {
if (rec->is_used) {

@@ -456,6 +456,9 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
void SetSpentKeyState(WalletBatch& batch, const uint256& hash, unsigned int n, bool used, std::set<CTxDestination>& tx_destinations) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);

std::vector<OutputGroup> GroupOutputs(const std::vector<COutput>& outputs, const CoinSelectionParams& coin_sel_params, const CoinEligibilityFilter& filter, bool positive_only) const;
//! Whether this address has been used (has received).
void SetAddressReceivedState(WalletBatch& batch, const CTxOut& cout, const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first argument of SetAddressReceivedState() seems unused unless I'm missing something.

Suggested change
void SetAddressReceivedState(WalletBatch& batch, const CTxOut& cout, const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
void SetAddressReceivedState(const CTxOut& cout, const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);

}
}
return false;
}
Copy link
Member

@jonatack jonatack Jul 6, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style nit: clang format and also can simplify

 bool CWallet::HasAddressReceived(const CTxDestination& dst) const
 {
-
     const std::string key{"first_txid"};
-    std::map<CTxDestination, CAddressBookData>::const_iterator i = m_address_book.find(dst);
-    if(i != m_address_book.end())
-    {
-        CAddressBookData::StringMap::const_iterator j = i->second.destdata.find(key);
-        if(j != i->second.destdata.end())
-        {
-            return true;
-        }
-    }
-    return false;
+    const std::map<CTxDestination, CAddressBookData>::const_iterator it{m_address_book.find(dst)};
+    return it != m_address_book.end() && it->second.destdata.find(key) != it->second.destdata.end() ? true : false;
 }

AssertLockHeld(cs_wallet);
CTxDestination dst;
if (ExtractDestination(cout.scriptPubKey, dst) && IsMine(dst)) {

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, omit extra line break here and also line 891 below

Copy link
Contributor

@ryanofsky ryanofsky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewing bb47908. This seems pretty good but:

  • It seems like SetAddressReceivedState should be called in LoadToWallet as well as AddToWallet, not just AddToWallet so old and new addresses are displayed correctly, not just oldnew addresses.
  • It seems like SetAddressReceivedState should be called regardless of WALLET_FLAG_AVOID_REUSE flag. The avoid reuse feature is for detecting addresses that we previously spent from (and avoiding spending from them again). This feature is about detecting which addresses we previously received to, which is not directly related, and probably doesn't need a feature flag since it doesn't affect the wallet database storage.
  • Would seem more efficient and simpler to a add new bool CAddressBookData::received member instead of adding a "first_txid" entry and transaction hash to the CAddressBookData::destdata map
  • Could be nice to have some test coverage for this in https://github.com/bitcoin/bitcoin/blob/master/src/qt/test/wallettests.cpp

EDIT: corrected old/new above

@ghost
Copy link

ghost commented Jul 6, 2021

It seems like SetAddressReceivedState should be called in LoadToWallet as well as AddToWallet, not just AddToWallet so old and new addresses are displayed correctly, not just old addresses.

I relaunched bitcoin-qt today and my old addresses which had received bitcoin, were marked grey yesterday are not greyed out now:

image

It seems like SetAddressReceivedState should be called regardless of WALLET_FLAG_AVOID_REUSE flag. The avoid reuse feature is for detecting addresses that we previously spent from (and avoiding spending from them again). This feature is about detecting which addresses we previously received to, which is not directly related, and probably doesn't need a feature flag since it doesn't affect the wallet database storage.

Agree

@ghost ghost mentioned this pull request Jul 10, 2021
@DrahtBot
Copy link
Contributor

DrahtBot commented Sep 3, 2021

🐙 This pull request conflicts with the target branch and needs rebase.

Want to unsubscribe from rebase notifications on this pull request? Just convert this pull request to a "draft".

@za-kk
Copy link
Contributor Author

za-kk commented Nov 14, 2021

Thanks for the feedback everyone! Closing this PR for now until I have more time to come back and implement the changes, anyone else is welcome to pick it up in the meantime if desired 😀

@za-kk za-kk closed this Nov 14, 2021
@bitcoin bitcoin locked and limited conversation to collaborators Nov 14, 2022
@fanquake
Copy link
Member

Removing "Up for grabs" here. Followup could start in bitcoin-core/gui#528, or the QML repo.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.