From 7db6f012c08c796645c38b87d35e89cf6c18ed3b Mon Sep 17 00:00:00 2001 From: Murch Date: Fri, 1 Mar 2024 15:06:50 -0500 Subject: [PATCH] test: Move BnB feerate sensitivity tests Originally these tests verified that at a SelectCoins level that a solution with fewer inputs gets preferred at high feerates, and a solution with more inputs gets preferred at low feerates. This outcome relies on the behavior of BnB, so we move these tests under the umbrella of BnB tests. Originally these tests relied on SFFO to work. --- src/wallet/test/coinselection_tests.cpp | 27 +++++++++++++++-- src/wallet/test/coinselector_tests.cpp | 39 ++----------------------- 2 files changed, 28 insertions(+), 38 deletions(-) diff --git a/src/wallet/test/coinselection_tests.cpp b/src/wallet/test/coinselection_tests.cpp index f211e50752..392caabe2d 100644 --- a/src/wallet/test/coinselection_tests.cpp +++ b/src/wallet/test/coinselection_tests.cpp @@ -86,12 +86,12 @@ static std::string InputAmountsToString(const SelectionResult& selection) return "[" + util::Join(selection.GetInputSet(), " ", [](const auto& input){ return util::ToString(input->txout.nValue);}) + "]"; } -static void TestBnBSuccess(std::string test_title, std::vector& utxo_pool, const CAmount& selection_target, const std::vector& expected_input_amounts, const CoinSelectionParams& cs_params = default_cs_params) +static void TestBnBSuccess(std::string test_title, std::vector& utxo_pool, const CAmount& selection_target, const std::vector& expected_input_amounts, const CoinSelectionParams& cs_params = default_cs_params, int custom_spending_vsize = 68) { SelectionResult expected_result(CAmount(0), SelectionAlgorithm::BNB); CAmount expected_amount = 0; for (CAmount input_amount : expected_input_amounts) { - OutputGroup group = MakeCoin(input_amount, true, cs_params); + OutputGroup group = MakeCoin(input_amount, true, cs_params, custom_spending_vsize); expected_amount += group.m_value; expected_result.AddInput(group); } @@ -118,5 +118,28 @@ BOOST_AUTO_TEST_CASE(bnb_test) TestBnBSuccess("Select upper bound", utxo_pool, /*selection_target=*/4 * CENT - default_cs_params.m_cost_of_change, /*expected_input_amounts=*/{1 * CENT, 3 * CENT}); } +BOOST_AUTO_TEST_CASE(bnb_feerate_sensitivity_test) +{ + // Create sets of UTXOs with the same effective amounts at different feerates (but different absolute amounts) + std::vector low_feerate_pool; // 5 sat/vB (default, and lower than long_term_feerate of 10 sat/vB) + AddCoins(low_feerate_pool, {2 * CENT, 3 * CENT, 5 * CENT, 10 * CENT}); + TestBnBSuccess("Select many inputs at low feerates", low_feerate_pool, /*selection_target=*/10 * CENT, /*expected_input_amounts=*/{2 * CENT, 3 * CENT, 5 * CENT}); + + CoinSelectionParams high_feerate_params = init_default_params(); + high_feerate_params.m_effective_feerate = CFeeRate{25'000}; + std::vector high_feerate_pool; // 25 sat/vB (greater than long_term_feerate of 10 sat/vB) + AddCoins(high_feerate_pool, {2 * CENT, 3 * CENT, 5 * CENT, 10 * CENT}, high_feerate_params); + TestBnBSuccess("Select one input at high feerates", high_feerate_pool, /*selection_target=*/10 * CENT, /*expected_input_amounts=*/{10 * CENT}, high_feerate_params); + + // Add heavy inputs {6, 7} to existing {2, 3, 5, 10} + low_feerate_pool.push_back(MakeCoin(6 * CENT, true, default_cs_params, /*custom_spending_vsize=*/500)); + low_feerate_pool.push_back(MakeCoin(7 * CENT, true, default_cs_params, /*custom_spending_vsize=*/500)); + TestBnBSuccess("Prefer two heavy inputs over two light inputs at low feerates", low_feerate_pool, /*selection_target=*/13 * CENT, /*expected_input_amounts=*/{6 * CENT, 7 * CENT}, default_cs_params, /*custom_spending_vsize=*/500); + + high_feerate_pool.push_back(MakeCoin(6 * CENT, true, high_feerate_params, /*custom_spending_vsize=*/500)); + high_feerate_pool.push_back(MakeCoin(7 * CENT, true, high_feerate_params, /*custom_spending_vsize=*/500)); + TestBnBSuccess("Prefer two light inputs over two heavy inputs at high feerates", high_feerate_pool, /*selection_target=*/13 * CENT, /*expected_input_amounts=*/{3 * CENT, 10 * CENT}, high_feerate_params); +} + BOOST_AUTO_TEST_SUITE_END() } // namespace wallet diff --git a/src/wallet/test/coinselector_tests.cpp b/src/wallet/test/coinselector_tests.cpp index ad872de192..7fb88f5f9d 100644 --- a/src/wallet/test/coinselector_tests.cpp +++ b/src/wallet/test/coinselector_tests.cpp @@ -321,7 +321,7 @@ BOOST_AUTO_TEST_CASE(bnb_search_test) CoinsResult available_coins; - // single coin should be selected when effective fee > long term fee + // pre selected coin should be selected even if disadvantageous coin_selection_params_bnb.m_effective_feerate = CFeeRate(5000); coin_selection_params_bnb.m_long_term_feerate = CFeeRate(3000); @@ -332,42 +332,9 @@ BOOST_AUTO_TEST_CASE(bnb_search_test) add_coin(available_coins, *wallet, 1 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true); expected_result.Clear(); - add_coin(10 * CENT + input_fee, 2, expected_result); + add_coin(9 * CENT + input_fee, 2, expected_result); + add_coin(1 * CENT + input_fee, 2, expected_result); CCoinControl coin_control; - const auto result11 = SelectCoins(*wallet, available_coins, /*pre_set_inputs=*/{}, 10 * CENT, coin_control, coin_selection_params_bnb); - BOOST_CHECK(EquivalentResult(expected_result, *result11)); - available_coins.Clear(); - - // more coins should be selected when effective fee < long term fee - coin_selection_params_bnb.m_effective_feerate = CFeeRate(3000); - coin_selection_params_bnb.m_long_term_feerate = CFeeRate(5000); - - // Add selectable outputs, increasing their raw amounts by their input fee to make the effective value equal to the raw amount - input_fee = coin_selection_params_bnb.m_effective_feerate.GetFee(/*num_bytes=*/68); // bech32 input size (default test output type) - add_coin(available_coins, *wallet, 10 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true); - add_coin(available_coins, *wallet, 9 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true); - add_coin(available_coins, *wallet, 1 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true); - - expected_result.Clear(); - add_coin(9 * CENT + input_fee, 2, expected_result); - add_coin(1 * CENT + input_fee, 2, expected_result); - const auto result12 = SelectCoins(*wallet, available_coins, /*pre_set_inputs=*/{}, 10 * CENT, coin_control, coin_selection_params_bnb); - BOOST_CHECK(EquivalentResult(expected_result, *result12)); - available_coins.Clear(); - - // pre selected coin should be selected even if disadvantageous - coin_selection_params_bnb.m_effective_feerate = CFeeRate(5000); - coin_selection_params_bnb.m_long_term_feerate = CFeeRate(3000); - - // Add selectable outputs, increasing their raw amounts by their input fee to make the effective value equal to the raw amount - input_fee = coin_selection_params_bnb.m_effective_feerate.GetFee(/*num_bytes=*/68); // bech32 input size (default test output type) - add_coin(available_coins, *wallet, 10 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true); - add_coin(available_coins, *wallet, 9 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true); - add_coin(available_coins, *wallet, 1 * CENT + input_fee, coin_selection_params_bnb.m_effective_feerate, 6 * 24, false, 0, true); - - expected_result.Clear(); - add_coin(9 * CENT + input_fee, 2, expected_result); - add_coin(1 * CENT + input_fee, 2, expected_result); coin_control.m_allow_other_inputs = true; COutput select_coin = available_coins.All().at(1); // pre select 9 coin coin_control.Select(select_coin.outpoint);