This addresses a few remaining issues pointed out in #13756:
- First commit addresses #13756 (review)
- Second commit addresses #13756 (review)
Ping jnewbery and achow101 as they pointed out these issues.
This addresses a few remaining issues pointed out in #13756:
Ping jnewbery and achow101 as they pointed out these issues.
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.
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.
2408@@ -2409,6 +2409,7 @@ static UniValue getbalances(const JSONRPCRequest& request)
2409 " \"trusted\": xxx (numeric) trusted balance (outputs created by the wallet or confirmed outputs)\n"
2410 " \"untrusted_pending\": xxx (numeric) untrusted pending balance (outputs created by others that are in the mempool)\n"
2411 " \"immature\": xxx (numeric) balance from immature coinbase outputs\n"
2412+ " \"used\": xxx (numeric) balance from coins sent to addresses that were previously spent from (potentially privacy violating)\n"
7e7bb17352a3a74e142eae20572a163384fa1502
Only present if avoid_reuse
flag is set.
2434@@ -2434,13 +2435,16 @@ static UniValue getbalances(const JSONRPCRequest& request)
2435
2436 UniValue obj(UniValue::VOBJ);
2437
2438+ bool avoid_reuse = wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
7e7bb17352a3a74e142eae20572a163384fa1502
nit, const
2442 {
2443 UniValue balances_mine{UniValue::VOBJ};
2444 balances_mine.pushKV("trusted", ValueFromAmount(bal.m_mine_trusted));
2445 balances_mine.pushKV("untrusted_pending", ValueFromAmount(bal.m_mine_untrusted_pending));
2446 balances_mine.pushKV("immature", ValueFromAmount(bal.m_mine_immature));
2447+ if (avoid_reuse) balances_mine.pushKV("used", ValueFromAmount(bal_used.m_mine_trusted + bal_used.m_mine_untrusted_pending - bal.m_mine_trusted - bal.m_mine_untrusted_pending));
7e7bb17352a3a74e142eae20572a163384fa1502
Maybe test that this is not present if avoid_reused
flag is not set.
2890@@ -2891,9 +2891,8 @@ static UniValue listunspent(const JSONRPCRequest& request)
2891
2892 bool avoid_reuse = pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
5e704ab66336eafef2955e3087f7bbf8c7ca26cd
Move after wallet lock in L3023.
2928@@ -2930,9 +2929,7 @@ static UniValue listunspent(const JSONRPCRequest& request)
2929 " \"witnessScript\" : \"script\" (string) witnessScript if the scriptPubKey is P2WSH or P2SH-P2WSH\n"
2930 " \"spendable\" : xxx, (bool) Whether we have the private keys to spend this output\n"
2931 " \"solvable\" : xxx, (bool) Whether we know how to spend this output, ignoring the lack of keys\n"
2932- + (avoid_reuse ?
2933- " \"reused\" : xxx, (bool) Whether this output is reused/dirty (sent to an address that was previously spent from)\n" :
2934- "") +
2935+ " \"reused\" : xxx, (bool) Whether this output is reused/dirty (sent to an address that was previously spent from)\n"
5e704ab66336eafef2955e3087f7bbf8c7ca26cd
Mention “only present if avoid_reuse flag is set”.
3019@@ -3017,6 +3020,8 @@ static UniValue listunspent(const JSONRPCRequest& request)
3020
3021 LOCK(pwallet->cs_wallet);
3022
3023+ bool avoid_reuse = pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
67+ '''Make assertions about a node's getbalances output'''
68+ balances = node.getbalances()
69+ if mine:
70+ got = balances["mine"]
71+ for k,v in mine.items():
72+ assert(k in got)
assert_approx
are enough.
6@@ -7,7 +7,7 @@ A new wallet flag `avoid_reuse` has been added (default off). When enabled,
7 a wallet will distinguish between used and unused addresses, and default to not
8 use the former in coin selection.
9
10-(Note: rescanning the blockchain is required, to correctly mark previously
11+(Rescanning the blockchain is required, to correctly mark previously
0Rescanning the blockchain is required, to correctly mark previously
29@@ -30,10 +30,12 @@ These include:
30
31 - createwallet
32 - getbalance
33+- getbalances
34 - sendtoaddress
35
36-In addition, `sendtoaddress` has been changed to enable `-avoidpartialspends` when
37-`avoid_reuse` is enabled.
38+In addition, `sendtoaddress` has been changed to always use `-avoidpartialspends`
0In addition, `sendtoaddress` has been changed to avoid partial spends ... (if not already enabled via the `-avoidpartialspends` command line flag) ...
62@@ -63,6 +63,18 @@ def assert_unspent(node, total_count=None, total_sum=None, reused_supported=None
63 if reused_sum is not None:
64 assert_approx(stats["reused"]["sum"], reused_sum, 0.001)
65
66+def assert_balances(node, mine=None, watchonly=None):
watchonly
is ever used. Just remove it (and the if watchonly
block in the function)
11@@ -12,11 +12,11 @@
12 )
13
14 # TODO: Copied from wallet_groups.py -- should perhaps move into util.py
15-def assert_approx(v, vexp, vspan=0.00001):
16+def assert_approx(v, vexp, vspan=0.00001, descr=None):
assert_balances()
is never called with watchonly
, and so assert_approx()
is only called for mine
balances.
Code looks good, code review ACK https://github.com/bitcoin/bitcoin/pull/16239/commits/7f39c40a332824043e3bef282580daf748131bb4
I’m just slightly unsure about the word “used” in the getbalance RPC, could seem like the balance which has been used (spent) rather than the balance which is “dirty” or “reused” or something
I initially used the word “dirty”, but then realized that is internally used for something else in the wallet, and there was a comment about “dirty” being confusing in #13756 (comment)
I think “dirty” is a confusing concept. Maybe add an exclamation mark (or a detective icon) next to the transaction and when the user clicks on that, say something like “This address has been used before, for privacy reasons it’s better to create a new address each time you wish to receive coins, even from the same person”.
(in reference to a GUI comment).
I’m open for changing it, but I’m not sure what would be a good name for it.
I’m open for changing it, but I’m not sure what would be a good name for it.
How about “used address balance” or “reused address balance”? Bit of a mouthful, but at least it’s explicit.
@jnewbery A bit long, maybe.. I mean, if we change it I would ideally like to change it everywhere, including the “avoid_reuse” flags in RPC commands and such.
Even “used”/“reused” does not accurately describe what this is referring to, as evident by the fact I as the author screwed it up (thankfully @jnewbery caught that one).
“UTXO/balance that was sent to an address after it was spent from”
2434@@ -2434,13 +2435,16 @@ static UniValue getbalances(const JSONRPCRequest& request)
2435
2436 UniValue obj(UniValue::VOBJ);
2437
2438+ const bool avoid_reuse = wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
2439 const auto bal = wallet.GetBalance();
2440+ const auto bal_used = avoid_reuse ? wallet.GetBalance(0, false) : bal;
I felt like this logic could have used more commenting, and the variable was a bit confusingly named (and also could potentially be scoped more tightly).
I think the following is equivalent, but perhaps a little clearer:
0→ git d
1diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
2index ce1c94905..f53469ce6 100644
3--- a/src/wallet/rpcwallet.cpp
4+++ b/src/wallet/rpcwallet.cpp
5@@ -2435,16 +2435,19 @@ static UniValue getbalances(const JSONRPCRequest& request)
6
7 UniValue obj(UniValue::VOBJ);
8
9- const bool avoid_reuse = wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
10 const auto bal = wallet.GetBalance();
11- const auto bal_used = avoid_reuse ? wallet.GetBalance(0, false) : bal;
12 UniValue balances{UniValue::VOBJ};
13 {
14 UniValue balances_mine{UniValue::VOBJ};
15 balances_mine.pushKV("trusted", ValueFromAmount(bal.m_mine_trusted));
16 balances_mine.pushKV("untrusted_pending", ValueFromAmount(bal.m_mine_untrusted_pending));
17 balances_mine.pushKV("immature", ValueFromAmount(bal.m_mine_immature));
18- if (avoid_reuse) balances_mine.pushKV("used", ValueFromAmount(bal_used.m_mine_trusted + bal_used.m_mine_untrusted_pending - bal.m_mine_trusted - bal.m_mine_untrusted_pending));
19+ if (wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE)) {
20+ // If the AVOID_REUSE flag is set, bal has been set to just the un-reused address balance. Get
21+ // the total balance, and then subtract bal to get the reused address balance.
22+ const auto full_bal = wallet.GetBalance(0, false);
23+ balances_mine.pushKV("used", ValueFromAmount(full_bal.m_mine_trusted + full_bal.m_mine_untrusted_pending - bal.m_mine_trusted - bal.m_mine_untrusted_pending));
24+ }
25 balances.pushKV("mine", balances_mine);
26 }
27 if (wallet.HaveWatchOnly()) {
Feel free to use if you think that’s better.
62@@ -63,6 +63,13 @@ def assert_unspent(node, total_count=None, total_sum=None, reused_supported=None
63 if reused_sum is not None:
64 assert_approx(stats["reused"]["sum"], reused_sum, 0.001)
65
66+def assert_balances(node, mine):
67+ '''Make assertions about a node's getbalances output'''
68+ balances = node.getbalances()
69+ got = balances["mine"]
ACK 7f39c40a332824043e3bef282580daf748131bb4 (reviewed code and ran tests locally)
I’ve left a couple of style nits inline. Feel free to take or leave.
Always show the same help topic regardless of wallet flags, and explain that something is not always available, rather than runtime-modifying the help output.
ACK 71d0344cf25d3aaf60112c5248198c444bc98105
Thanks for quick turnaround!