-
Notifications
You must be signed in to change notification settings - Fork 38.8k
Bugfix: Correctly calculate balances when min_conf is used, and for getbalance("*") #14602
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
7809c34 to
0d4ff9b
Compare
src/wallet/rpcwallet.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should keep this as trusted_only|dummy to not break existing clients that use named args?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. Probably not, since afaik "dummy" has only ever been used in versions where it's actually broken anyway?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that dummy as a named arg doesn't need to be kept around, but if account was already removed as an alias, why add it back? This should just be trusted_only I think?
This is also the cause of the linter error, because trusted_only has an entry in vRPCConvertParams but account doesn't
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removing account appears to have been a bug, since we still accept "*" as a value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@luke-jr only as a dummy, hence the name, accounts are completely removed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"*" isn't an account.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then why would specifying it using account= make sense?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because that's what the parameter was called when named args were introduced.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, that name was already removed, so NACK on adding it back again, it makes no sense
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removing it introduced a bug by breaking existing code that uses the "*" mode.
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsReviewers, 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. |
|
I don't understand what the Travis linter is trying to complain about. |
|
I think the linter doesn't understand that an option can have two different types (and wants you to specify both conversions similar to |
34e258f to
5505437
Compare
jnewbery
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concept ACK adding an option to return a balance including untrusted transactions.
Thanks for catching the missing min_depth check in IsSpent.
I think this could do with some additional test cases in the wallet_basic.py test file.
src/wallet/rpcwallet.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should try to avoid having a single argument accept two different types. It's messy and I don't think it's supported by the CRPConvertTable logic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's only a boolean. The string stuff is strictly for backward compatibility.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree with @jnewbery, because you've added the argument to vRPCConvertParams it'll try and convert it from JSON despite it being a string? Have you tested this backwards compatibility? IMO if this is going to be done, we just drop the string part completely and put it in release notes as a breaking change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bitcoin-cli is just a testing tool. As such, I don't think we need to worry about backward compatibility there.
This is fully backward compatible with any normal JSON-RPC client.
src/wallet/rpcwallet.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer to drop this undocumented functionality if at all possible. It's confusing that getbalance and getbalance * should return different values (and this argument has been deprecated since 7b782f5).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They always have returned different values. I think the API changes here clear up the confusion?
|
Concept ACK |
|
Failing with |
|
@promag That's a linter bug, and IMO outside the scope of this PR to fix. It is correct that trusted_only is a JSON/converted parameter, and the account alias is a String parameter. |
src/wallet/rpcwallet.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that dummy as a named arg doesn't need to be kept around, but if account was already removed as an alias, why add it back? This should just be trusted_only I think?
This is also the cause of the linter error, because trusted_only has an entry in vRPCConvertParams but account doesn't
src/wallet/rpcwallet.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests are failing because this error message has been changed, you'll either need to update the tests or just change it back to "dummy first argument must be excluded or set to \"*\"."
src/wallet/rpcwallet.cpp
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree with @jnewbery, because you've added the argument to vRPCConvertParams it'll try and convert it from JSON despite it being a string? Have you tested this backwards compatibility? IMO if this is going to be done, we just drop the string part completely and put it in release notes as a breaking change
|
@luke-jr Needs rebase. |
|
It'd be great to have this in 0.17.1. @luke-jr Would you mind someone else rebasing this? |
|
Rebased |
5505437 to
cdc9814
Compare
|
Still needs comments above addressed too |
|
Test issues fixed |
meshcollider
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for splitting out the backport as we discussed on IRC.
| } else if (trusted_only_uv.isStr()) { | ||
| // backward compatibility | ||
| if (trusted_only_uv.get_str() != "*") { | ||
| throw JSONRPCError(RPC_METHOD_DEPRECATED, "accounts no longer supported; set 1st field to trusted_only"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO this would be better just to give a type error, that it should be boolean not string
| bool trusted_only = true; | ||
| if (trusted_only_uv.isBool()) { | ||
| trusted_only = trusted_only_uv.get_bool(); | ||
| } else if (trusted_only_uv.isStr()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This still won't work because of the entry in vRPCConvertParams. I don't think a single parameter can accept either a string or a boolean in this way, because there is no way to tell otherwise if true is supposed to be a string "true" (which should error) or the boolean value true (which should work). I think the only options are either to break compatibility and drop the "*" case in favor of the boolean only, or not switch to a boolean and just accept "*" and "" (empty string)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It works fine... the lookup table has no effect on the JSON-RPC server, only the bitcoin-cli testing tool.
| Needs rebase |
|
Would be nice to have a basic test that covers these changes. Otherwise a future refactoring or "bug fix" will likely break this again and all effort is undone. |
jnewbery
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've spent several hours reviewing and writing tests for this, and I'm now more convinced that we should try to remove the getbalance * usage. My tests are in this branch: https://github.com/jnewbery/bitcoin/tree/untrusted_balance. When I run them against a slightly modified version of this branch, there's all kinds of unintuitive behaviour like double counting conflicting transactions, or counting a transaction and its spending transaction. If I run the test against v0.16.3 I see other strange behaviour like negative balances.
The behaviour with this branch is different from v0.16.3, but I don't think either are good. It makes sense for there to be a method to see untrusted transactions, but summing them into a balance is dangerous and confusing for users.
Can we step back and answer what use case we're trying to support here? Why do we want to support a non-isTrusted balance? getbalance(minconf=0) already supports showing the unconfirmed balance, with the caveat that it only includes trusted unconfirmed txs (ie ones where all the inputs are from us and the tx is in the mempool).
|
|
||
| if (pcoin->GetDepthInMainChain(*locked_chain) < min_depth) continue; | ||
|
|
||
| nTotal += pcoin->GetAvailableCredit(*locked_chain, true, filter, min_depth); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This won't work. GetAvailableCredit() uses the nAvailableCreditCached cache, so it doesn't matter what value is passed in as min_depth here after the first call.
…s that were spent more recently
jnewbery
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR needs a few things before I'd consider it ready for merge:
- A rationale for why we'd want to provide this 'feature'. Summing up untrusted coins into a 'balance' can lead to very confusing results, such as negative balances and double-counting conflicting transactions. An uninformed user could see money 'disappear' or be tricked into thinking they've received money which they haven't.
- Full documentation of the usage. I removed
getbalance *here: https://github.com/bitcoin/bitcoin/pull/12953/files#diff-df7d84ff2f53fcb2a0dc15a3a51e55ceL822 because the option had been marked as deprecated. If we want to support this usage, then it should be properly documented, with appropriate warnings and caveats. - Full test coverage, so this doesn't get regressed again. I wrote some tests here: https://github.com/jnewbery/bitcoin/tree/untrusted_balance in the course of reviewing this PR.
- Not gratuitously breaking bitcoin-cli because you don't happen to use it.
| } else if (filter == ISMINE_WATCH_ONLY) { | ||
| cache = &nAvailableWatchCreditCached; | ||
| cache_used = &fAvailableWatchCreditCached; | ||
| if (min_depth == 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please at least add a comment here to explain why you're not hitting/updating the cache if min_depth != 0
@luke-jr I agree with this, but I don't understand if adding up values of |
c1825b9 [tests] Add wallet_balance.py (John Newbery) Pull request description: Adds a test specifically to test the wallet's getbalance and getunconfirmedbalance RPCs. `wallet_basic.py` is too large and should be broken down into more focused test cases. I wrote `wallet_balance.py` to test the changes in bitcoin#14602. Offering as a PR in case people think it's more generally useful. Tree-SHA512: 573ae8faf377df3d87d5112870b40690efb285fc5578fff8acc2ac1a0e4625ae65d3dfa8abbac577c87bec015038f425833783fa09f014f87906e8d098ed30d7
| { "wallet", "encryptwallet", &encryptwallet, {"passphrase"} }, | ||
| { "wallet", "getaddressesbylabel", &getaddressesbylabel, {"label"} }, | ||
| { "wallet", "getaddressinfo", &getaddressinfo, {"address"} }, | ||
| { "wallet", "getbalance", &getbalance, {"dummy","minconf","include_watchonly"} }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dummy should stay otherwise it breaks calls using named parameters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"dummy" has NEVER worked as a named parameter. The only calls using named parameters where this ever worked, used the name "account"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just tested v0.17.0 and the following works:
bitcoin-cli -regtest --named getbalance account="*"
5097.99999647
bitcoin-cli -regtest --named getbalance dummy="*"
5097.99999647
|
Closing this for now. |
getbalance("*")has always given the final balance ignoring whether the wallet considers coins trusted or not, whilegetbalance()checked the trusted status.Furthermore,
CWallet::GetBalance(the trusted-only implementation) did not support setting amin_confparameter. This was added in #13566, but only checkedmin_conffor UTXO creation, not UTXO spending.This fixes
getbalanceto work correctly in both regards.It also renames the dummy argument to
trusted_onlyand accepts a boolean instead of the fixed string"*"to fit more with the no-accounts stuff.See also: #6276 fixed the first issue in 2015.