Skip to content

[RPC] Include coinbase transactions in receivedby RPCs#14707

Merged
maflcko merged 3 commits intobitcoin:masterfrom
andrewtoth:receivedby-coinbase
Dec 7, 2021
Merged

[RPC] Include coinbase transactions in receivedby RPCs#14707
maflcko merged 3 commits intobitcoin:masterfrom
andrewtoth:receivedby-coinbase

Conversation

@andrewtoth
Copy link
Contributor

@andrewtoth andrewtoth commented Nov 12, 2018

The current *receivedby* RPCs filter out coinbase transactions. This doesn't seem correct since an output to your address in a coinbase transaction is receiving those coins.

This PR corrects this behaviour. Also, a new option include_immature_coinbase is added (default=false) that includes immature coinbase transactions when set to true.

However, since this is potentially a breaking change this PR introduces a hidden configuration option -deprecatedrpc=exclude_coinbase. This can be set to revert to previous behaviour. If no reports of broken workflow are received, then this option can be removed in a future release.

Fixes #14654.

@sipa
Copy link
Member

sipa commented Nov 12, 2018

Concept ACK, but you can't break compatibility by reordering another argument to listreceivedbyaddress. It's also unnecessary I think; you can specify "null" to get the default.

@andrewtoth
Copy link
Contributor Author

@sipa Not sure how to pass "null" as address_filter parameter without breaking #14417.

Copy link
Contributor

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

@sipa Not sure how to pass "null" as address_filter parameter without breaking #14417.

You can use named arguments instead.

Could have release note of the changed RPC's and the new argument.

@gmaxwell
Copy link
Contributor

gmaxwell commented Nov 12, 2018

Do we know a usecase where anyone would want this behaviour? It seems transparently broken to me.

If not, I think I would prefer we fix it and have a LOUD release note about the change, and if we're feeling especially conservative have a hidden config option to restore the old behaviour which we can drop after a couple releases if no one reports needing it.

Having an option presents a perpetual usage complexity increase, and defaulting the option to the old behaviour risks users being messed up by continuing to miss these payments.

One thing to consider, however, is that coinbase payments have different deconfirmation risks then general transactions... and cannot be spent for 100 blocks. E.g. you don't want service that accept a 1 conf deposit and withdraw being exploited as a orphan risk eliminator. Nor do we want to undermine parties cashflow handling by causing them to think they can spend more now than they can. There is justification for treating coinbase payments differently (e.g. only showing them once they're spendable), just not for hiding them completely. Having a "include coinbase payments yes/no" doesn't solve these concerns. Having a "delay them by 100 blocks, yes/no" probably would.

So maybe I would suggest having an argument to hide them until maturity, defaulting on, a hidden option to get the old behaviour, defaulting off, to be removed once it's confirmed no one needs it, and a loud release note explaining the change.

@promag
Copy link
Contributor

promag commented Nov 12, 2018

@gmaxwell it is however useful to know if a payment was made regardless if it takes 100 blocks to be spendable?

@gmaxwell
Copy link
Contributor

It can be, but listreceivedbyaddress doesn't normally show unconfirmed payments and the output IIRC doesn't even tell you if its an immature coinbase payment (and if it did, many people who didn't even realize coinbase payments were possible would not know to check for it)

@promag
Copy link
Contributor

promag commented Nov 12, 2018

@gmaxwell what if we consider minconf the depth added to the minimum spendable depth? Then minconf=1 for coinbase transactions would be 101?

@andrewtoth
Copy link
Contributor Author

@gmaxwell I agree. I think it is an error that should be corrected. I'm not sure why anyone would want coinbase txs excluded. I haven't seen a good explanation for why they are filtered out, or a usecase.

@DrahtBot
Copy link
Contributor

DrahtBot commented Nov 13, 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:

  • #20892 (tests: Run both descriptor and legacy tests within a single test invocation by achow101)

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.

@andrewtoth
Copy link
Contributor Author

andrewtoth commented Nov 15, 2018

Commits and PR description have been updated.

@andrewtoth
Copy link
Contributor Author

andrewtoth commented Nov 16, 2018

I refactored the getreceivedby calls to use a common function GetReceived. This mirrors the listreceivedby calls and doesn't repeat as much code.

@andrewtoth andrewtoth changed the title [RPC] Add include_coinbase option to receiveby RPCs [RPC] Include coinbase transactions in receiveby RPCs Nov 17, 2018
@andrewtoth andrewtoth changed the title [RPC] Include coinbase transactions in receiveby RPCs [RPC] Include coinbase transactions in receivedby RPCs Nov 17, 2018
@andrewtoth andrewtoth force-pushed the receivedby-coinbase branch 3 times, most recently from 3a1cc7c to 97602b5 Compare November 20, 2018 02:40
@andrewtoth
Copy link
Contributor Author

@gmaxwell Updated this PR with your suggestions.

@andrewtoth andrewtoth force-pushed the receivedby-coinbase branch 2 times, most recently from b49685a to 0fa9b60 Compare November 24, 2018 15:01
@andrewtoth andrewtoth force-pushed the receivedby-coinbase branch from c7c662b to 77da829 Compare April 7, 2021 00:25
Comment on lines +687 to +688
|| (wtx.IsCoinBase() && (depth < 1 || filter_coinbase))
|| (!include_immature && wtx.IsImmatureCoinBase())
Copy link
Contributor

Choose a reason for hiding this comment

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

Consistency helps readability. I think you can make this more consistent and readable as:

Suggested change
|| (wtx.IsCoinBase() && (depth < 1 || filter_coinbase))
|| (!include_immature && wtx.IsImmatureCoinBase())
|| (wtx.IsCoinBase() && (depth < 1 || !include_coinbase))
|| (wtx.IsImmatureCoinBase() && !include_immature_coinbase)

(where include_coinbase = !(wallet.chain().rpcEnableDeprecated("filter_coinbase")))

Copy link
Contributor

Choose a reason for hiding this comment

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

Another idea, this logic is close to that added to ListReceived() further down in this file; have you considered refactoring this logic into a separate small function? This may make the logic unit-testable, but may not be worth it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jnewbery Great suggestion, I agree this makes it much more readable.

@LarryRuane Since there are only two instances of this duplication, should we defer to the rule of three?

Copy link
Member

@glozow glozow 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 to not filtering out coinbases (especially if they're mature, I can't imagine why someone would want to filter those out). I have a few questions.

// Coinbase with less than 1 confirmation is an orphan
|| (wtx.IsCoinBase() && (depth < 1 || filter_coinbase))
|| (!include_immature && wtx.IsImmatureCoinBase())
|| !wallet.chain().checkFinalTx(*wtx.tx)) {
Copy link
Member

Choose a reason for hiding this comment

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

I expect this refers to outputs that we can't spend yet because a timelock hasn't been met. If a user wants to include immature coinbases, might they want to include nonfinal ones too? I understand that include_immature is supposed to be only for immature coinbases but I think a user might find it more helpful to be able to configure spendability in general rather than just for coinbases

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought this was an interesting idea. However, while implementing and trying to write a test, I was unable to broadcast a non-final tx (rejected with non-final). Do you know any way that a wallet would be able to have a non-final tx? If not, then it's possible this check is unnecessary and can be removed.

Copy link
Member

Choose a reason for hiding this comment

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

Oh hm, I guess the finality wouldn't really be reflected in the received transaction's header, but in the redeem script for it. I'm not too sure how the wallet keeps track of timelocked outputs 🤔 I don't think this check should be removed though

self.nodes[0].invalidateblock(hash)

self.log.info("getreceivedbyaddress does not include orphan when minconf is 0 when including immature")
balance = self.nodes[0].getreceivedbyaddress(address=address, minconf=0, include_immature=True)
Copy link
Member

Choose a reason for hiding this comment

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

Question: What happens if a user puts -spendzeroconfchange=0 (it's True by default, right?) and then calls getreceivedbyaddress(minconf=0)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm I'm not sure there is any effect in this case. The getreceivedby* RPCs only return a balance, and setting minconf=0 would return the unconfirmed balance using the tally code in GetReceived. I don't believe it would be affected by spendzeroconfchange, which from what I can see is only used in CWallet::SelectCoins.

@andrewtoth
Copy link
Contributor Author

@jnewbery @glozow @LarryRuane thank you all for your review! I've updated with all of your suggestions.

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.

Code review ACK 5e13dac43f257cc0869150c8f8b400b353885997 modulo release note comment.

Copy link
Contributor

Choose a reason for hiding this comment

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

nit: remove extra linebreak if you retouch this branch.

Copy link
Contributor

Choose a reason for hiding this comment

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

Feel free to remove this extra newline if you need to touch this branch again.

@andrewtoth
Copy link
Contributor Author

@jnewbery not sure what commit your ACK is referencing. Looks like github does not recognize it either.

@jnewbery
Copy link
Contributor

@jnewbery not sure what commit your ACK is referencing. Looks like github does not recognize it either.

Oops, sorry @andrewtoth - I rebased your branch on master before building/reviewing (building a branch that's based on a very old master commit results in a very slow build since lots of header files have changed). I then accidentally left my ACK for my new head commit hash instead of the one in this PR.

ACK 164e26d42e

@jnewbery
Copy link
Contributor

jnewbery commented Nov 4, 2021

reACK 1f084ec0ef

@andrewtoth: github doesn't generate a notification for reviewers if you just force-push a rebase. If you want people to re-review after a rebase you should leave a comment. That'll notify everyone who has previously reviewed the PR.

Copy link
Contributor

@LarryRuane LarryRuane 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 has hidden conflicts in the functional test; the generate() and generatetoaddress() signatures have changed.

@maflcko
Copy link
Member

maflcko commented Dec 6, 2021

Yeah, needs rebase again.

                                   TypeError: generatetoaddress() missing 1 required keyword-only argument: 'invalid_call'

@andrewtoth
Copy link
Contributor Author

Rebased.

@maflcko
Copy link
Member

maflcko commented Dec 7, 2021

Looks like there are test failures with descriptor wallets?

@andrewtoth
Copy link
Contributor Author

@MarcoFalke fixed.

@jnewbery
Copy link
Contributor

jnewbery commented Dec 7, 2021

reACK 1dcba99

Copy link
Member

@maflcko maflcko left a comment

Choose a reason for hiding this comment

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

Sorry for the incremental review

This release changes this behaviour and returns results accounting for received coins from coinbase outputs.

A new option, `include_immature_coinbase` (default=`false`), determines whether to account for immature coinbase transactions.
Immature coinbase transactions are coinbase transactions that have 100 or fewer confirmations, and are not spendable.
Copy link
Member

Choose a reason for hiding this comment

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

Is this still up-to-date? The default seems to be true. Also, instead of using the release notes to explain what immature txs are, what about moving this to the rpc help? Either this is relevant for future releases as well, or not at all.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The option is defined here and here, made clear to be false when no option is specified by your suggestion here.

I can move the immature txs explanation to the rpc help if I have to rebase again. Do you think it's a blocker? The release notes will have to be manually updated anyways, right?

Copy link
Member

Choose a reason for hiding this comment

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

No, not a blocker.

Sorry for the brain fart. I keep messing up true and false for boolean values lately.

Copy link
Member

Choose a reason for hiding this comment

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

Maybe for clarity (in the future) the second section can be switched with the third section, so that the behavior changing stuff is bundled together and the new rpc arg option is in a separate bundle?

Copy link
Member

Choose a reason for hiding this comment

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

If someone decides to address the nits, the notes snippet can also be moved to the main release notes file in the same pull request, to avoid having to touch it again.

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.

received wallet rpc calls do not include coinbase outputs