-
Notifications
You must be signed in to change notification settings - Fork 37.4k
wallet: Use GetSelectionAmount in ApproximateBestSubset #22686
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
For 22.0 backport (this bug may cause other issues that are not as immediately obvious). |
Failure in the previous releases CI. Similar to #18737 / #18737: test 2021-08-12T02:39:40.038000Z TestFramework (ERROR): Assertion failed
Traceback (most recent call last):
File "/tmp/cirrus-build/ci/scratch/build/bitcoin-x86_64-pc-linux-gnu/test/functional/test_framework/test_framework.py", line 131, in main
self.run_test()
File "/tmp/cirrus-build/ci/scratch/build/bitcoin-x86_64-pc-linux-gnu/test/functional/feature_fee_estimation.py", line 271, in run_test
check_estimates(self.nodes[1], self.fees_per_kb)
File "/tmp/cirrus-build/ci/scratch/build/bitcoin-x86_64-pc-linux-gnu/test/functional/feature_fee_estimation.py", line 155, in check_estimates
check_smart_estimates(node, fees_seen)
File "/tmp/cirrus-build/ci/scratch/build/bitcoin-x86_64-pc-linux-gnu/test/functional/feature_fee_estimation.py", line 145, in check_smart_estimates
% (feerate, last_feerate))
AssertionError: Estimated fee (0.000238) larger than last fee (0.000201) for lower number of confirms
test 2021-08-12T02:39:40.040000Z TestFramework (DEBUG): Closing down network thread
test 2021-08-12T02:39:40.041000Z TestFramework (INFO): Stopping nodes
test 2021-08-12T02:39:40.041000Z TestFramework.node0 (DEBUG): Stopping node |
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsReviewers, this pull request conflicts with the following ones:
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. |
cc @xekyo |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be clear, the bug is that it is using the output value, even if we're not subtracting fee from outputs. We use GetSelectionAmount
to switch between effective and output value as our target based on subtracting fee from outputs or not.
This explanation should go in the commit message, or at least the OP to get pulled in on merge.
For target value calculations, GetSelectionAmount should be used, not m_effective_value or m_value. Specifically, ApproximateBestSubset mistakenly uses m_value when calculating whether the target value has been met. This has been changed to use GetSelectionAmount.
When the fee is not subtracted from the outputs, the amount that has been reserved for the fee (change_and_fee - change_amount) must be enough to cover the fee that is needed. It would be a bug to not do so, so use an assert to make this obvious if such a situation were to occur.
ApproximateBestSubset had an edge case (due to not using GetSelectionAmount) where it was possible for it to return success but fail to select enough to cover transaction fees. A test is added that could trigger this failure prior to the fix being implemented.
I've added a specific explanation in the first commit |
5a89197
to
92885c4
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
utACK 6e6a7e1
Verified the test fails on master but passes with this PR
utACK 92885c4 |
Post-merge utACK 92885c4 |
@xekyo thanks for following up. |
For target value calculations, GetSelectionAmount should be used, not m_effective_value or m_value. Specifically, ApproximateBestSubset mistakenly uses m_value when calculating whether the target value has been met. This has been changed to use GetSelectionAmount. Github-Pull: bitcoin#22686 Rebased-From: 2de222c
When the fee is not subtracted from the outputs, the amount that has been reserved for the fee (change_and_fee - change_amount) must be enough to cover the fee that is needed. It would be a bug to not do so, so use an assert to make this obvious if such a situation were to occur. Github-Pull: bitcoin#22686 Rebased-From: d926232
ApproximateBestSubset had an edge case (due to not using GetSelectionAmount) where it was possible for it to return success but fail to select enough to cover transaction fees. A test is added that could trigger this failure prior to the fix being implemented. Github-Pull: bitcoin#22686 Rebased-From: 92885c4
Backported in #22629. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to descri ED48 be this comment to others. Learn more.
See #22742
tx = tester.createrawtransaction([], [{funds.getnewaddress(): 2}]) | ||
no_change_tx = tester.fundrawtransaction(tx, {"subtractFeeFromOutputs": [0]}) | ||
|
||
overhead_fees = feerate * len(tx) / 2 / 1000 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we divide by 2 here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To get the byte length of the hex string.
lower_bound = Decimal("2.00000001") - fees | ||
# The target value must be at most 2 - cost_of_change - not_input_fees - min_change (these are all | ||
# included in the target before ApproximateBestSubset). | ||
upper_bound = Decimal("2.0") - cost_of_change - overhead_fees - Decimal("0.01") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test also passes with much higher upper_bound.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The lower and upper bounds are the minimum and maximum values that cause this test to fail prior to this PR. So a higher upper bound should still pass after this PR, and all values in between should pass after this PR.
8dcbbbe test: fix bug in 22686 (S3RK) Pull request description: It seems there is a bug in the test in bitcoin#22686, the code behaviour itself looks correct. Instead of verifying the scenario from bitcoin#22670 with both `upper_bound` and `lower_bound` for the transaction amount, the tests verified `lower_bound` two times. This fix is to properly use function parameter instead of a variable from the scope. The test still passes with both values, so no code changes are required. ACKs for top commit: achow101: ACK 8dcbbbe Tree-SHA512: 82837b2e00bd075a7b6b7a31031f4d3ba1ab4bd5967e90488f527fcc618aeb3945d6ae3ed66b9eb11616dda3ef376c5001559d2a7a79a759fc6800358bf52537
For target value calculations, GetSelectionAmount should be used, not m_effective_value or m_value. Specifically, ApproximateBestSubset mistakenly uses m_value when calculating whether the target value has been met. This has been changed to use GetSelectionAmount. Github-Pull: bitcoin#22686 Rebased-From: 2de222c
When the fee is not subtracted from the outputs, the amount that has been reserved for the fee (change_and_fee - change_amount) must be enough to cover the fee that is needed. It would be a bug to not do so, so use an assert to make this obvious if such a situation were to occur. Github-Pull: bitcoin#22686 Rebased-From: d926232
ApproximateBestSubset had an edge case (due to not using GetSelectionAmount) where it was possible for it to return success but fail to select enough to cover transaction fees. A test is added that could trigger this failure prior to the fix being implemented. Github-Pull: bitcoin#22686 Rebased-From: 92885c4
For target value calculations, GetSelectionAmount should be used, not m_effective_value or m_value. Specifically, ApproximateBestSubset mistakenly uses m_value when calculating whether the target value has been met. This has been changed to use GetSelectionAmount. Github-Pull: bitcoin#22686 Rebased-From: 2de222c
When the fee is not subtracted from the outputs, the amount that has been reserved for the fee (change_and_fee - change_amount) must be enough to cover the fee that is needed. It would be a bug to not do so, so use an assert to make this obvious if such a situation were to occur. Github-Pull: bitcoin#22686 Rebased-From: d926232
ApproximateBestSubset had an edge case (due to not using GetSelectionAmount) where it was possible for it to return success but fail to select enough to cover transaction fees. A test is added that could trigger this failure prior to the fix being implemented. Github-Pull: bitcoin#22686 Rebased-From: 92885c4
For target value calculations, GetSelectionAmount should be used, not m_effective_value or m_value. Specifically, ApproximateBestSubset mistakenly uses m_value when calculating whether the target value has been met. This has been changed to use GetSelectionAmount. Github-Pull: bitcoin#22686 Rebased-From: 2de222c
When the fee is not subtracted from the outputs, the amount that has been reserved for the fee (change_and_fee - change_amount) must be enough to cover the fee that is needed. It would be a bug to not do so, so use an assert to make this obvious if such a situation were to occur. Github-Pull: bitcoin#22686 Rebased-From: d926232
ApproximateBestSubset had an edge case (due to not using GetSelectionAmount) where it was possible for it to return success but fail to select enough to cover transaction fees. A test is added that could trigger this failure prior to the fix being implemented. Github-Pull: bitcoin#22686 Rebased-From: 92885c4
32e1424 Fix build with Boost 1.77.0 (Rafael Sadowski) cb34a0a qt: Handle new added plurals in bitcoin_en.ts (Hennadii Stepanov) 068985c doc: Mention the flat directory structure for uploads (Andrew Chow) 27d43e5 guix: Don't include directory name in SHA256SUMS (Andrew Chow) 88fb7e3 test: fix bug in 22686 (S3RK) 63fec7e clientversion: No suffix #if CLIENT_VERSION_IS_RELEASE (Carl Dong) dfaffbe test: Test for ApproximateBestSubset edge case with too little fees (Andrew Chow) e86b023 wallet: Assert that enough was selected to cover the fees (Andrew Chow) ffc81e2 wallet: Use GetSelectionAmount for target value calculations (Andrew Chow) ce77b45 release: Release with separate SHA256SUMS and sig files (Carl Dong) cb491bd guix-verify: 10000 Non-zero exit code when anything fails (Carl Dong) 6a611d2 gui: ensure external signer option remains disabled without signers (Andrew Chow) e9b4487 qt: Fix regression in "Encrypt Wallet" menu item (Hennadii Stepanov) 57fce06 consensus/params: simplify ValidDeployment check to avoid gcc warning (Anthony Towns) e9d30fb ci: Run fuzzer task for the master branch only (Hennadii Stepanov) Pull request description: Backported: 1) #22730 1) bitcoin-core/gui#393 1) #22597 1) bitcoin-core/gui#396 1) #22643 1) #22642 1) #22685 1) #22686 1) #22654 1) #22742 1) bitcoin-core/gui#406 1) #22713 ACKs for top commit: laanwj: Code list-of-backported-PRs review ACK 32e1424 Tree-SHA512: f5e2dd1be6cdcd39368eeb5d297b3ff4418d0bf2e70c90e59ab4ba1dbf16f773045d877b4997511de58c3aca75a978dcf043e338bad23951557e2a27ccc845f6
For target value calculations, GetSelectionAmount should be used, not m_effective_value or m_value. Specifically, ApproximateBestSubset mistakenly uses m_value when calculating whether the target value has been met. This has been changed to use GetSelectionAmount. Github-Pull: bitcoin/bitcoin#22686 Rebased-From: 2de222c40198d3d528668d78cc52e2ce3fa96765
When the fee is not subtracted from the outputs, the amount that has been reserved for the fee (change_and_fee - change_amount) must be enough to cover the fee that is needed. It would be a bug to not do so, so use an assert to make this obvious if such a situation were to occur. Github-Pull: bitcoin/bitcoin#22686 Rebased-From: d9262324e80da32725e21d4e0fbfee56f25490b1
ApproximateBestSubset had an edge case (due to not using GetSelectionAmount) where it was possible for it to return success but fail to select enough to cover transaction fees. A test is added that could trigger this failure prior to the fix being implemented. Github-Pull: bitcoin/bitcoin#22686 Rebased-From: 92885c4f69a5e6fc4989677d6e5be8a666fbff0d
For target value calculations, GetSelectionAmount should be used, not m_effective_value or m_value. Specifically, ApproximateBestSubset mistakenly uses m_value when calculating whether the target value has been met. This has been changed to use GetSelectionAmount. Github-Pull: bitcoin/bitcoin#22686 Rebased-From: 2de222c
When the fee is not subtracted from the outputs, the amount that has been reserved for the fee (change_and_fee - change_amount) must be enough to cover the fee that is needed. It would be a bug to not do so, so use an assert to make this obvious if such a situation were to occur. Github-Pull: bitcoin/bitcoin#22686 Rebased-From: d926232
ApproximateBestSubset had an edge case (due to not using GetSelectionAmount) where it was possible for it to return success but fail to select enough to cover transaction fees. A test is added that could trigger this failure prior to the fix being implemented. Github-Pull: bitcoin/bitcoin#22686 Rebased-From: 92885c4
For target value calculations, GetSelectionAmount should be used, not m_effective_value or m_value. Specifically, ApproximateBestSubset mistakenly uses m_value when calculating whether the target value has been met. This has been changed to use GetSelectionAmount. Github-Pull: bitcoin/bitcoin#22686 Rebased-From: 2de222c
When the fee is not subtracted from the outputs, the amount that has been reserved for the fee (change_and_fee - change_amount) must be enough to cover the fee that is needed. It would be a bug to not do so, so use an assert to make this obvious if such a situation were to occur. Github-Pull: bitcoin/bitcoin#22686 Rebased-From: d926232
ApproximateBestSubset had an edge case (due to not using GetSelectionAmount) where it was possible for it to return success but fail to select enough to cover transaction fees. A test is added that could trigger this failure prior to the fix being implemented. Github-Pull: bitcoin/bitcoin#22686 Rebased-From: 92885c4
// The only time that fee_needed should be less than the amount available for fees (in change_and_fee - change_amount) is when | ||
// we are subtracting the fee from the outputs. If this occurs at any other time, it is a bug. | ||
assert(coin_selection_params.m_subtract_fee_outputs || fee_needed <= change_and_fee - change_amount); | ||
|
||
// Update nFeeRet in case fee_needed changed due to dropping the change output | ||
if (fee_needed <= change_and_fee - change_amount) { | ||
nFeeRet = change_and_fee - change_amount; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: this logic looks a little bit funny now. I think it might make more sense to have modified this if
block as
 if (fee_needed <= change_and_fee - change_amount) {
 nFeeRet = change_and_fee - change_amount;
} else {
 // The only time that fee_needed should be less than the amount available for fees (in change_and_fee - change_amount) is when
 // we are subtracting the fee from the outputs. If this occurs at any other time, it is a bug.
 assert(coin_selection_params.m_subtract_fee_outputs);
}
which is logically equivalent but doesn't do the same check twice
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JFYI #25647 changes these lines
When the fee is not subtracted from the outputs, the amount that has been reserved for the fee (change_and_fee - change_amount) must be enough to cover the fee that is needed. It would be a bug to not do so, so use an assert to make this obvious if such a situation were to occur. Github-Pull: bitcoin/bitcoin#22686 Rebased-From: d926232
The
m_value
used for the target calculation inApproximateBestSubset
is incorrect, it should beGetSelectionAmount
. This causes a bug that is only apparent when the minimum relay fee is set to be very high.A test case is added for this, in addition to an assert in
CreateTransactionInternal
that would have also caught this issue if someone were able to hit the edge case.Fixes #22670