Skip to content

Conversation

achow101
Copy link
Member

@achow101 achow101 commented Nov 7, 2022

When bumping the transaction fee, we will try to find the change output of the transaction in order to have an output whose value we can modify so that we can meet the target feerate. However we do not always find the change output which can cause us to unnecessarily add an additional output to the transaction. We can avoid this issue by outsourcing the determination of change to the user if they so desire.

This PR adds a orig_change_pos option to bumpfee which the user can use to specify the index of the change output.

Fixes #11233
Fixes #20795

Copy link
Member

@luke-jr luke-jr left a comment

Choose a reason for hiding this comment

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

We support subtracting fee from output, so I think the "reduce_output" name used in #12096 was better. (Would be nice if that situation could be detected, but I don't think we save the metadata needed for that.)

Also, might make sense to split the GUI part off to the GUI repo after the rest is merged. Seems like a hard thing to get a good UX for.

@achow101 achow101 force-pushed the bumpfee-choose-change-txout branch from 527b89d to 6d10ece Compare November 8, 2022 22:29
@ghost
Copy link

ghost commented Nov 8, 2022

Concept ACK

@DrahtBot
Copy link
Contributor

DrahtBot commented Nov 9, 2022

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

Reviews

See the guideline for information on the review process.

Type Reviewers
ACK ismaelsadeeq, pinheadmz, furszy
Concept ACK ghost, john-moffett, RandyMcMillan
Stale ACK Sjors

If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #bitcoin-core/gui/700 (Dialog for allowing the user to choose the change output when bumping a tx by achow101)
  • #27829 (rpc: fix data optionality for RPC calls. by miketwenty1)
  • #25979 ([WIP] wallet: standardize change output detection process by furszy)

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.

@john-moffett
Copy link
Contributor

john-moffett commented Nov 16, 2022

Concept ACK.

Tested and code reviewed 73d4ba2. Suggest changing the dialog UI to support scrolling and resizing in case there are lots of outputs:

Screenshot image

Here is a drop-in gist to implement scrolling and resizing, which changes it to:

Screenshot image

If a user creates a single-output tx and chooses that output as "change" to fee-bump, it will fail with the "Transaction must have at least one recipient" message. This makes sense if the user always expects the "payment" output to remain the same value, but if they're consolidating UTXOs or something, this may be desirable to allow.

@Sjors
Copy link
Member

Sjors commented Dec 12, 2022

We support subtracting fee from output, so I think the "reduce_output" name used in #12096 was better.

Agreed. The help text could clarify that in the general case you should pick the change address output for this.

@achow101
Copy link
Member Author

We support subtracting fee from output, so I think the "reduce_output" name used in #12096 was better. (Would be nice if that situation could be detected, but I don't think we save the metadata needed for that.)

I've taken the name, but I'm not entirely sure that it is accurate. While we will most likely reduce the amount of the specified output, it's not the only outcome. It could be that specified output does not provide enough value, in which case we will add additional inputs and set the output's value as the resulting change value, which will be higher than the original value.

Also, might make sense to split the GUI part off to the GUI repo after the rest is merged. Seems like a hard thing to get a good UX for.

Done, moved the GUI commits to bitcoin-core/gui#700

Suggest changing the dialog UI to support scrolling and resizing in case there are lots of outputs:

Took this suggestion in the PR to the GUI repo.

If a user creates a single-output tx and chooses that output as "change" to fee-bump, it will fail with the "Transaction must have at least one recipient" message. This makes sense if the user always expects the "payment" output to remain the same value, but if they're consolidating UTXOs or something, this may be desirable to allow.

Added a commit which handles that case.

@Sjors
Copy link
Member

Sjors commented Jan 24, 2023

Concept ACK

Did you mean for the middle commit to have txid: as its prefix?

On signet with an empty mempool, when I send a transaction with a single input at 1 sat/vbyte and then try to bump it to 2 sat/byte, it complains:

Insufficient total fee 0.00000222, must be at least 0.00000666 (oldFee 0.00000111 + incrementalFee 0.00000555)

getnetworkinfo says "incrementalfee": 0.00001000

Maybe maxTxSize is too pessimistic?

@achow101 achow101 force-pushed the bumpfee-choose-change-txout branch from ceab670 to 0b280af Compare January 24, 2023 18:05
@achow101
Copy link
Member Author

Did you mean for the middle commit to have txid: as its prefix?

Nope, fixed.

On signet with an empty mempool, when I send a transaction with a single input at 1 sat/vbyte and then try to bump it to 2 sat/byte, it complains:

Insufficient total fee 0.00000222, must be at least 0.00000666 (oldFee 0.00000111 + incrementalFee 0.00000555)

getnetworkinfo says "incrementalfee": 0.00001000

Maybe maxTxSize is too pessimistic?

I'm going to say that this is an orthogonal issue. It looks like the wallet has a minimum incremental feerate of 5 sat/vb, rather than the 1 sat/vb the mempool uses.

Copy link
Member

@Sjors Sjors left a comment

Choose a reason for hiding this comment

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

tACK 0b280af


return Result::OK;
return Result::OK;
Copy link
Member

Choose a reason for hiding this comment

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

0b280af nit: return could be outside the if else. If you touch it, there's also a typo in the commit description: transcation

@Sjors
Copy link
Member

Sjors commented Feb 22, 2023

utACK 4167843. The latest rebase takes the new outputs argument into account from #25344. It ensures they can't be combined, so that's good.

Copy link
Member

@pinheadmz pinheadmz left a comment

Choose a reason for hiding this comment

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

ACK 4167843

reviewed code, ran tests. Played with the feature on regtest and in particular using reduce_output to intentionally reduce the recipient output instead of the original change output added automatically by sendtoaddress. I don't think is explicitly covered in the test but could be. One other quesiton about the test below but otherwise LGTM

Show Signature
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

ACK 4167843e0729994954317e2a4ac8a96a453bad79
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCAAdFiEE5hdzzW4BBA4vG9eM5+KYS2KJyToFAmP4544ACgkQ5+KYS2KJ
yTr/hw//RCFzObS/NFeiJjG4Btb6kuDMDW7SYmXaEazT0mX91QpiQlq+cW92/FZa
FDqycJs43hMMu0ytmTJ8qs9S0sROU0IYRJghK16Ne16TBhtJwbpS93NIQo4LQY7j
a77Ql9DmDGt/c5EkN+lQsvk6W6PXlo1NqwvXT5Rn3NXnbJ0yD4PCo5ZQW1GQ305i
6pGboMlx97PGRtnCsFvfO6+lOAUlAPiwYXt8a+yfT2jhhFzmoi0KG4NlcPLHmwCL
OPKken36AE/2WMpZLu12nDMAb6qM3ia7/GiKxEB6+C0j0RBxYF4RAjmKxgNo/XJ/
f2yZiPmDSsGnZWaYRMpOjR5s0HgQS98WRUK17ZJfz8tN7qR9Y8L8wUwLTpvqHM/a
i+Je0mXY1k5iUtkOG9D9PKAAmsQ6OQzoCW1vzuKL1Z1jc2nKZHbuYbuE8OzyKlGc
A4gv/pNSyaWLHP7TqwvzxHTVlCNlbp+bN+PB21ojd4xsItCU5AGbLAxAMF+LJnwO
YL5xI+29voZcnZBiQI9/jHV8VJ5mUYYDT4f/nQYkTlMmAcBx7BzPF4Zh3h7gKOBA
ybhrHHsSNiXVcm2VIqI6Zb/Wvn/zRTJscxvRQNDuYvEGeCMjQSc1uaGulFflWLmq
qtGtR6U4j4GRTL8TyQcAZu4VfuaUH3up2Km3cKAAFvNqbaKOqlo=
=A42I
-----END PGP SIGNATURE-----

pinheadmz's public key is on keybase


new_tx = rbf_node.gettransaction(txid=new_txid, verbose=True)
assert_equal(len(new_tx["decoded"]["vout"]), 2)
new_change_pos = find_vout_for_address(rbf_node, new_txid, change_addr)
Copy link
Member

Choose a reason for hiding this comment

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

Will new_change_pos == change_pos always here? Or are the outputs of the replacement re-randomized?

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 will be re-randomized.

@RandyMcMillan
Copy link
Contributor

Concept ACK

@achow101 achow101 marked this pull request as ready for review May 19, 2023 17:14
@achow101 achow101 force-pushed the bumpfee-choose-change-txout branch from ec3b93d to dff7235 Compare June 8, 2023 10:10
@DrahtBot DrahtBot removed the CI failed label Jun 8, 2023
@ismaelsadeeq
Copy link
Member

tACK dff7235
Tested the reduce_output option on regtest with bumpfee RPC, the value of the output in the reduced_output was decreased to fee bump the transaction instead of adding another input.
tests fail on master and pass on dff7235.
Code looks good to me

@DrahtBot DrahtBot requested review from pinheadmz and Sjors June 24, 2023 12:54
@achow101 achow101 force-pushed the bumpfee-choose-change-txout branch from dff7235 to 2eeebc5 Compare June 26, 2023 17:29
achow101 added 3 commits June 26, 2023 17:49
If the user used a custom change address, it may not be detected as a
change output, resulting in an additional change output being added to
the bumped transaction. We can avoid this issue by allowing the user to
specify the position of the change output.
@achow101 achow101 force-pushed the bumpfee-choose-change-txout branch from 2eeebc5 to e8c31f1 Compare June 26, 2023 21:57
@ismaelsadeeq
Copy link
Member

re ACK e8c31f1

@pinheadmz
Copy link
Member

Additionally, a new dialog is added to the GUI that allows the user to select the change output when they are bumping the transaction fee. This dialog will default select output that the wallet determines to be change, if it could find one.

Not seeing this in this branch.

Copy link
Member

@pinheadmz pinheadmz left a comment

Choose a reason for hiding this comment

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

re-ACK e8c31f1

Reviewed all code changes, ran tests locally. I played with the feature in regtest with wallet TXs as well as PSBTs. Made sure invalid input threw errors and expected output was reduced by fee bump. Found one nit below. Maybe remove GUI from OP description? Is that being added in a bitcoin-core/gui PR ?

Show Signature
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

ACK e8c31f135c6e9a5f57325dbf4feceafd384f7762
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCAAdFiEE5hdzzW4BBA4vG9eM5+KYS2KJyToFAmS1V/kACgkQ5+KYS2KJ
yTon4g/+JpVTIdCwb4fvLOiulKLu+poVhET+Wz9iyC+47m4GJUPgcR8RyEcPFa+6
eEn7V1md7o9pOekPQnBLStZJZSFQwuJgG0utgt/M0a5yzQlNNsTcEh2nWqSAI1X2
RAzxOlBjomFzQndm8zQ6QVQRX4tmrwKdnJxumZxWrnRBToJCvikdDVzHIP1yS0CE
d9Z2yWNgJKkocuWACMOgfjt5GjR/Y0Y4qPDahcI10qpWjD2yFJMrx5DUjUnMxXyD
H/3+kYUga9yfFAlE1J9OyCWpL1k//zRcttBZxDoHZ/Hh3MIMvcla6eRAjndd0iU0
o92BVZS1+Ylz4mY2+aoja1yoXQa9JJwJavyOVNR0HtzXXtkzkWdf8shMcUe7jTXb
wlUJwm4+ItIZ05ms05eTmcxfDOc6aQjKud26hIG0TaztfLAZU3ITDdU9lHeZB8qC
szHpyVxLJ63BtaQCOdC//asAqxsn44EZlM3LY9iUE1jvxLAaaHN7yPgSO62A1B3N
RbQ+5BYLYWv6ceAnyUKxX7XnzEGjsFQnSe45KVYZ42zy4eO6kuc/xKy7his3oJ9r
7JT1FgA41wY8mi4KazB6JRyTwhcx0QQ3UxwbnLy3tzsTzWw0aU3dPqwG7iR2dTqH
Ac08JiqHzUCtTiYbRVrrATkgoZNeBqjCRhVr3o0z+2iKZLm6lWg=
=8/+K
-----END PGP SIGNATURE-----

pinheadmz's public key is on keybase

} else {
for (size_t i = 0; i < txouts.size(); ++i) {
const CTxOut& output = txouts.at(i);
if (reduce_output.has_value() ? reduce_output.value() == i : OutputIsChange(wallet, output)) {
Copy link
Member

Choose a reason for hiding this comment

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

nit: extra space?

Suggested change
if (reduce_output.has_value() ? reduce_output.value() == i : OutputIsChange(wallet, output)) {
if (reduce_output.has_value() ? reduce_output.value() == i : OutputIsChange(wallet, output)) {

@achow101
Copy link
Member Author

Additionally, a new dialog is added to the GUI that allows the user to select the change output when they are bumping the transaction fee. This dialog will default select output that the wallet determines to be change, if it could find one.

Not seeing this in this branch.

That was moved to bitcoin-core/gui#700. Dropped that from the PR description.

Comment on lines +248 to +254
for (size_t i = 0; i < txouts.size(); ++i) {
const CTxOut& output = txouts.at(i);
if (reduce_output.has_value() ? reduce_output.value() == i : OutputIsChange(wallet, output)) {
CTxDestination change_dest;
ExtractDestination(output.scriptPubKey, change_dest);
new_coin_control.destChange = change_dest;
} else {
Copy link
Member

Choose a reason for hiding this comment

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

If the transaction has two outputs: index 0 not change, and index 1 change for the wallet. When reduce_output=0, the first round of the loop will set destChange to the first output script, then the second round will overwrite destChange with the second output script.

This will have the bad outcome of dropping the first output (the one selected by the user) and send all coins to the second one. Leaving the bumped tx with only one output.

A solution for this could be to not discard change outputs from the recipients vector. But, for that, we need #27601. Which basically enables this feature.

So instead of having this feebumper loop dropping the change output, we can append it to the recipients list and specify inside coin control that we want to send any surplus between inputs and outputs there.

Copy link
Member

Choose a reason for hiding this comment

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

Weird, this comment was posted yesterday but is dated over a month ago (Jun 9). I thought for sure I had tested this case locally and didn't see a missing output -- is this still the case here? Since we check reduce_output.has_value() in the if condition, doesn't that mean that if that option is set only the selected option will be designated as change?

Copy link
Member

Choose a reason for hiding this comment

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

I thought for sure I had tested this case locally and didn't see a missing output -- is this still the case here? Since we check reduce_output.has_value() in the if condition, doesn't that mean that if that option is set only the selected option will be designated as change?

Yeah. Seems that I was partially blind yesterday. This issue can still be triggered by a transaction with +2 change outputs and no reduce_output (OutputIsChange() will be true for them, which overwrites destChange). But.. it isn't related to this PR.
So.. nvm. Will do another review round. Thanks @pinheadmz.

Copy link
Member

@furszy furszy 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 e8c31f1

OutputsDoc(),
RPCArgOptions{.skip_type_check = true}},
{"reduce_output", RPCArg::Type::NUM, RPCArg::DefaultHint{"not set, detect change automatically"}, "The 0-based index of the output from which the additional fees will be deducted. In general, this should be the position of change output. Cannot be provided if 'outputs' is specified."},
Copy link
Member

Choose a reason for hiding this comment

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

In 7d83502:

The first sentence "The 0-based index of the output from which the additional fees will be deducted" isn't totally accurate to what will happen.

If the bumpfee process adds another input to satisfy the new fee, the reduce_output output will also be increased by the new inputs - outputs surplus.

Copy link
Contributor

Choose a reason for hiding this comment

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

@furszy makes an important point. Consider the case where I am paying someone on chain under the stipulation that they will eat the mining fee. (Thus, I specify their address in subtractfeefrom when I'm constructing my transaction.) Later, they tell me that they can't wait for confirmation any longer and need an urgent fee bump. If I naïvely specify their output as the reduce_output, I may end up paying them much more than I intended to if I only have large UTxOs in my wallet.

Copy link
Member

Choose a reason for hiding this comment

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

@whitslack yes. That would be an ugly outcome. We could have fixed the RPC docs here.

Would say to work towards #27601 to fix this scenario (and others) properly.
This issue comes from a workaround code that avoids the dup change outputs bug. Basically, the change output is manually discarded from the recipients list and expected to be re-added later, with the new fees subtracted, by the inner transaction creation process logic.

With #27601, we will be able to specify the output to reduce (SFFO) and the existent change output unequivocally.

Copy link
Member

Choose a reason for hiding this comment

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

This seems like a very serious bug that should have blocked the merge... :|

Copy link
Member

Choose a reason for hiding this comment

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

Should we disable the adding of new inputs when reduce_output is set? If someone really intends to do that, they should probably use outputs.

Copy link
Member

Choose a reason for hiding this comment

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

Made a separate issue to track this: #28180

@fanquake fanquake merged commit 04afe55 into bitcoin:master Jul 20, 2023
sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Jul 21, 2023
Copy link

@donsheddy4 donsheddy4 left a comment

Choose a reason for hiding this comment

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

Very good

@bitcoin bitcoin locked and limited conversation to collaborators Aug 8, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Privacy Issue - Increase Fee with Custom Change Address grabs new UTXO bumpfee behavior with custom change address