mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-06-17 01:58:57 +02:00
coinselection: BnB skip exploring high waste
At high feerates adding more inputs will increase the waste score. If the current waste is already higher than the best selection’s we cannot improve upon the best selection. All solutions that include the current selection with more additional inputs must be worse than the best selection so far: SHIFT This optimization only works at high feerates, because at low feerates, adding more inputs decreases waste, so this condition would exit prematurely. We would never attempt input sets with higher weight than the prior best selection, even though we would prefer those at low feerates.
This commit is contained in:
@@ -132,6 +132,8 @@ util::Result<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool
|
||||
|
||||
size_t curr_try = 0;
|
||||
SelectionResult result(selection_target, SelectionAlgorithm::BNB);
|
||||
// We don’t have access to the feerate here, but fee to long_term_fee is as feerate to LTFRE
|
||||
bool is_feerate_high = utxo_pool.at(0).fee > utxo_pool.at(0).long_term_fee;
|
||||
while (true) {
|
||||
bool should_shift{false}, should_cut{false};
|
||||
// Select `next_utxo`
|
||||
@@ -151,6 +153,13 @@ util::Result<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_pool
|
||||
} else if (curr_amount > selection_target + cost_of_change) {
|
||||
// Overshot target range: SHIFT
|
||||
should_shift = true;
|
||||
} else if (is_feerate_high && curr_selection_waste > best_waste) {
|
||||
// At high feerates adding more inputs will increase the waste score. If the current waste is already worse
|
||||
// than the best selection’s while we have insufficient funds, it is impossible for this partial selection
|
||||
// to beat the best selection by adding more inputs: SHIFT
|
||||
// At low feerates, additional inputs lower the waste score, and using this would cause us to skip exploring
|
||||
// combinations with more inputs of lower amounts.
|
||||
should_shift = true;
|
||||
} else if (curr_amount >= selection_target) {
|
||||
// Selection is within target window: potential solution
|
||||
// Adding more UTXOs only increases fees and cannot be better: SHIFT
|
||||
|
||||
@@ -226,7 +226,7 @@ BOOST_AUTO_TEST_CASE(bnb_feerate_sensitivity_test)
|
||||
const CoinSelectionParams high_feerate_params = init_cs_params(/*eff_feerate=*/25'000);
|
||||
std::vector<OutputGroup> 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}, /*expected_attempts=*/8, high_feerate_params);
|
||||
TestBnBSuccess("Select one input at high feerates", high_feerate_pool, /*selection_target=*/10 * CENT, /*expected_input_amounts=*/{10 * CENT}, /*expected_attempts=*/7, 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));
|
||||
@@ -235,7 +235,7 @@ BOOST_AUTO_TEST_CASE(bnb_feerate_sensitivity_test)
|
||||
|
||||
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}, /*expected_attempts=*/28, high_feerate_params);
|
||||
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}, /*expected_attempts=*/15, high_feerate_params);
|
||||
}
|
||||
|
||||
static void TestSRDSuccess(std::string test_title, std::vector<OutputGroup>& utxo_pool, const CAmount& selection_target, const CoinSelectionParams& cs_params = default_cs_params, const int max_selection_weight = MAX_STANDARD_TX_WEIGHT)
|
||||
|
||||
Reference in New Issue
Block a user