Skip to content

Commit

Permalink
Add benchmark for branch and bound
Browse files Browse the repository at this point in the history
  • Loading branch information
yancyribbens committed Jan 2, 2024
1 parent 0875ab2 commit d1b0e32
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 46 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,19 @@ The current interface is provided via `select_coins()` function. The required p

As discussed in the literature above, ideally we want to choose a selection from the existing UTXO set available to the wallet. However, if there is no combination that efficiently matches the target spend amount, then creating a change output by splitting a UTXO is the next best option. Therefore, the algorithm takes into account the current cost of creating a new output (cost_of_change).

## Benchmarks

To run the benchmarks use: RUSTFLAGS='--cfg=bench' cargo +nightly bench.

### performance comparison

A basic performance comparison between this current [Rust BnB](https://github.com/p2pderivatives/rust-bitcoin-coin-selection/pull/28/files#diff-9098d62be93e83524a8371395c973d761a95000d1c295f600a8c808e917c16d9R122) implementation and the [Bitcoin Core](https://github.com/bitcoin/bitcoin/blob/4b1196a9855dcd188a24f393aa2fa21e2d61f061/src/wallet/coinselection.cpp#L76) version using commodity hardware (My rather old laptop).

|implementation|pool size|ns/iter|
|-------------:|---------|-------|
| Rust BnB| 1,000|897,593|
| C++ Core BnB| 1,000|816,374|

## Minimum Supported Rust Version (MSRV)

This library should always compile with any combination of features on **Rust 1.48**.
44 changes: 44 additions & 0 deletions src/branch_and_bound.rs
Original file line number Diff line number Diff line change
Expand Up @@ -537,3 +537,47 @@ mod tests {
assert_eq!(list, Vec::new());
}
}

#[cfg(bench)]
#[cfg(test)]
mod benches {
use super::*;
use bitcoin::ScriptBuf;
use bitcoin::TxOut;
use bitcoin::Weight;
use test::Bencher;

#[bench]
/// Creates a UTXO pool of 1,000 coins that do not match and one coin
/// that will be a match when combined with any of the other 1,000 coins.
///
/// Matching benchmark of Bitcoin core coin-selection benchmark.
// https://github.com/bitcoin/bitcoin/blob/f3bc1a72825fe2b51f4bc20e004cef464f05b965/src/bench/coin_selection.cpp#L44
fn bench_select_coins_bnb(bh: &mut Bencher) {
// https://github.com/bitcoin/bitcoin/blob/f3bc1a72825fe2b51f4bc20e004cef464f05b965/src/wallet/coinselection.h#L18
let cost_of_change = Amount::from_sat(50_000);

let one = WeightedUtxo {
satisfaction_weight: Weight::ZERO,
utxo: TxOut { value: Amount::from_sat(1_000), script_pubkey: ScriptBuf::new() },
};

let two = WeightedUtxo {
satisfaction_weight: Weight::ZERO,
utxo: TxOut { value: Amount::from_sat(3), script_pubkey: ScriptBuf::new() },
};

let target = Amount::from_sat(1_003);
let mut utxo_pool = vec![one; 1000];
utxo_pool.push(two);

bh.iter(|| {
let result =
select_coins_bnb(target, cost_of_change, FeeRate::ZERO, &mut utxo_pool.clone())
.unwrap();
assert_eq!(2, result.len());
assert_eq!(Amount::from_sat(1_000), result[0].utxo.value);
assert_eq!(Amount::from_sat(3), result[1].utxo.value);
});
}
}
46 changes: 0 additions & 46 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,49 +72,3 @@ pub fn select_coins<T: Utxo>(
coins
}
}

#[cfg(bench)]
mod benches {
use crate::select_coins_bnb;
use crate::Utxo;
use test::Bencher;

#[derive(Clone, Debug, Eq, PartialEq)]
struct MinimalUtxo {
value: u64,
}

impl Utxo for MinimalUtxo {
fn get_value(&self) -> u64 {
self.value
}
}

#[bench]
/// Creates a UTXO pool of 1,000 coins that do not match and one coin
/// that will be a match when combined with any of the other 1,000 coins.
///
/// Matching benchmark of Bitcoin core coin-selection benchmark.
// https://github.com/bitcoin/bitcoin/blob/f3bc1a72825fe2b51f4bc20e004cef464f05b965/src/bench/coin_selection.cpp#L44
fn bench_select_coins_bnb(bh: &mut Bencher) {
// https://github.com/bitcoin/bitcoin/blob/f3bc1a72825fe2b51f4bc20e004cef464f05b965/src/consensus/amount.h#L15
/// The amount of satoshis in one BTC.
const COIN: u64 = 100_000_000;

// https://github.com/bitcoin/bitcoin/blob/f3bc1a72825fe2b51f4bc20e004cef464f05b965/src/wallet/coinselection.h#L18
/// lower bound for randomly-chosen target change amount
const CHANGE_LOWER: u64 = 50_000;

let u = MinimalUtxo { value: 1000 * COIN };
let mut utxo_pool = vec![u; 1000];
utxo_pool.push(MinimalUtxo { value: 3 * COIN });

bh.iter(|| {
let result =
select_coins_bnb(1003 * COIN, CHANGE_LOWER, &mut utxo_pool.clone()).unwrap();
assert_eq!(2, result.len());
assert_eq!(1000 * COIN, result[0].value);
assert_eq!(3 * COIN, result[1].value);
});
}
}

0 comments on commit d1b0e32

Please sign in to comment.