Skip to content

Commit 798d7b6

Browse files
committed
Merge #19: Implement proper RBF API so you can satisfy rule 4
0f7cc31 Implement proper RBF logic satisfying rule 4 (LLFourn) 7a28288 Implement proper RBF logic satisfying rule 4 (LLFourn) Pull request description: Removes `min_fee` constraint in favour of proper rule 4 handling (min_fee was pretty useless). See for rule 4: https://github.com/bitcoin/bitcoin/blob/master/doc/policy/mempool-replacements.md#current-replace-by-fee-policy LowestFee BnB metric updated to bound correctly for this. A few other coin_selector API changes Fixes: #12 ACKs for top commit: evanlinjin: ACK 0f7cc31 Tree-SHA512: 85372ae2cd5371e366afc5b1ebd002fbf295abf2d82243f803a44fe41870ad4f7790d744b23b6d9d704a9737c9d0b91773524abd2b78d209db860c387754fa94
2 parents 3a91cc0 + 0f7cc31 commit 798d7b6

19 files changed

+691
-323
lines changed

CHANGELOG.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Unreleased
2+
3+
- Remove `is_target_met_with_change_policy`: it was redundant. If the target is met without a change policy it will always be met with it.
4+
- Remove `min_fee` in favour of `replace` which allows you to replace a transaction
5+
- Remove `Drain` argument from `CoinSelector::select_until_target_met` because adding a drain won't
6+
change when the target is met.
7+

README.md

+34-18
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@ output(s). The other is the weight of spending the drain output later on (the in
7676
use std::str::FromStr;
7777
use bdk_coin_select::{CoinSelector, Candidate, DrainWeights, TXIN_BASE_WEIGHT, ChangePolicy, TR_KEYSPEND_TXIN_WEIGHT};
7878
use bitcoin::{Address, Network, Transaction, TxIn, TxOut};
79-
const TR_SATISFACTION_WEIGHT: u32 = 66;
8079
let base_tx = Transaction {
8180
input: vec![],
8281
output: vec![/* include your recipient outputs here */],
@@ -129,19 +128,37 @@ Built-in metrics are provided in the [`metrics`] submodule. Currently, only the
129128
[`LowestFee`](metrics::LowestFee) metric is considered stable.
130129

131130
```rust
132-
use bdk_coin_select::{ Candidate, CoinSelector, FeeRate, Target, ChangePolicy };
131+
use bdk_coin_select::{ Candidate, CoinSelector, FeeRate, Target, TargetFee, ChangePolicy, TR_KEYSPEND_TXIN_WEIGHT };
133132
use bdk_coin_select::metrics::LowestFee;
134-
let candidates = [];
133+
let candidates = [
134+
Candidate {
135+
input_count: 1,
136+
value: 400_000,
137+
weight: TR_KEYSPEND_TXIN_WEIGHT,
138+
is_segwit: true
139+
},
140+
Candidate {
141+
input_count: 1,
142+
value: 200_000,
143+
weight: TR_KEYSPEND_TXIN_WEIGHT,
144+
is_segwit: true
145+
},
146+
Candidate {
147+
input_count: 1,
148+
value: 11_000,
149+
weight: TR_KEYSPEND_TXIN_WEIGHT,
150+
is_segwit: true
151+
}
152+
];
135153
let base_weight = 0;
136154
let drain_weights = bdk_coin_select::DrainWeights::default();
137155
let dust_limit = 0;
138-
let long_term_feerate = FeeRate::default_min_relay_fee();
156+
let long_term_feerate = FeeRate::from_sat_per_vb(10.0);
139157

140158
let mut coin_selector = CoinSelector::new(&candidates, base_weight);
141159

142160
let target = Target {
143-
feerate: FeeRate::default_min_relay_fee(),
144-
min_fee: 0,
161+
fee: TargetFee::from_feerate(FeeRate::from_sat_per_vb(15.0)),
145162
value: 210_000,
146163
};
147164

@@ -151,7 +168,7 @@ let target = Target {
151168
let change_policy = ChangePolicy::min_value_and_waste(
152169
drain_weights,
153170
dust_limit,
154-
target.feerate,
171+
target.fee.rate,
155172
long_term_feerate,
156173
);
157174

@@ -166,7 +183,11 @@ let metric = LowestFee {
166183

167184
// We run the branch and bound algorithm with a max round limit of 100,000.
168185
match coin_selector.run_bnb(metric, 100_000) {
169-
Err(err) => println!("failed to find a solution: {}", err),
186+
Err(err) => {
187+
println!("failed to find a solution: {}", err);
188+
// fall back to naive selection
189+
coin_selector.select_until_target_met(target).expect("a selection was impossible!");
190+
}
170191
Ok(score) => {
171192
println!("we found a solution with score {}", score);
172193

@@ -179,6 +200,7 @@ match coin_selector.run_bnb(metric, 100_000) {
179200
println!("We are including a change output of {} value (0 means not change)", change.value);
180201
}
181202
};
203+
182204
```
183205

184206
## Finalizing a Selection
@@ -195,7 +217,7 @@ match coin_selector.run_bnb(metric, 100_000) {
195217
use bdk_coin_select::{CoinSelector, Candidate, DrainWeights, Target, ChangePolicy, TR_KEYSPEND_TXIN_WEIGHT, Drain};
196218
use bitcoin::{Amount, TxOut, Address};
197219
let base_weight = 0_u32;
198-
let drain_weights = DrainWeights::new_tr_keyspend();
220+
let drain_weights = DrainWeights::TR_KEYSPEND;
199221
use core::str::FromStr;
200222

201223
// A random target, as an example.
@@ -222,7 +244,7 @@ let candidate_txouts = vec![
222244
script_pubkey: Address::from_str("bc1p0d0rhyynq0awa9m8cqrcr8f5nxqx3aw29w4ru5u9my3h0sfygnzs9khxz8").unwrap().payload.script_pubkey()
223245
}
224246
];
225-
// We transform the candidate txouts into something `CoinSelector` can
247+
// We transform the candidate txouts into something `CoinSelector` can
226248
// understand.
227249
let candidates = candidate_txouts
228250
.iter()
@@ -236,7 +258,7 @@ let candidates = candidate_txouts
236258

237259
let mut selector = CoinSelector::new(&candidates, base_weight);
238260
selector
239-
.select_until_target_met(target, Drain::none())
261+
.select_until_target_met(target)
240262
.expect("we've got enough coins");
241263

242264
// Get a list of coins that are selected.
@@ -256,11 +278,5 @@ if drain.is_some() {
256278

257279
# Minimum Supported Rust Version (MSRV)
258280

259-
This library is tested to compile on 1.54
281+
This library is compiles on rust v1.54 and above
260282

261-
To build with the MSRV, you will need to pin the following dependencies:
262-
263-
```shell
264-
# tempfile 3.7.0 has MSRV 1.63.0+
265-
cargo update -p tempfile --precise "3.6.0"
266-
```

0 commit comments

Comments
 (0)