Skip to content

Commit

Permalink
Add constant CHANGE_LOWER
Browse files Browse the repository at this point in the history
  • Loading branch information
yancyribbens committed Feb 21, 2023
1 parent 9fc03bc commit 48fc157
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 8 deletions.
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ pub use crate::single_random_draw::select_coins_srd;
#[cfg(any(test, feature = "rand"))]
use crate::errors::LibError;

// https://github.com/bitcoin/bitcoin/blob/f722a9bd132222d9d5cd503b5af25c905b205cdb/src/wallet/coinselection.h#L20
#[cfg(any(test, feature = "rand"))]
const CHANGE_LOWER: u64 = 50_000;

/// Trait that a UTXO struct must implement to be used as part of the coin selection
/// algorithm.
pub trait Utxo: Clone {
Expand Down
35 changes: 27 additions & 8 deletions src/single_random_draw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
#[cfg(any(test, feature = "rand"))]
use crate::Utxo;

#[cfg(any(test, feature = "rand"))]
use crate::CHANGE_LOWER;

#[cfg(any(test, feature = "rand"))]
use rand::seq::SliceRandom;

Expand All @@ -30,7 +33,12 @@ pub fn select_coins_srd<T: Utxo, R: rand::Rng + ?Sized>(

let mut i = 0;

while sum < target && i < utxo_pool.len() {
// The required size of a change output must be at least
// larger than the target by CHANGE_LOWER amount to avoid
// needlessly small change outputs.
let lower_bound = target + CHANGE_LOWER;

while sum < lower_bound && i < utxo_pool.len() {
let utxo = &utxo_pool[i];

let fee = get_fee_vbytes(fee_rate, utxo.get_weight())?;
Expand All @@ -41,7 +49,7 @@ pub fn select_coins_srd<T: Utxo, R: rand::Rng + ?Sized>(
i += 1;
}

if sum >= target {
if sum >= lower_bound {
Ok(Some(res))
} else {
Ok(None)
Expand All @@ -52,6 +60,7 @@ pub fn select_coins_srd<T: Utxo, R: rand::Rng + ?Sized>(
mod tests {
use crate::single_random_draw::select_coins_srd;
use crate::Utxo;
use crate::CHANGE_LOWER;
use rand::rngs::mock::StepRng;

// https://github.com/bitcoin/bitcoin/blob/b264410e012a61b103e1a03c43df4e17b9b75452/src/test/util/setup_common.h#L80
Expand All @@ -60,8 +69,8 @@ mod tests {
const FEE_RATE: u64 = 10;

const UTXO_POOL: [MinimalUtxo; 2] = [
MinimalUtxo { value: CENT, weight: WEIGHT },
MinimalUtxo { value: 2 * CENT, weight: WEIGHT },
MinimalUtxo { value: CENT + CHANGE_LOWER, weight: WEIGHT },
MinimalUtxo { value: 2 * CENT + CHANGE_LOWER, weight: WEIGHT },
];

#[derive(Clone, Debug, Eq, PartialEq)]
Expand Down Expand Up @@ -112,7 +121,7 @@ mod tests {

#[test]
fn select_coins_srd_with_solution() {
let expected_result = vec![MinimalUtxo { value: 2 * CENT, weight: WEIGHT }];
let expected_result = vec![MinimalUtxo { value: 2 * CENT + CHANGE_LOWER, weight: WEIGHT }];
let utxo_match = select_coins_srd(
target_minus_fee(2 * CENT, 1),
&mut UTXO_POOL.clone(),
Expand All @@ -127,8 +136,8 @@ mod tests {
#[test]
fn select_coins_all_solution() {
let expected_result = vec![
MinimalUtxo { value: CENT * 2, weight: WEIGHT },
MinimalUtxo { value: CENT, weight: WEIGHT },
MinimalUtxo { value: CENT * 2 + CHANGE_LOWER, weight: WEIGHT },
MinimalUtxo { value: CENT + CHANGE_LOWER, weight: WEIGHT },
];

let utxo_match = select_coins_srd(
Expand Down Expand Up @@ -164,7 +173,7 @@ mod tests {

#[test]
fn select_coins_srd_with_error_can_succeed() {
let value = CENT;
let value = CENT + CHANGE_LOWER;
let expected_result = vec![MinimalUtxo { value, weight: WEIGHT }];

let mut utxo_pool = vec![
Expand All @@ -177,4 +186,14 @@ mod tests {

assert_eq!(utxo_match.expect("did not properly select coins"), expected_result);
}

#[test]
fn select_coins_srd_change_output_too_small() {
let mut utxo_pool = [MinimalUtxo { value: CENT, weight: WEIGHT }];

let utxo_match =
select_coins_srd(target_minus_fee(CENT, 1), &mut utxo_pool, FEE_RATE, &mut get_rng())
.expect("unexpected error");
assert!(utxo_match.is_none());
}
}

0 comments on commit 48fc157

Please sign in to comment.