Join GitHub today
GitHub is home to over 20 million developers working together to host and review code, manage projects, and build software together.
Add change output if necessary to reduce excess fee #10712
Conversation
instagibbs
reviewed
Jun 30, 2017
imo this is superior in its simplicity and targeting the exact situation better over #10333 .
A bit worried about the failure case triggering anytime fee estimations change. I know you don't want to in this PR, but pulling out the estimation and getting a feerate that is reapplied in the main loop seems worth it, is easy to review, and will have to be done anyways for effective value work.
| - // to be addressed so we avoid creating too small an output. | ||
| + CAmount max_excess_fee = GetMinimumFee(change_prototype_size, currentConfirmationTarget, ::mempool, ::feeEstimator, nullptr) + | ||
| + GetDustThreshold(change_prototype_txout, ::dustRelayFee); | ||
| + // If we have no change and a big enough excess fee, then |
instagibbs
Jun 30, 2017
Member
please move first explanation a few lines before for the "increase change" to appropriate spot
ryanofsky
Jul 10, 2017
Contributor
please move first explanation a few lines before for the "increase change" to appropriate spot
I think order of the comments does makes sense. First comment describes the normal case, second comment describes unhandled special case, and third comment describes handled special case accompanied by implementation for that case.
I might move the code for the normal case above the code & comments for the two special cases, though this would increase the size of the diff. Just a thought, though.
instagibbs
Jul 11, 2017
Member
He moved it, the comment wasn't marked as resolved. Happy with current arrangement.
| + // change input. Only try this once. | ||
| + if (nFeeRet > nFeeNeeded + max_excess_fee && nChangePosInOut == -1 && nSubtractFeeFromAmount == 0 && pick_new_inputs) { | ||
| + pick_new_inputs = false; | ||
| + nFeeRet = nFeeNeeded; |
instagibbs
Jun 30, 2017
Member
this needs to be nFeeRet = nFeeNeeded + GetMinimumFee(change_prototype_size, currentConfirmationTarget, ::mempool, ::feeEstimator, nullptr) ; at a minimum, right?
nFeeNeeded at this point will not pay for the new change output.
| @@ -2754,6 +2771,11 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT | ||
| } | ||
| break; // Done, enough fee included. | ||
| } | ||
| + else if (!pick_new_inputs) { | ||
| + // This shouldn't happen |
instagibbs
Jun 30, 2017
Member
nit: slightly longer explanation for reader?
"This shouldn't happen, we should have had enough excess fee to pay for the newly created change output."
With fix on the nFeeRet, a very slight increase in fee between estimation calls(can that happen?) will result in this triggering.
morcos
Jun 30, 2017
Contributor
yes, i don't think that can happen (a change in fee estimation) but belts and suspenders.
In any case will be cleaned up post 0.15 with effective value logic and only calculating the needed fee rate once.
| @@ -2774,6 +2773,8 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT | ||
| } | ||
| } | ||
| + if (nChangePosInOut == -1) reserveKey.ReturnKey(); // Return any reserved key if we don't have change |
|
Fixed bug and nits and squashed @instagibbs I'm fine with doing the GetMinimumFeeRate refactor for 0.15, but I already did a lot of other work on GetMinimumFee in #10706 which I would really like to get in for 0.15, so I'm wary of piling on too many changes that touch the same lines of code and not being able to get them all in. |
fanquake
added the
Wallet
label
Jul 1, 2017
|
All return points should call |
|
Reference #10247. |
promag
reviewed
Jul 3, 2017
utACK.
IMO going for one last iteration and to have one more flag is a clear sign that a more thoughtful refactor should be done. Not that I'm against this change, but reading this code should be plain and easy.
promag
reviewed
Jul 4, 2017
•
Nit, should variables be in camel or snake case? Also could you fix brace styles for the moved code?
morcos
referenced
this pull request
Jul 5, 2017
Closed
[wallet] fee fixes: always create change, adjust value, and p… #10333
|
@promag As for calling ReturnKey, I suppose that does make sense, but the existing code did not do that, and I haven't materially changed that behavior. I'm happy to add it though if I should? |
|
@morcos another PR is fine. As @instagibbs said, this is a bugfix. |
laanwj
added
to Blockers in High-priority for review
Jul 6, 2017
|
Replaced #10333 with this one in "High priority for review" (reviewing a closed PR with high priority makes little sense). |
jonasschnelli
added this to the
0.15.0
milestone
Jul 6, 2017
ryanofsky
reviewed
Jul 10, 2017
Wow, this code is ridiculously complicated. Pretty clean fix, though. Would be nice if we could mock SelectCoins and easily write unit tests for these cases.
utACK d64a4b9
| - // to be addressed so we avoid creating too small an output. | ||
| + CAmount max_excess_fee = GetMinimumFee(change_prototype_size, currentConfirmationTarget, ::mempool, ::feeEstimator, nullptr) + | ||
| + GetDustThreshold(change_prototype_txout, ::dustRelayFee); | ||
| + // If we have no change and a big enough excess fee, then |
ryanofsky
Jul 10, 2017
Contributor
please move first explanation a few lines before for the "increase change" to appropriate spot
I think order of the comments does makes sense. First comment describes the normal case, second comment describes unhandled special case, and third comment describes handled special case accompanied by implementation for that case.
I might move the code for the normal case above the code & comments for the two special cases, though this would increase the size of the diff. Just a thought, though.
| + // try to construct transaction again only without picking | ||
| + // new inputs. We now know we only need the smaller fee | ||
| + // (because of reduced tx size) and so we should add a | ||
| + // change input. Only try this once. |
| @@ -2773,7 +2800,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT | ||
| } | ||
| } | ||
| - if (nChangePosInOut == -1) reserveKey.ReturnKey(); // Return any reserved key if we don't have change | ||
| + if (nChangePosInOut == -1) reservekey.ReturnKey(); // Return any reserved key if we don't have change |
ryanofsky
Jul 10, 2017
Contributor
In commit "Fix rare edge case of paying too many fees"
This needs to be moved to the previous commit for it to compile.
|
Fixed commit history and fixed comment nit
|
| @@ -2754,6 +2775,12 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT | ||
| } | ||
| break; // Done, enough fee included. | ||
| } | ||
| + else if (!pick_new_inputs) { |
|
utACK 533b3f0 |
laanwj
merged commit 0f402b9
into
bitcoin:master
Jul 11, 2017
1 check was pending
laanwj
added a commit
that referenced
this pull request
Jul 11, 2017
|
|
laanwj |
e8b9523
|
morcos
referenced
this pull request
Jul 11, 2017
Merged
Improve wallet fee logic and fix GUI bugs #10706
|
Posthumous utACK 0f402b9 |
morcos commentedJun 30, 2017
This is an alternative to #10333
See commit messages.
The first commit is mostly code move, it just moves the change creation code out of the loop.
@instagibbs