Merge bitcoin/bitcoin#26242: [24.x] wallet: Use correct effective value when checking target

2730ed2b0d6c5cd8e029c67074aac11e610b19fd test: Check external coin effective value is used in CoinSelection (Aurèle Oulès)
21f96f40d18e0b052cb4ef24cda7847051ca16d8 wallet: Use correct effective value when checking target (Aurèle Oulès)

Pull request description:

  backport of #26203

ACKs for top commit:
  jarolrod:
    ACK 2730ed2b0d6c5cd8e029c67074aac11e610b19fd

Tree-SHA512: ce84ac8d47861f290a26d572512467e89ec6ac27973d954d76245b6c6fdea01e36f2e0bce41599abfe14d0014335ebd17b990177771803de39406097973186ca
This commit is contained in:
glozow 2022-10-05 08:52:31 +01:00
commit 2e5706d601
No known key found for this signature in database
GPG Key ID: BA03F4DBE0C63FB4
2 changed files with 54 additions and 1 deletions

View File

@ -590,7 +590,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;
}

View File

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