diff --git a/README.md b/README.md index 172866d..96a9e9e 100644 --- a/README.md +++ b/README.md @@ -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| 1000 |897,593| +| C++ Core BnB| 1000 |816,374| + ## Minimum Supported Rust Version (MSRV) This library should always compile with any combination of features on **Rust 1.48**. diff --git a/src/branch_and_bound.rs b/src/branch_and_bound.rs index 74abfff..5ca1a27 100644 --- a/src/branch_and_bound.rs +++ b/src/branch_and_bound.rs @@ -539,3 +539,47 @@ mod tests { assert_eq!(list, expected_list(expected_i_list, &mut weighted_utxos)); } } + +#[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); + }); + } +} diff --git a/src/lib.rs b/src/lib.rs index c700cbf..96493d6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -72,49 +72,3 @@ pub fn select_coins( 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); - }); - } -}