Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/iter branch and bound #30

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,11 @@
# 0.2.0 - 2023-06-03

- Add Single Random Draw module and a basic error type.

# 0.3.0 - 2024-02-07

- Move existing branch and bound to a new module.
- Re-implement branch and bound optimizing for waste score and performance.
- Change the return type of SRD to Iterator.
- Use Criterion instead of Cargo Bench for benchmarking.
- Bump MSRV to 1.56.1
17 changes: 11 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,27 @@ homepage = "https://github.com/rust-bitcoin/rust-bitcoin-coin-selection/"
license = "CC0-1.0"
name = "rust-bitcoin-coin-selection"
repository = "https://github.com/rust-bitcoin/rust-bitcoin-coin-selection/"
version = "0.2.0"
version = "0.3.0"
# documentation = "https://docs.rs/bitcoin-coin-selection/"
description = "Libary providing utility functions to efficiently select a set of UTXOs."
keywords = ["crypto", "bitcoin"]
readme = "README.md"

[dependencies]
bitcoin = { git="https://github.com/yancyribbens/rust-bitcoin", branch = "add-effective-value-calculation" }
bitcoin = { git="https://github.com/yancyribbens/rust-bitcoin", rev="2f109442e30d74fb7502e7fd1ce2075a67262cd5" }
rand = {version = "0.8.5", default-features = false, optional = true}

[dev-dependencies]
criterion = "0.3"
rust-bitcoin-coin-selection = {path = ".", features = ["rand"]}
rand = "0.8.5"

[patch.crates-io]
bitcoin_hashes = { git = "https://github.com/yancyribbens/rust-bitcoin", branch = "add-effective-value-calculation" }
bitcoin-io = { git = "https://github.com/yancyribbens/rust-bitcoin", branch = "add-effective-value-calculation" }
bitcoin-units = { git = "https://github.com/yancyribbens/rust-bitcoin", branch = "add-effective-value-calculation" }
bitcoin-internals = { git = "https://github.com/yancyribbens/rust-bitcoin", branch = "add-effective-value-calculation" }
bitcoin_hashes = { git = "https://github.com/yancyribbens/rust-bitcoin", rev="2f109442e30d74fb7502e7fd1ce2075a67262cd5" }
bitcoin-io = { git = "https://github.com/yancyribbens/rust-bitcoin", rev="2f109442e30d74fb7502e7fd1ce2075a67262cd5" }
bitcoin-units = { git = "https://github.com/yancyribbens/rust-bitcoin", rev="2f109442e30d74fb7502e7fd1ce2075a67262cd5" }
bitcoin-internals = { git = "https://github.com/yancyribbens/rust-bitcoin", rev="2f109442e30d74fb7502e7fd1ce2075a67262cd5" }

[[bench]]
name = "coin_selection"
harness = false
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,23 @@ 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: `cargo bench`.

Note: criterion requires rustc version 1.65 to run the benchmarks.

### 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,810|
| C++ Core BnB| 1,000|816,374|

Note: The measurements where recorded using rustc 1.75. Expect worse performance with MSRV.

## Minimum Supported Rust Version (MSRV)

This library should always compile with any combination of features on **Rust 1.48**.
This library should always compile with any combination of features on **Rust 1.56.1**.
49 changes: 49 additions & 0 deletions benches/coin_selection.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use criterion::{black_box, criterion_group, criterion_main, Criterion};

use bitcoin::Amount;
use bitcoin::FeeRate;
use bitcoin::ScriptBuf;
use bitcoin::TxOut;
use bitcoin::Weight;
use rust_bitcoin_coin_selection::select_coins_bnb;
use rust_bitcoin_coin_selection::WeightedUtxo;

pub fn criterion_benchmark(c: &mut Criterion) {
// 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);

c.bench_function("bnb 1000", |b| {
b.iter(|| {
let result: Vec<_> = select_coins_bnb(
black_box(target),
black_box(cost_of_change),
black_box(FeeRate::ZERO),
black_box(FeeRate::ZERO),
black_box(&utxo_pool),
)
.unwrap()
.collect();

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);
})
});
}

criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);
Loading
Loading