Skip to content

Conversation

achow101
Copy link
Member

@achow101 achow101 commented Nov 17, 2021

Often the goal with subtracting fee from outputs is to sweep an entire wallet's balance. As such, it is reasonable to allow negative effective value UTXOs as inputs as otherwise the target value (the balance) cannot be reached. However this is not always desirable as there may be solutions with only positive EV UTXOs, so we only try with negative EV UTXOs if we are unable to find any solutions with the normal groupings.

Fixes #23026

@maflcko maflcko added this to the 22.1 milestone Nov 17, 2021
@achow101 achow101 force-pushed the no-change-fee-w-sffo branch from 05ef67a to c351e53 Compare November 17, 2021 18:12
@DrahtBot
Copy link
Contributor

DrahtBot commented Nov 18, 2021

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

Conflicts

No conflicts as of last run.

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.

Code review ACK c351e53

Checked that the new test fails on current master but passes with this PR.

@S3RK
Copy link
Contributor

S3RK commented Nov 22, 2021

Concept ACK.

Did a light code review and I think it's better to drop the first commit as it's not required to fix the linked bug. If you'd like to keep it, I'd suggest to make inclusion/exclusion of the change fee explicit when stetting targets for coinselection algorithms, rather than implicit m_change_fee = 0 (it's not zero, it's just payed by recipient!).

Copy link
Contributor

@S3RK S3RK left a comment

Choose a reason for hiding this comment

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

some nits below

@gruve-p
Copy link
Contributor

gruve-p commented Nov 23, 2021

ACK c351e53

@fanquake fanquake requested a review from instagibbs November 25, 2021 07:44
@fanquake
Copy link
Member

cc @yurayakimenko

@instagibbs
Copy link
Member

concept ACK, if someone wants to do "send max value possible" we could support this as another option and choose positive only groups again.

Copy link
Contributor

@rajarshimaitra rajarshimaitra left a comment

Choose a reason for hiding this comment

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

tACK c351e53

Verified that the test fails in master.

Though I am thinking, the problem of negative ev utxos are only relevant for sweeping transactions with fundrawtransaction rpc (there are other ways to create sweeps). Does this warrant removing negative ev for all cases with subtract_fee_outputs? Maybe we can have a more sweeping focused approach to trigger BnB?

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.

But this solution means you will end up with less bitcoins on the receiving end, doesn't it? Users probably would prefer the higher amount received.

I suppose the best UX would be to either ignore the net-negative UTXOs and simply send less than the requested amount. But that is apt to unprovably "burn" the dust unless we can somehow publish the dust private keys for others to sweep (but that seems dangerous and potentially ties to some centralised publisher).

Second-best might be to effectively reduce the fee rate by simply refusing to pay more for these UTXOs than they're worth. But care is needed to ensure the user is aware of this and transactions don't get stuck.

Also, any of this should only occur when trying to send the entire balance I think?

@achow101
Copy link
Member Author

achow101 commented Dec 5, 2021

But this solution means you will end up with less bitcoins on the receiving end, doesn't it?

Yes.

Users probably would prefer the higher amount received.

I'm not sure. Subtract fee from outputs has always been "X amount leaves the wallet", so I think having less than that leave would be surprising?

I suppose the best UX would be to either ignore the net-negative UTXOs and simply send less than the requested amount. But that is apt to unprovably "burn" the dust unless we can somehow publish the dust private keys for others to sweep (but that seems dangerous and potentially ties to some centralised publisher).

Negative EV UTXOs can become positive if the feerate were to drop (assuming it was high).

Second-best might be to effectively reduce the fee rate by simply refusing to pay more for these UTXOs than they're worth. But care is needed to ensure the user is aware of this and transactions don't get stuck.

I think that might be dangerous, and surprising to users.

Also, any of this should only occur when trying to send the entire balance I think?

I think it is reasonable for this to occur for all subtract fee from outputs sends. Maybe it should try positive only first, and if that fails, allow negative?

@instagibbs
Copy link
Member

ACK f44c3ce

@Sjors
Copy link
Member

Sjors commented Dec 10, 2021

Nit: typo in the PR title "negtive" (may make it harder to find later)

I typically use the "subtract fee" feature in combination with manual coin selection (for which this PR has no effect). That's different from the use case of emptying out a wallet. At minimum the RPC docs should warn that this will spend negative net value coins. The GUI should also warn, preferably only when this is actually the case. It can get quite expensive if a wallet has lots of dust.

The first commit is worth its own PR if this doesn't make it.

@fanquake fanquake changed the title wallet: Allow negtive effective value inputs when subtracting fee from outputs wallet: Allow negative effective value inputs when subtracting fee from outputs Dec 10, 2021
Sometimes subtractFeeFromOutputs requires spending negative ev UTXOs
(e.g. when sweeping an entire wallet). If we are unable to find any
solutions normally, then try again but this time allowing negative ev
UTXOs.
When subtracting fee from outputs, it should be okay to spend negative
ev UTXOs because the recipient is paying for it.
@achow101 achow101 force-pushed the no-change-fee-w-sffo branch from f44c3ce to a26a64c Compare December 10, 2021 14:27
@achow101
Copy link
Member Author

I've changed this to try negative EVs if there are no solutions with the normal groupings.

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.

Code review ACK a26a64c

Haven't re-verified test

Copy link
Member

@instagibbs instagibbs left a comment

Choose a reason for hiding this comment

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

good change to simplify the behavior difference

reACK a26a64c

@@ -403,6 +403,20 @@ std::optional<SelectionResult> AttemptSelection(const CWallet& wallet, const CAm
results.push_back(*srd_result);
}

// If we didn't find any solutions, and are subtracting the fee from the outputs, we may need to include negative effective value coins.
// So try BnB and SRD again with all_groups.
// It is safe to do this because a solution including negative EVs will have a greater waste.
Copy link
Member

Choose a reason for hiding this comment

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

What about just throwing these two selections into the mix unconditionally? Would that be correct? Efficiency aside.

bnb_result->ComputeAndSetWaste(CAmount(0));
results.push_back(*bnb_result);
}
if (auto srd_result{SelectCoinsSRD(all_groups, srd_target)}) {
Copy link
Member

Choose a reason for hiding this comment

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

Might this trigger the Assume(group.GetSelectionAmount() > 0) statement in SelectCoinsSRD()?

Copy link
Member

Choose a reason for hiding this comment

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

(also note the comment on the declaration for SelectCoinsSRD() in coinselection.h states that it expects positive ev groups, might need to change that)

@murchandamus
Copy link
Contributor

murchandamus commented Jan 5, 2022

I already mentioned this in person, but I find that "subtract fee" leads to unintuitive behavior, especially in the context of sweeping (and makes all tests a lot more complicated).

It would make more sense to me that the wallet never spends UTXOs with negative effective value unless explicitly tasked to do so, since it just costs users (either sender or receiver) more fees and more blockspace for the debatable reason of not leaving any UTXOs behind. The main use-case where I see "subtract fee from recipient" making sense, is in the context of Coin Control, when the sender picks the inputs explicitly and doesn't want to calculate the appropriate fee manually.

Especially in the case of sweeping, I agree with Luke, that the user should prefer getting more money over using all UTXOs. If they sweep at minFeeRate, they're getting the optimal outcome anyway. We might want to introduce a dedicated sweep function that sends the maximum by default, and optionally can be toggled to spend all UTXOs.

@ryanofsky
Copy link
Contributor

I already mentioned this in person, but I find that "subtract fee" leads to unintuitive behavior, especially in the context of sweeping (and makes all tests a lot more complicated).

Could you maybe illustrate what the unintuitive behavior is with an example? The rest of your comment about "user should get more money by default" obviously sounds good if it doesn't have other tradeoffs.

@achow101
Copy link
Member Author

achow101 commented Jan 5, 2022

The main use-case where I see "subtract fee from recipient" making sense, is in the context of Coin Control, when the sender picks the inputs explicitly and doesn't want to calculate the appropriate fee manually.

And that scenario could be considered sweeping as well. Sweeping can be generalized to "spend UTXOs XYZ fully with all value going to one output" where XYZ could be all UTXOs in the wallet, or a preset input list.

Especially in the case of sweeping, I agree with Luke, that the user should prefer getting more money over using all UTXOs. If they sweep at minFeeRate, they're getting the optimal outcome anyway. We might want to introduce a dedicated sweep function that sends the maximum by default, and optionally can be toggled to spend all UTXOs.

I think it is unintuitive and not very good UX to not spend uneconomical UTXOs in a sweep. I think that users would expect a sweep function to spend all UTXOs regardless, and it would be surprising if sweeping a wallet left behind any balance, even uneconomical.

Could you maybe illustrate what the unintuitive behavior is with an example?

I'm not sure about unintuitive, but subtractFeeFromOutputs definitely causes a lot of headaches in coin selection code, so getting rid of it would greatly simplify a lot of it. It would certainly make the logic much easier to follow.


For some historical context, #5831 added subtractFeeFromAmount (which was a rebase of #4331) and that points to 2 issues where the proposed use case is sweeping.

@achow101
Copy link
Member Author

Closing this in favor of introducing sendall to solve the problem.

@achow101 achow101 closed this Mar 10, 2022
@bitcoin bitcoin locked and limited conversation to collaborators Mar 31, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

subtractFeeFromOutputs option in fundrawtransaction RPC call is not working as expected on v22.0