Skip to content

Conversation

@luke-jr
Copy link
Member

@luke-jr luke-jr commented Oct 29, 2018

getbalance("*") has always given the final balance ignoring whether the wallet considers coins trusted or not, while getbalance() checked the trusted status.

Furthermore, CWallet::GetBalance (the trusted-only implementation) did not support setting a min_conf parameter. This was added in #13566, but only checked min_conf for UTXO creation, not UTXO spending.

This fixes getbalance to work correctly in both regards.

It also renames the dummy argument to trusted_only and 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.

@luke-jr luke-jr force-pushed the bugfix_rpc_getbalance_untrusted branch 2 times, most recently from 7809c34 to 0d4ff9b Compare October 29, 2018 16:06
Copy link
Member

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?

Copy link
Member Author

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?

Copy link
Contributor

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

Copy link
Member Author

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?

Copy link
Contributor

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

Copy link
Member Author

Choose a reason for hiding this comment

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

"*" isn't an account.

Copy link
Contributor

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?

Copy link
Member Author

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.

Copy link
Contributor

@meshcollider meshcollider Nov 10, 2018

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

Copy link
Member Author

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.

@DrahtBot
Copy link
Contributor

DrahtBot commented Oct 29, 2018

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

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #14726 (Use RPCHelpMan for all RPCs by MarcoFalke)
  • #14707 ([RPC] Include coinbase transactions in receivedby RPCs by andrewtoth)
  • #14459 (More RPC help description fixes by ch4ot1c)
  • #13756 (wallet: "avoid_reuse" wallet flag for improved privacy by kallewoof)

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 Author

luke-jr commented Oct 29, 2018

I don't understand what the Travis linter is trying to complain about.

@maflcko
Copy link
Member

maflcko commented Oct 29, 2018

I think the linter doesn't understand that an option can have two different types (and wants you to specify both conversions similar to { "getblock", 1, "verbosity" }, { "getblock", 1, "verbose" },)

Copy link
Contributor

@jnewbery jnewbery left a 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.

Copy link
Contributor

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.

Copy link
Member Author

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.

Copy link
Contributor

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

Copy link
Member Author

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.

Copy link
Contributor

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).

Copy link
Member Author

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?

@practicalswift
Copy link
Contributor

Concept ACK

@promag
Copy link
Contributor

promag commented Nov 3, 2018

Failing with

* Checking consistency between dispatch tables and vRPCConvertParams
ERROR: getbalance argument ['trusted_only', 'account'] has conflicts in vRPCConvertParams conversion specifier [True, False]

@luke-jr
Copy link
Member Author

luke-jr commented Nov 3, 2018

@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.

Copy link
Contributor

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

Copy link
Contributor

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 \"*\"."

Copy link
Contributor

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

@maflcko maflcko added this to the 0.17.1 milestone Nov 14, 2018
@sipa
Copy link
Member

sipa commented Nov 19, 2018

@luke-jr Needs rebase.

@sipa
Copy link
Member

sipa commented Nov 22, 2018

It'd be great to have this in 0.17.1.

@luke-jr Would you mind someone else rebasing this?

@luke-jr
Copy link
Member Author

luke-jr commented Nov 22, 2018

Rebased

@luke-jr luke-jr force-pushed the bugfix_rpc_getbalance_untrusted branch from 5505437 to cdc9814 Compare November 22, 2018 01:41
@meshcollider
Copy link
Contributor

Still needs comments above addressed too

@luke-jr
Copy link
Member Author

luke-jr commented Nov 22, 2018

Test issues fixed

Copy link
Contributor

@meshcollider meshcollider 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 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");
Copy link
Contributor

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()) {
Copy link
Contributor

@meshcollider meshcollider Nov 22, 2018

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)

Copy link
Member Author

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.

@DrahtBot
Copy link
Contributor

Needs rebase

@maflcko
Copy link
Member

maflcko commented Nov 23, 2018

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.

Copy link
Contributor

@jnewbery jnewbery left a 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);
Copy link
Contributor

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.

Copy link
Contributor

@jnewbery jnewbery left a 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:

} else if (filter == ISMINE_WATCH_ONLY) {
cache = &nAvailableWatchCreditCached;
cache_used = &fAvailableWatchCreditCached;
if (min_depth == 0) {
Copy link
Contributor

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

@ryanofsky
Copy link
Contributor

<luke-jr> jnewbery: making it impossible to get the current balance (ie, with untrusted txs included) is IMO not acceptable

@luke-jr I agree with this, but I don't understand if adding up values of getbalance and getunconfirmedbalance as an alternative would give the wrong result, or if it would give the right result, but be less than ideal because it's inconvenient or not atomic. Do you have thoughts on this?

@maflcko maflcko modified the milestones: 0.17.1, 0.17.2 Nov 30, 2018
maflcko pushed a commit to maflcko/bitcoin-core that referenced this pull request Nov 30, 2018
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"} },
Copy link
Contributor

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.

Copy link
Member Author

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"

Copy link
Contributor

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

@luke-jr
Copy link
Member Author

luke-jr commented Jan 5, 2019

Closing this for now.

@luke-jr luke-jr closed this Jan 5, 2019
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Dec 16, 2021
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.