diff options
author | glozow <gloriajzhao@gmail.com> | 2022-10-04 09:57:05 +0100 |
---|---|---|
committer | glozow <gloriajzhao@gmail.com> | 2022-10-04 09:57:17 +0100 |
commit | cda6c791903c10ec20d3a6c4619bfe78ff02f3b6 (patch) | |
tree | 101e234b5c624b41a9bbabeb64388701699cda11 /src | |
parent | 1730f6cb23cc05445df3266cb21b8846b99427b4 (diff) | |
parent | d0d9cf7aea2ff36a14a19e6999400e4070b7b0c9 (diff) | |
download | bitcoin-cda6c791903c10ec20d3a6c4619bfe78ff02f3b6.tar.xz |
Merge bitcoin/bitcoin#26203: wallet: Use correct effective value when checking target
d0d9cf7aea2ff36a14a19e6999400e4070b7b0c9 test: Check external coin effective value is used in CoinSelection (Aurèle Oulès)
76b79c1a177afa006184d716bd3d5b22ebadb168 wallet: Use correct effective value when checking target (Aurèle Oulès)
Pull request description:
Fixes #26185. The following assert failed because it was not checked in the parent function.
https://github.com/bitcoin/bitcoin/blob/2bd9aa5a44b88c866c4d98f8a7bf7154049cba31/src/wallet/coinselection.cpp#L391
ACKs for top commit:
glozow:
reACK d0d9cf7aea2ff36a14a19e6999400e4070b7b0c9
furszy:
ACK d0d9cf7a
Tree-SHA512: e126daba1115e9d143f2a582c6953e7ea55e96853b6e819c7744fd7a23668f7d9854681d43ef55d8774655bc54e7e87c1c9fccd746d9e30fbf3caa82ef808ae9
Diffstat (limited to 'src')
-rw-r--r-- | src/wallet/spend.cpp | 8 | ||||
-rw-r--r-- | src/wallet/test/coinselector_tests.cpp | 47 |
2 files changed, 54 insertions, 1 deletions
diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp index 523db8d7bc..6833f9a095 100644 --- a/src/wallet/spend.cpp +++ b/src/wallet/spend.cpp @@ -582,7 +582,13 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& a if (coin_control.HasSelected() && !coin_control.m_allow_other_inputs) { SelectionResult result(nTargetValue, SelectionAlgorithm::MANUAL); result.AddInput(preset_inputs); - if (result.GetSelectedValue() < nTargetValue) return std::nullopt; + + if (!coin_selection_params.m_subtract_fee_outputs && result.GetSelectedEffectiveValue() < nTargetValue) { + return std::nullopt; + } else if (result.GetSelectedValue() < nTargetValue) { + return std::nullopt; + } + result.ComputeAndSetWaste(coin_selection_params.min_viable_change, coin_selection_params.m_cost_of_change, coin_selection_params.m_change_fee); return result; } diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp index 30a7fb9eb6..23f024247d 100644 --- a/src/wallet/test/coinselector_tests.cpp +++ b/src/wallet/test/coinselector_tests.cpp @@ -922,5 +922,52 @@ BOOST_AUTO_TEST_CASE(effective_value_test) BOOST_CHECK_EQUAL(output5.GetEffectiveValue(), nValue); // The effective value should be equal to the absolute value if input_bytes is -1 } +BOOST_AUTO_TEST_CASE(SelectCoins_effective_value_test) +{ + // Test that the effective value is used to check whether preset inputs provide sufficient funds when subtract_fee_outputs is not used. + // This test creates a coin whose value is higher than the target but whose effective value is lower than the target. + // The coin is selected using coin control, with m_allow_other_inputs = false. SelectCoins should fail due to insufficient funds. + + std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(m_node.chain.get(), "", m_args, CreateMockWalletDatabase()); + wallet->LoadWallet(); + LOCK(wallet->cs_wallet); + wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS); + wallet->SetupDescriptorScriptPubKeyMans(); + + CoinsResult available_coins; + { + std::unique_ptr<CWallet> dummyWallet = std::make_unique<CWallet>(m_node.chain.get(), "dummy", m_args, CreateMockWalletDatabase()); + dummyWallet->LoadWallet(); + LOCK(dummyWallet->cs_wallet); + dummyWallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS); + dummyWallet->SetupDescriptorScriptPubKeyMans(); + + add_coin(available_coins, *dummyWallet, 100000); // 0.001 BTC + } + + CAmount target{99900}; // 0.000999 BTC + + FastRandomContext rand; + CoinSelectionParams cs_params{ + rand, + /*change_output_size=*/34, + /*change_spend_size=*/148, + /*min_change_target=*/1000, + /*effective_feerate=*/CFeeRate(3000), + /*long_term_feerate=*/CFeeRate(1000), + /*discard_feerate=*/CFeeRate(1000), + /*tx_noinputs_size=*/0, + /*avoid_partial=*/false, + }; + CCoinControl cc; + cc.m_allow_other_inputs = false; + COutput output = available_coins.All().at(0); + cc.SetInputWeight(output.outpoint, 148); + cc.SelectExternal(output.outpoint, output.txout); + + const auto result = SelectCoins(*wallet, available_coins, target, cc, cs_params); + BOOST_CHECK(!result); +} + BOOST_AUTO_TEST_SUITE_END() } // namespace wallet |