diff --git a/README.md b/README.md index ee28526..73ab478 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ A basic performance comparison between this Rust BnB implementation and [Bitcoin |implementation|pool size|ns/iter| |-------------:|---------|-------| -| Rust BnB| 1,000|897,810| +| Rust BnB| 1,000|598,370 | | C++ Core BnB| 1,000|816,374| Note: The measurements where recorded using rustc 1.75. Expect worse performance with MSRV. diff --git a/src/branch_and_bound.rs b/src/branch_and_bound.rs index b445f2b..bd9ab0c 100644 --- a/src/branch_and_bound.rs +++ b/src/branch_and_bound.rs @@ -274,18 +274,23 @@ pub fn select_coins_bnb( // * Add next node to the inclusion branch. else { let (eff_value, utxo_waste, _) = w_utxos[index]; - current_waste = current_waste.checked_add(utxo_waste)?; - - index_selection.push(index); - - // unchecked add is used here for performance. Since the sum of all utxo values - // did not overflow, then any positive subset of the sum will not overflow. - value = value.unchecked_add(eff_value); // unchecked sub is used her for performance. // The bounds for available_value are at most the sum of utxos // and at least zero. available_value = available_value.unchecked_sub(eff_value); + + if index_selection.is_empty() + || index - 1 == *index_selection.last().unwrap() + || w_utxos[index].0 != w_utxos[index - 1].0 + { + index_selection.push(index); + current_waste = current_waste.checked_add(utxo_waste)?; + + // unchecked add is used here for performance. Since the sum of all utxo values + // did not overflow, then any positive subset of the sum will not overflow. + value = value.unchecked_add(eff_value); + } } // no overflow is possible since the iteration count is bounded. @@ -618,6 +623,26 @@ mod tests { assert_coin_select_params(¶ms, Some(&["10 cBTC", "6 cBTC", "2 cBTC"])); } + #[test] + fn select_coins_bnb_early_bail_optimization() { + let mut utxos = vec!["7 cBTC", "7 cBTC", "7 cBTC", "7 cBTC", "2 cBTC"]; + for _i in 0..50_000 { + utxos.push("5 cBTC"); + } + let params = ParamsStr { + target: "30 cBTC", + cost_of_change: "5000 sats", + fee_rate: "0", + lt_fee_rate: "0", + weighted_utxos: utxos, + }; + + assert_coin_select_params( + ¶ms, + Some(&["7 cBTC", "7 cBTC", "7 cBTC", "7 cBTC", "2 cBTC"]), + ); + } + #[test] fn select_coins_bnb_exhaust() { // Recreate make_hard from bitcoin core test suit.