Skip to content

Commit cd4dd53

Browse files
authored
Merge branch 'bitcoindevkit:master' into fix/truc-utxo-filter
2 parents 07d6718 + db1eab4 commit cd4dd53

16 files changed

Lines changed: 239 additions & 81 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Cargo.lock
44

55
*.swp
66
.idea
7+
justfile.local
78

89
# Example persisted files.
910
*.db

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "bdk_wallet"
33
homepage = "https://bitcoindevkit.org"
4-
version = "3.0.0"
4+
version = "3.1.0-alpha.0"
55
repository = "https://github.com/bitcoindevkit/bdk_wallet"
66
documentation = "https://docs.rs/bdk_wallet"
77
description = "A modern, lightweight, descriptor-based wallet library"

ci/pin-msrv.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ set -euo pipefail
1010
# cargo clean
1111
# rustup default 1.85.0
1212

13+
cargo update -p idna_adapter --precise "1.2.1"
1314
cargo update -p icu_normalizer --precise "2.1.1"
1415
cargo update -p icu_provider --precise "2.1.1"
1516
cargo update -p icu_locale_core --precise "2.1.1"

examples/justfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import? "justfile.local"
2+
13
set quiet := true
24
default_wallet := 'test'
35
default_private := 'false'

justfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import? "justfile.local"
2+
13
alias b := build
24
alias c := check
35
alias f := fmt

rust-toolchain.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
[toolchain]
2-
channel = "1.94.0"
2+
channel = "1.95.0"
33
components = ["clippy", "rustfmt"]

src/descriptor/dsl.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ macro_rules! apply_modifier {
395395
})
396396
}};
397397
( l: $inner:expr ) => {{
398-
$inner.and_then(|(a_minisc, a_keymap, a_networks_kinds)| {
398+
$inner.and_then(|(a_minisc, a_keymap, a_network_kinds)| {
399399
$crate::impl_leaf_opcode_value_two!(
400400
OrI,
401401
$crate::alloc::sync::Arc::new($crate::fragment!(false).unwrap().0),
@@ -405,7 +405,7 @@ macro_rules! apply_modifier {
405405
})
406406
}};
407407
( u: $inner:expr ) => {{
408-
$inner.and_then(|(a_minisc, a_keymap, a_networks)| {
408+
$inner.and_then(|(a_minisc, a_keymap, a_network_kinds)| {
409409
$crate::impl_leaf_opcode_value_two!(
410410
OrI,
411411
$crate::alloc::sync::Arc::new(a_minisc),
@@ -1250,4 +1250,18 @@ mod test {
12501250

12511251
assert_eq!(descriptor.to_string(), "tr(02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c,pk(02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c))#lzl2vmc7")
12521252
}
1253+
1254+
#[test]
1255+
fn test_dsl_l_and_u_modifiers() {
1256+
let private_key =
1257+
PrivateKey::from_wif("cSQPHDBwXGjVzWRqAHm6zfvQhaTuj1f2bFH58h55ghbjtFwvmeXR").unwrap();
1258+
1259+
// Test l: modifier - or_i(false, X)
1260+
let (l_desc, _, _) = descriptor!(wsh(l: pk(private_key))).unwrap();
1261+
assert!(l_desc.to_string().contains("l:pk("));
1262+
1263+
// Test u: modifier - or_i(X, false)
1264+
let (u_desc, _, _) = descriptor!(wsh(u: pk(private_key))).unwrap();
1265+
assert!(u_desc.to_string().contains("u:pk("));
1266+
}
12531267
}

src/test_utils.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,11 @@ pub fn get_test_wpkh_and_change_desc() -> (&'static str, &'static str) {
147147
"wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/*)")
148148
}
149149

150+
/// `wpkh` two-path descriptor
151+
pub fn get_test_two_path_wpkh() -> &'static str {
152+
"wpkh(tpubDDks68wKK1xKaVVVbNmXUAx68K1K817M6KwjvjEyCrjdU7xMvjKnfYAtZjfZcrfPfGFzqmibuVqMzKJGbBnK7mo7WSJri8Y9QgM7aNQ3fCp/<0;1>/*)"
153+
}
154+
150155
/// `wsh` descriptor with policy `and(pk(A),older(6))`
151156
pub fn get_test_single_sig_csv() -> &'static str {
152157
"wsh(and_v(v:pk(cVpPVruEDdmutPzisEsYvtST1usBR3ntr8pXSyt6D2YYqXRyPcFW),older(6)))"

src/wallet/coin_selection.rs

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -704,16 +704,17 @@ impl CoinSelectionAlgorithm for SingleRandomDraw {
704704
}
705705

706706
fn calculate_cs_result(
707-
mut selected_utxos: Vec<OutputGroup>,
708-
mut required_utxos: Vec<OutputGroup>,
707+
selected_utxos: Vec<OutputGroup>,
708+
required_utxos: Vec<OutputGroup>,
709709
excess: Excess,
710710
) -> CoinSelectionResult {
711-
selected_utxos.append(&mut required_utxos);
712-
let fee_amount = selected_utxos.iter().map(|u| u.fee).sum();
713-
let selected = selected_utxos
711+
let mut selected = required_utxos;
712+
selected.extend(selected_utxos);
713+
let fee_amount = selected.iter().map(|u| u.fee).sum();
714+
let selected = selected
714715
.into_iter()
715-
.map(|u| u.weighted_utxo.utxo)
716-
.collect::<Vec<_>>();
716+
.map(|output_group| output_group.weighted_utxo.utxo)
717+
.collect();
717718

718719
CoinSelectionResult {
719720
selected,
@@ -939,7 +940,7 @@ mod test {
939940
.coin_select(
940941
utxos,
941942
vec![],
942-
FeeRate::from_sat_per_vb_unchecked(1),
943+
FeeRate::from_sat_per_vb_u32(1),
943944
target_amount,
944945
&drain_script,
945946
&mut thread_rng(),
@@ -961,7 +962,7 @@ mod test {
961962
.coin_select(
962963
utxos,
963964
vec![],
964-
FeeRate::from_sat_per_vb_unchecked(1),
965+
FeeRate::from_sat_per_vb_u32(1),
965966
target_amount,
966967
&drain_script,
967968
&mut thread_rng(),
@@ -983,7 +984,7 @@ mod test {
983984
.coin_select(
984985
vec![],
985986
utxos,
986-
FeeRate::from_sat_per_vb_unchecked(1),
987+
FeeRate::from_sat_per_vb_u32(1),
987988
target_amount,
988989
&drain_script,
989990
&mut thread_rng(),
@@ -1004,7 +1005,7 @@ mod test {
10041005
let result = LargestFirstCoinSelection.coin_select(
10051006
vec![],
10061007
utxos,
1007-
FeeRate::from_sat_per_vb_unchecked(1),
1008+
FeeRate::from_sat_per_vb_u32(1),
10081009
target_amount,
10091010
&drain_script,
10101011
&mut thread_rng(),
@@ -1021,7 +1022,7 @@ mod test {
10211022
let result = LargestFirstCoinSelection.coin_select(
10221023
vec![],
10231024
utxos,
1024-
FeeRate::from_sat_per_vb_unchecked(1000),
1025+
FeeRate::from_sat_per_vb_u32(1000),
10251026
target_amount,
10261027
&drain_script,
10271028
&mut thread_rng(),
@@ -1039,7 +1040,7 @@ mod test {
10391040
.coin_select(
10401041
vec![],
10411042
utxos,
1042-
FeeRate::from_sat_per_vb_unchecked(1),
1043+
FeeRate::from_sat_per_vb_u32(1),
10431044
target_amount,
10441045
&drain_script,
10451046
&mut thread_rng(),
@@ -1061,7 +1062,7 @@ mod test {
10611062
.coin_select(
10621063
utxos,
10631064
vec![],
1064-
FeeRate::from_sat_per_vb_unchecked(1),
1065+
FeeRate::from_sat_per_vb_u32(1),
10651066
target_amount,
10661067
&drain_script,
10671068
&mut thread_rng(),
@@ -1085,7 +1086,7 @@ mod test {
10851086
.coin_select(
10861087
vec![],
10871088
all_utxos,
1088-
FeeRate::from_sat_per_vb_unchecked(1),
1089+
FeeRate::from_sat_per_vb_u32(1),
10891090
target_amount,
10901091
&drain_script,
10911092
&mut thread_rng(),
@@ -1110,7 +1111,7 @@ mod test {
11101111
.coin_select(
11111112
vec![],
11121113
all_utxos,
1113-
FeeRate::from_sat_per_vb_unchecked(1),
1114+
FeeRate::from_sat_per_vb_u32(1),
11141115
target_amount,
11151116
&drain_script,
11161117
&mut thread_rng(),
@@ -1136,7 +1137,7 @@ mod test {
11361137
.coin_select(
11371138
vec![],
11381139
utxos,
1139-
FeeRate::from_sat_per_vb_unchecked(1),
1140+
FeeRate::from_sat_per_vb_u32(1),
11401141
target_amount,
11411142
&drain_script,
11421143
&mut thread_rng(),
@@ -1157,7 +1158,7 @@ mod test {
11571158
let result = OldestFirstCoinSelection.coin_select(
11581159
vec![],
11591160
utxos,
1160-
FeeRate::from_sat_per_vb_unchecked(1),
1161+
FeeRate::from_sat_per_vb_u32(1),
11611162
target_amount,
11621163
&drain_script,
11631164
&mut thread_rng(),
@@ -1176,7 +1177,7 @@ mod test {
11761177
let result = OldestFirstCoinSelection.coin_select(
11771178
vec![],
11781179
utxos,
1179-
FeeRate::from_sat_per_vb_unchecked(1000),
1180+
FeeRate::from_sat_per_vb_u32(1000),
11801181
target_amount,
11811182
&drain_script,
11821183
&mut thread_rng(),
@@ -1196,7 +1197,7 @@ mod test {
11961197
.coin_select(
11971198
vec![],
11981199
utxos,
1199-
FeeRate::from_sat_per_vb_unchecked(1),
1200+
FeeRate::from_sat_per_vb_u32(1),
12001201
target_amount,
12011202
&drain_script,
12021203
&mut thread_rng(),
@@ -1218,7 +1219,7 @@ mod test {
12181219
.coin_select(
12191220
utxos.clone(),
12201221
utxos,
1221-
FeeRate::from_sat_per_vb_unchecked(1),
1222+
FeeRate::from_sat_per_vb_u32(1),
12221223
target_amount,
12231224
&drain_script,
12241225
&mut thread_rng(),
@@ -1260,7 +1261,7 @@ mod test {
12601261
let mut rng: StdRng = SeedableRng::from_seed(seed);
12611262
let mut utxos = generate_random_utxos(&mut rng, 300);
12621263
let target_amount = sum_random_utxos(&mut rng, &mut utxos) + FEE_AMOUNT;
1263-
let fee_rate = FeeRate::from_sat_per_vb_unchecked(1);
1264+
let fee_rate = FeeRate::from_sat_per_vb_u32(1);
12641265
let drain_script = ScriptBuf::default();
12651266

12661267
let result = SingleRandomDraw.coin_select(
@@ -1288,7 +1289,7 @@ mod test {
12881289
// 100_000, 10, 200_000
12891290
let utxos = get_test_utxos();
12901291
let target_amount = Amount::from_sat(300_000) + FEE_AMOUNT;
1291-
let fee_rate = FeeRate::from_sat_per_vb_unchecked(1);
1292+
let fee_rate = FeeRate::from_sat_per_vb_u32(1);
12921293
let drain_script = ScriptBuf::default();
12931294

12941295
let result = SingleRandomDraw.coin_select(
@@ -1361,7 +1362,7 @@ mod test {
13611362
let result = BranchAndBoundCoinSelection::<SingleRandomDraw>::default().coin_select(
13621363
vec![],
13631364
utxos,
1364-
FeeRate::from_sat_per_vb_unchecked(1),
1365+
FeeRate::from_sat_per_vb_u32(1),
13651366
target_amount,
13661367
&drain_script,
13671368
&mut thread_rng(),
@@ -1379,7 +1380,7 @@ mod test {
13791380
let result = BranchAndBoundCoinSelection::<SingleRandomDraw>::default().coin_select(
13801381
vec![],
13811382
utxos,
1382-
FeeRate::from_sat_per_vb_unchecked(1000),
1383+
FeeRate::from_sat_per_vb_u32(1000),
13831384
target_amount,
13841385
&drain_script,
13851386
&mut thread_rng(),
@@ -1440,7 +1441,7 @@ mod test {
14401441

14411442
#[test]
14421443
fn test_bnb_function_no_exact_match() {
1443-
let fee_rate = FeeRate::from_sat_per_vb_unchecked(10);
1444+
let fee_rate = FeeRate::from_sat_per_vb_u32(10);
14441445
let utxos: Vec<OutputGroup> = get_test_utxos()
14451446
.into_iter()
14461447
.map(|u| OutputGroup::new(u, fee_rate))
@@ -1472,7 +1473,7 @@ mod test {
14721473

14731474
#[test]
14741475
fn test_bnb_function_tries_exceeded() {
1475-
let fee_rate = FeeRate::from_sat_per_vb_unchecked(10);
1476+
let fee_rate = FeeRate::from_sat_per_vb_u32(10);
14761477
let utxos: Vec<OutputGroup> = generate_same_value_utxos(Amount::from_sat(100_000), 100_000)
14771478
.into_iter()
14781479
.map(|u| OutputGroup::new(u, fee_rate))
@@ -1506,7 +1507,7 @@ mod test {
15061507
// The match won't be exact but still in the range
15071508
#[test]
15081509
fn test_bnb_function_almost_exact_match_with_fees() {
1509-
let fee_rate = FeeRate::from_sat_per_vb_unchecked(1);
1510+
let fee_rate = FeeRate::from_sat_per_vb_u32(1);
15101511
let size_of_change = 31;
15111512
let cost_of_change = (Weight::from_vb_unchecked(size_of_change) * fee_rate)
15121513
.to_signed()
@@ -1597,7 +1598,7 @@ mod test {
15971598
let selection = BranchAndBoundCoinSelection::<SingleRandomDraw>::default().coin_select(
15981599
vec![],
15991600
utxos,
1600-
FeeRate::from_sat_per_vb_unchecked(10),
1601+
FeeRate::from_sat_per_vb_u32(10),
16011602
Amount::from_sat(500_000),
16021603
&drain_script,
16031604
&mut thread_rng(),
@@ -1624,7 +1625,7 @@ mod test {
16241625
let selection = BranchAndBoundCoinSelection::<SingleRandomDraw>::default().coin_select(
16251626
required,
16261627
optional,
1627-
FeeRate::from_sat_per_vb_unchecked(10),
1628+
FeeRate::from_sat_per_vb_u32(10),
16281629
Amount::from_sat(500_000),
16291630
&drain_script,
16301631
&mut thread_rng(),
@@ -1647,7 +1648,7 @@ mod test {
16471648
let selection = BranchAndBoundCoinSelection::<SingleRandomDraw>::default().coin_select(
16481649
utxos,
16491650
vec![],
1650-
FeeRate::from_sat_per_vb_unchecked(10_000),
1651+
FeeRate::from_sat_per_vb_u32(10_000),
16511652
Amount::from_sat(500_000),
16521653
&drain_script,
16531654
&mut thread_rng(),
@@ -1721,7 +1722,7 @@ mod test {
17211722
];
17221723

17231724
let optional = generate_same_value_utxos(Amount::from_sat(100_000), 30);
1724-
let fee_rate = FeeRate::from_sat_per_vb_unchecked(1);
1725+
let fee_rate = FeeRate::from_sat_per_vb_u32(1);
17251726
let target_amount = calc_target_amount(&optional[0..3], fee_rate);
17261727
assert_eq!(target_amount, Amount::from_sat(299_796));
17271728
let drain_script = ScriptBuf::default();

src/wallet/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1492,10 +1492,10 @@ impl Wallet {
14921492

14931493
if tx.output.is_empty() {
14941494
// Uh oh, our transaction has no outputs.
1495-
// We allow this when:
1496-
// - We have a drain_to address and the utxos we must spend (this happens,
1497-
// for example, when we RBF).
1498-
// - We have a drain_to address and drain_wallet set.
1495+
// We allow this when we have a `drain_to` address and either:
1496+
// - `drain_wallet` is enabled
1497+
// - there are UTXOs we must spend (this happens, for example, when
1498+
// sweeping specific UTXOs to a given address)
14991499
// Otherwise, we don't know who we should send the funds to, and how much
15001500
// we should send!
15011501
if params.drain_to.is_some() && (params.drain_wallet || !params.utxos.is_empty()) {

0 commit comments

Comments
 (0)