Skip to content

Commit

Permalink
wip: Add loop iteration limit
Browse files Browse the repository at this point in the history
  • Loading branch information
yancyribbens committed Dec 8, 2023
1 parent c98543c commit 4992291
Showing 1 changed file with 133 additions and 19 deletions.
152 changes: 133 additions & 19 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,19 @@ pub fn select_coins_bnb(
_fee_rate: FeeRate,
weighted_utxos: &mut [WeightedUtxo],
) -> Option<Vec<WeightedUtxo>> {
// Total_Tries in Core:
// https://github.com/bitcoin/bitcoin/blob/1d9da8da309d1dbf9aef15eb8dc43b4a2dc3d309/src/wallet/coinselection.cpp#L74
const ITERATION_LIMIT: i32 = 100_000;

let mut iteration = 0;
let mut index = 0;
let mut backtrack;

let mut value = Amount::ZERO;
let waste = Amount::MAX_MONEY;

let mut selection: Vec<WeightedUtxo> = vec![];
let mut best_selection: Vec<WeightedUtxo> = vec![];
let available_value: Amount = weighted_utxos.iter().map(|u| u.utxo.value).sum();

if available_value < target {
Expand All @@ -161,29 +172,67 @@ pub fn select_coins_bnb(

weighted_utxos.sort_by(|a, b| b.utxo.value.cmp(&a.utxo.value));

for (_i, utxo) in weighted_utxos.iter().enumerate() {
while iteration < ITERATION_LIMIT {
backtrack = false;

// backtrack
//
// There are three conditions for backtracking:
//
// * value meets or exceeded target
// * leaf node (nothing left to explorer)
// * not enough value to make it to target
if value >= target
|| available_value + value < target
|| utxo == weighted_utxos.last().unwrap()
{
// backtrack
// * value meets or exceeded target.
// * leaf node (nothing left to explorer).
// * not enough value to make it to target.

// value meets or exceeds the target:
//
// For example:
// o
// /
// 4
// /
// 3
//
// Transform to:
// o
// /
// 4
// / \
// 3
if value >= target {
backtrack = true;
let current_waste = value - target;

if current_waste <= waste {
best_selection = selection.clone();
selection.pop();
}

index -= 1;
}

//if index == selection.len() {
//}

//if available_value + value < target {
//}

if backtrack {
if selection.is_empty() {
return Some(best_selection);
}
}
// proceed with depth first search.
else {
let utxo = &weighted_utxos[index];
selection.push(utxo.clone());
value += utxo.utxo.value;
}

index += 1;
iteration += 1;
}

Some(selection)
Some(best_selection)
}

#[cfg(test)]
Expand Down Expand Up @@ -216,17 +265,82 @@ mod tests {
},
};

vec![utxo_one, utxo_two]
let utxo_three = WeightedUtxo {
satisfaction_weight: SATISFACTION_SIZE,
utxo: TxOut {
value: Amount::from_str("3 cBTC").unwrap(),
script_pubkey: ScriptBuf::new(),
},
};

let utxo_four = WeightedUtxo {
satisfaction_weight: SATISFACTION_SIZE,
utxo: TxOut {
value: Amount::from_str("4 cBTC").unwrap(),
script_pubkey: ScriptBuf::new(),
},
};

vec![utxo_one, utxo_two, utxo_three, utxo_four]
}

#[test]
fn one_solution_one_coin() {
let target = Amount::from_str("1 cBTC").unwrap();

let mut weighted_utxos = vec![WeightedUtxo {
satisfaction_weight: SATISFACTION_SIZE,
utxo: TxOut {
value: Amount::from_str("1 cBTC").unwrap(),
script_pubkey: ScriptBuf::new(),
},
}];

let utxo_match = select_coins_bnb(target, FEE_RATE, &mut weighted_utxos).unwrap();

let expected_utxos = vec![WeightedUtxo {
satisfaction_weight: SATISFACTION_SIZE,
utxo: TxOut {
value: Amount::from_str("1 cBTC").unwrap(),
script_pubkey: ScriptBuf::new(),
},
}];

assert_eq!(utxo_match, expected_utxos);
}

#[test]
fn find_solution_one_cbtc() {
let _target = Amount::from_str("1.5 cBTC").unwrap();
let _weighted_utxos: Vec<WeightedUtxo> = create_weighted_utxos();
fn one_solution_two_coins() {
let target = Amount::from_str("4 cBTC").unwrap();

let mut weighted_utxos = vec![
WeightedUtxo {
satisfaction_weight: SATISFACTION_SIZE,
utxo: TxOut {
value: Amount::from_str("4 cBTC").unwrap(),
script_pubkey: ScriptBuf::new(),
},
},
WeightedUtxo {
satisfaction_weight: SATISFACTION_SIZE,
utxo: TxOut {
value: Amount::from_str("3 cBTC").unwrap(),
script_pubkey: ScriptBuf::new(),
},
},
];

let utxo_match = select_coins_bnb(target, FEE_RATE, &mut weighted_utxos).unwrap();

let expected_utxos = vec![WeightedUtxo {
satisfaction_weight: SATISFACTION_SIZE,
utxo: TxOut {
value: Amount::from_str("4 cBTC").unwrap(),
script_pubkey: ScriptBuf::new(),
},
}];

//let utxo_match = select_coins_bnb(target, FEE_RATE, &mut weighted_utxos);
//let expected_bool_vec = vec![false, false, false, true];
//assert_eq!(expected_bool_vec, utxo_match);
assert_eq!(utxo_match, expected_utxos);
}

//#[test]
Expand Down Expand Up @@ -299,8 +413,8 @@ mod tests {
//}

#[test]
fn select_coins_bnb_no_solution() {
let target: Amount = Amount::from_str("4 cBTC").unwrap();
fn select_coins_bnb_not_enough_value() {
let target: Amount = Amount::from_str("11 cBTC").unwrap();
let mut weighted_utxos: Vec<WeightedUtxo> = create_weighted_utxos();

let result = select_coins_bnb(target, FEE_RATE, &mut weighted_utxos);
Expand Down

0 comments on commit 4992291

Please sign in to comment.