Skip to content

Commit

Permalink
Write lowest fee test that hits important branch
Browse files Browse the repository at this point in the history
That proptest is not hitting for some reason.
  • Loading branch information
LLFourn committed Dec 22, 2023
1 parent b3e71ee commit f242bff
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 3 deletions.
4 changes: 2 additions & 2 deletions src/metrics/lowest_fee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ impl BnbMetric for LowestFee {

if let Some((_, low_sats_per_wu_candidate)) = cs.unselected().next_back() {
let ev = low_sats_per_wu_candidate.effective_value(self.target.feerate);
if ev < 0.0 {
if ev < -0.0 {
// we can only reduce excess if ev is negative
let value_per_negative_effective_value =
low_sats_per_wu_candidate.value_pwu() / ev.abs();
Expand All @@ -78,7 +78,7 @@ impl BnbMetric for LowestFee {
.drain_weights
.waste(self.target.feerate, self.long_term_feerate);
let best_score_without_change = Ordf32(
current_score.0 - cost_of_change + cost_of_getting_rid_of_change,
current_score.0 + cost_of_getting_rid_of_change - cost_of_change,
);
if best_score_without_change < current_score {
return Some(best_score_without_change);
Expand Down
81 changes: 80 additions & 1 deletion tests/lowest_fee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

mod common;
use bdk_coin_select::metrics::{Changeless, LowestFee};
use bdk_coin_select::ChangePolicy;
use bdk_coin_select::{BnbMetric, Candidate, CoinSelector};
use bdk_coin_select::{ChangePolicy, Drain, DrainWeights, FeeRate, Target};
use proptest::prelude::*;

proptest! {
Expand Down Expand Up @@ -160,3 +160,82 @@ fn combined_changeless_metric() {

assert!(combined_rounds >= rounds);
}

/// This test considers the case where you could actually lower your long term fee by adding another input.
#[test]
fn adding_another_input_to_remove_change() {
let target = Target {
feerate: FeeRate::from_sat_per_vb(1.0),
min_fee: 0,
value: 99_700,
};

let candidates = vec![
Candidate {
value: 100_000,
weight: 100,
input_count: 1,
is_segwit: true,
},
Candidate {
value: 50_000,
weight: 100,
input_count: 1,
is_segwit: true,
},
Candidate {
value: 10,
weight: 100,
input_count: 1,
is_segwit: true,
},
];

let mut cs = CoinSelector::new(&candidates, 200);

let best_solution = {
let mut cs = cs.clone();
cs.select(0);
cs.select(2);
cs
};

let drain_weights = DrainWeights {
output_weight: 100,
spend_weight: 1_000,
};

let excess_to_make_first_candidate_satisfy_but_have_change = {
let mut cs = cs.clone();
cs.select(0);
assert!(cs.is_target_met(target));
let with_change_excess = cs.excess(
target,
Drain {
value: 0,
weights: drain_weights,
},
);
assert!(with_change_excess > 0);
with_change_excess as u64
};

let change_policy = ChangePolicy {
min_value: excess_to_make_first_candidate_satisfy_but_have_change - 1,
drain_weights,
};

let mut metric = LowestFee {
target,
long_term_feerate: FeeRate::from_sat_per_vb(1.0),
change_policy,
};

let (score, _) = common::bnb_search(&mut cs, metric, 10).expect("finds solution");
let best_solution_score = metric.score(&best_solution).expect("must be a solution");

assert_eq!(best_solution.drain(target, change_policy), Drain::none());

assert!(score <= best_solution_score);
assert_eq!(cs.selected_indices(), best_solution.selected_indices());
}

0 comments on commit f242bff

Please sign in to comment.