• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

bitcoindevkit / bdk / 9475497656

12 Jun 2024 02:00AM UTC coverage: 82.974% (-0.4%) from 83.405%
9475497656

Pull #1468

github

web-flow
Merge 44e446faa into 473ef9714
Pull Request #1468: wip(feat): use `Weight` type instead of `usize`

112 of 190 new or added lines in 19 files covered. (58.95%)

13 existing lines in 3 files now uncovered.

11253 of 13562 relevant lines covered (82.97%)

16764.07 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

55.15
/crates/wallet/src/descriptor/dsl.rs
1
// Bitcoin Dev Kit
2
// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
3
//
4
// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
5
//
6
// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
7
// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
8
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
9
// You may not use this file except in accordance with one or both of these
10
// licenses.
11

12
//! Descriptors DSL
13

14
#[doc(hidden)]
15
#[macro_export]
16
macro_rules! impl_top_level_sh {
17
    // disallow `sortedmulti` in `bare()`
18
    ( Bare, new, new, Legacy, sortedmulti $( $inner:tt )* ) => {
19
        compile_error!("`bare()` descriptors can't contain any `sortedmulti()` operands");
20
    };
21
    ( Bare, new, new, Legacy, sortedmulti_vec $( $inner:tt )* ) => {
22
        compile_error!("`bare()` descriptors can't contain any `sortedmulti_vec()` operands");
23
    };
24

25
    ( $inner_struct:ident, $constructor:ident, $sortedmulti_constructor:ident, $ctx:ident, sortedmulti $( $inner:tt )* ) => {{
26
        use core::marker::PhantomData;
27

28
        use $crate::miniscript::descriptor::{$inner_struct, Descriptor, DescriptorPublicKey};
29
        use $crate::miniscript::$ctx;
30

31
        let build_desc = |k, pks| {
2✔
32
            Ok((Descriptor::<DescriptorPublicKey>::$inner_struct($inner_struct::$sortedmulti_constructor(k, pks)?), PhantomData::<$ctx>))
2✔
33
        };
2✔
34

35
        $crate::impl_sortedmulti!(build_desc, sortedmulti $( $inner )*)
36
    }};
37
    ( $inner_struct:ident, $constructor:ident, $sortedmulti_constructor:ident, $ctx:ident, sortedmulti_vec $( $inner:tt )* ) => {{
38
        use core::marker::PhantomData;
39

40
        use $crate::miniscript::descriptor::{$inner_struct, Descriptor, DescriptorPublicKey};
41
        use $crate::miniscript::$ctx;
42

43
        let build_desc = |k, pks| {
1✔
44
            Ok((Descriptor::<DescriptorPublicKey>::$inner_struct($inner_struct::$sortedmulti_constructor(k, pks)?), PhantomData::<$ctx>))
1✔
45
        };
1✔
46

47
        $crate::impl_sortedmulti!(build_desc, sortedmulti_vec $( $inner )*)
48
    }};
49

50
    ( $inner_struct:ident, $constructor:ident, $sortedmulti_constructor:ident, $ctx:ident, $( $minisc:tt )* ) => {{
51
        use $crate::miniscript::descriptor::{$inner_struct, Descriptor, DescriptorPublicKey};
52

53
        $crate::fragment!($( $minisc )*)
54
            .and_then(|(minisc, keymap, networks)| Ok(($inner_struct::$constructor(minisc)?, keymap, networks)))
20✔
55
            .and_then(|(inner, key_map, valid_networks)| Ok((Descriptor::<DescriptorPublicKey>::$inner_struct(inner), key_map, valid_networks)))
20✔
56
    }};
57
}
58

59
#[doc(hidden)]
60
#[macro_export]
61
macro_rules! impl_top_level_pk {
62
    ( $inner_type:ident, $ctx:ty, $key:expr ) => {{
63
        use $crate::miniscript::descriptor::$inner_type;
64

65
        #[allow(unused_imports)]
66
        use $crate::keys::{DescriptorKey, IntoDescriptorKey};
67
        let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
68

69
        $key.into_descriptor_key()
70
            .and_then(|key: DescriptorKey<$ctx>| key.extract(&secp))
41✔
71
            .map_err($crate::descriptor::DescriptorError::Key)
72
            .map(|(pk, key_map, valid_networks)| ($inner_type::new(pk), key_map, valid_networks))
41✔
73
    }};
74
}
75

76
#[doc(hidden)]
77
#[macro_export]
78
macro_rules! impl_top_level_tr {
79
    ( $internal_key:expr, $tap_tree:expr ) => {{
80
        use $crate::miniscript::descriptor::{
81
            Descriptor, DescriptorPublicKey, KeyMap, TapTree, Tr,
82
        };
83
        use $crate::miniscript::Tap;
84

85
        #[allow(unused_imports)]
86
        use $crate::keys::{DescriptorKey, IntoDescriptorKey, ValidNetworks};
87

88
        let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
89

90
        $internal_key
91
            .into_descriptor_key()
92
            .and_then(|key: DescriptorKey<Tap>| key.extract(&secp))
13✔
93
            .map_err($crate::descriptor::DescriptorError::Key)
94
            .and_then(|(pk, mut key_map, mut valid_networks)| {
13✔
95
                let tap_tree = $tap_tree.map(
13✔
96
                    |(tap_tree, tree_keymap, tree_networks): (
13✔
97
                        TapTree<DescriptorPublicKey>,
98
                        KeyMap,
99
                        ValidNetworks,
100
                    )| {
4✔
101
                        key_map.extend(tree_keymap.into_iter());
4✔
102
                        valid_networks =
4✔
103
                            $crate::keys::merge_networks(&valid_networks, &tree_networks);
4✔
104

4✔
105
                        tap_tree
4✔
106
                    },
13✔
107
                );
13✔
108

13✔
109
                Ok((
13✔
110
                    Descriptor::<DescriptorPublicKey>::Tr(Tr::new(pk, tap_tree)?),
13✔
111
                    key_map,
13✔
112
                    valid_networks,
13✔
113
                ))
114
            })
13✔
115
    }};
×
116
}
×
117

×
118
#[doc(hidden)]
×
119
#[macro_export]
×
120
macro_rules! impl_leaf_opcode {
×
121
    ( $terminal_variant:ident ) => {{
×
122
        use $crate::descriptor::CheckMiniscript;
×
123

×
124
        $crate::miniscript::Miniscript::from_ast(
×
125
            $crate::miniscript::miniscript::decode::Terminal::$terminal_variant,
×
126
        )
×
127
        .map_err($crate::descriptor::DescriptorError::Miniscript)
×
128
        .and_then(|minisc| {
×
129
            minisc.check_miniscript()?;
×
130
            Ok(minisc)
×
131
        })
×
132
        .map(|minisc| {
×
133
            (
×
134
                minisc,
×
135
                $crate::miniscript::descriptor::KeyMap::default(),
×
136
                $crate::keys::any_network(),
×
137
            )
×
138
        })
×
139
    }};
×
140
}
×
141

×
142
#[doc(hidden)]
×
143
#[macro_export]
×
144
macro_rules! impl_leaf_opcode_value {
×
145
    ( $terminal_variant:ident, $value:expr ) => {{
×
146
        use $crate::descriptor::CheckMiniscript;
×
147

×
148
        $crate::miniscript::Miniscript::from_ast(
×
149
            $crate::miniscript::miniscript::decode::Terminal::$terminal_variant($value),
×
150
        )
×
151
        .map_err($crate::descriptor::DescriptorError::Miniscript)
×
152
        .and_then(|minisc| {
5✔
153
            minisc.check_miniscript()?;
5✔
154
            Ok(minisc)
5✔
155
        })
5✔
156
        .map(|minisc| {
5✔
157
            (
5✔
158
                minisc,
5✔
159
                $crate::miniscript::descriptor::KeyMap::default(),
5✔
160
                $crate::keys::any_network(),
5✔
161
            )
5✔
162
        })
5✔
163
    }};
×
164
}
×
165

×
166
#[doc(hidden)]
×
167
#[macro_export]
×
168
macro_rules! impl_leaf_opcode_value_two {
×
169
    ( $terminal_variant:ident, $one:expr, $two:expr ) => {{
×
170
        use $crate::descriptor::CheckMiniscript;
×
171

×
172
        $crate::miniscript::Miniscript::from_ast(
×
173
            $crate::miniscript::miniscript::decode::Terminal::$terminal_variant($one, $two),
×
174
        )
×
175
        .map_err($crate::descriptor::DescriptorError::Miniscript)
×
UNCOV
176
        .and_then(|minisc| {
×
UNCOV
177
            minisc.check_miniscript()?;
×
UNCOV
178
            Ok(minisc)
×
UNCOV
179
        })
×
UNCOV
180
        .map(|minisc| {
×
UNCOV
181
            (
×
UNCOV
182
                minisc,
×
UNCOV
183
                $crate::miniscript::descriptor::KeyMap::default(),
×
UNCOV
184
                $crate::keys::any_network(),
×
UNCOV
185
            )
×
UNCOV
186
        })
×
187
    }};
×
188
}
×
189

×
190
#[doc(hidden)]
×
191
#[macro_export]
×
192
macro_rules! impl_node_opcode_two {
×
193
    ( $terminal_variant:ident, $( $inner:tt )* ) => ({
×
194
        use $crate::descriptor::CheckMiniscript;
×
195

×
196
        let inner = $crate::fragment_internal!( @t $( $inner )* );
×
197
        let (a, b) = $crate::descriptor::dsl::TupleTwo::from(inner).flattened();
×
198

×
199
        a
×
200
            .and_then(|a| Ok((a, b?)))
×
201
            .and_then(|((a_minisc, mut a_keymap, a_networks), (b_minisc, b_keymap, b_networks))| {
×
202
                // join key_maps
×
203
                a_keymap.extend(b_keymap.into_iter());
×
204

×
205
                let minisc = $crate::miniscript::Miniscript::from_ast($crate::miniscript::miniscript::decode::Terminal::$terminal_variant(
×
206
                    $crate::alloc::sync::Arc::new(a_minisc),
×
207
                    $crate::alloc::sync::Arc::new(b_minisc),
×
208
                ))?;
×
209

×
210
                minisc.check_miniscript()?;
×
211

×
212
                Ok((minisc, a_keymap, $crate::keys::merge_networks(&a_networks, &b_networks)))
×
213
            })
×
214
    });
×
215
}
×
216

×
217
#[doc(hidden)]
×
218
#[macro_export]
×
219
macro_rules! impl_node_opcode_three {
×
220
    ( $terminal_variant:ident, $( $inner:tt )* ) => ({
×
221
        use $crate::descriptor::CheckMiniscript;
×
222

×
223
        let inner = $crate::fragment_internal!( @t $( $inner )* );
×
224
        let (a, b, c) = $crate::descriptor::dsl::TupleThree::from(inner).flattened();
×
225

×
226
        a
×
227
            .and_then(|a| Ok((a, b?, c?)))
2✔
228
            .and_then(|((a_minisc, mut a_keymap, a_networks), (b_minisc, b_keymap, b_networks), (c_minisc, c_keymap, c_networks))| {
2✔
229
                // join key_maps
2✔
230
                a_keymap.extend(b_keymap.into_iter());
2✔
231
                a_keymap.extend(c_keymap.into_iter());
2✔
232

2✔
233
                let networks = $crate::keys::merge_networks(&a_networks, &b_networks);
2✔
234
                let networks = $crate::keys::merge_networks(&networks, &c_networks);
2✔
235

×
236
                let minisc = $crate::miniscript::Miniscript::from_ast($crate::miniscript::miniscript::decode::Terminal::$terminal_variant(
2✔
237
                    $crate::alloc::sync::Arc::new(a_minisc),
2✔
238
                    $crate::alloc::sync::Arc::new(b_minisc),
2✔
239
                    $crate::alloc::sync::Arc::new(c_minisc),
2✔
240
                ))?;
2✔
241

×
242
                minisc.check_miniscript()?;
2✔
243

×
244
                Ok((minisc, a_keymap, networks))
2✔
245
            })
2✔
246
    });
×
247
}
×
248

×
249
#[doc(hidden)]
×
250
#[macro_export]
×
251
macro_rules! impl_sortedmulti {
×
252
    ( $build_desc:expr, sortedmulti_vec ( $thresh:expr, $keys:expr ) ) => ({
×
253
        let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
×
254
        $crate::keys::make_sortedmulti($thresh, $keys, $build_desc, &secp)
×
255
    });
×
256
    ( $build_desc:expr, sortedmulti ( $thresh:expr $(, $key:expr )+ ) ) => ({
×
257
        use $crate::keys::IntoDescriptorKey;
×
258
        let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
×
259

×
260
        let keys = vec![
×
261
            $(
×
262
                $key.into_descriptor_key(),
×
263
            )*
×
264
        ];
×
265

×
266
        keys.into_iter().collect::<Result<$crate::alloc::vec::Vec<_>, _>>()
×
267
            .map_err($crate::descriptor::DescriptorError::Key)
×
268
            .and_then(|keys| $crate::keys::make_sortedmulti($thresh, keys, $build_desc, &secp))
2✔
269
    });
×
270

×
271
}
×
272

×
273
#[doc(hidden)]
×
274
#[macro_export]
×
275
macro_rules! parse_tap_tree {
×
276
    ( @merge $tree_a:expr, $tree_b:expr) => {{
×
277
        use $crate::miniscript::descriptor::TapTree;
×
278

×
279
        $tree_a
×
280
            .and_then(|tree_a| Ok((tree_a, $tree_b?)))
1✔
281
            .and_then(|((a_tree, mut a_keymap, a_networks), (b_tree, b_keymap, b_networks))| {
1✔
282
                a_keymap.extend(b_keymap.into_iter());
1✔
283
                Ok((TapTree::combine(a_tree, b_tree), a_keymap, $crate::keys::merge_networks(&a_networks, &b_networks)))
1✔
284
            })
1✔
285

×
286
    }};
×
287

×
288
    // Two sub-trees
×
289
    ( { { $( $tree_a:tt )* }, { $( $tree_b:tt )* } } ) => {{
×
290
        let tree_a = $crate::parse_tap_tree!( { $( $tree_a )* } );
×
291
        let tree_b = $crate::parse_tap_tree!( { $( $tree_b )* } );
×
292

×
293
        $crate::parse_tap_tree!(@merge tree_a, tree_b)
×
294
    }};
×
295

×
296
    // One leaf and a sub-tree
×
297
    ( { $op_a:ident ( $( $minisc_a:tt )* ), { $( $tree_b:tt )* } } ) => {{
×
298
        let tree_a = $crate::parse_tap_tree!( $op_a ( $( $minisc_a )* ) );
×
299
        let tree_b = $crate::parse_tap_tree!( { $( $tree_b )* } );
×
300

×
301
        $crate::parse_tap_tree!(@merge tree_a, tree_b)
×
302
    }};
×
303
    ( { { $( $tree_a:tt )* }, $op_b:ident ( $( $minisc_b:tt )* ) } ) => {{
×
304
        let tree_a = $crate::parse_tap_tree!( { $( $tree_a )* } );
×
305
        let tree_b = $crate::parse_tap_tree!( $op_b ( $( $minisc_b )* ) );
×
306

×
307
        $crate::parse_tap_tree!(@merge tree_a, tree_b)
×
308
    }};
×
309

×
310
    // Two leaves
×
311
    ( { $op_a:ident ( $( $minisc_a:tt )* ), $op_b:ident ( $( $minisc_b:tt )* ) } ) => {{
×
312
        let tree_a = $crate::parse_tap_tree!( $op_a ( $( $minisc_a )* ) );
×
313
        let tree_b = $crate::parse_tap_tree!( $op_b ( $( $minisc_b )* ) );
×
314

×
315
        $crate::parse_tap_tree!(@merge tree_a, tree_b)
×
316
    }};
×
317

×
318
    // Single leaf
×
319
    ( $op:ident ( $( $minisc:tt )* ) ) => {{
×
320
        use $crate::alloc::sync::Arc;
×
321
        use $crate::miniscript::descriptor::TapTree;
×
322

×
323
        $crate::fragment!( $op ( $( $minisc )* ) )
×
324
            .map(|(a_minisc, a_keymap, a_networks)| (TapTree::Leaf(Arc::new(a_minisc)), a_keymap, a_networks))
5✔
325
    }};
×
326
}
×
327

×
328
#[doc(hidden)]
×
329
#[macro_export]
×
330
macro_rules! apply_modifier {
×
331
    ( $terminal_variant:ident, $inner:expr ) => {{
×
332
        use $crate::descriptor::CheckMiniscript;
×
333

×
334
        $inner
×
335
            .map_err(|e| -> $crate::descriptor::DescriptorError { e.into() })
2✔
336
            .and_then(|(minisc, keymap, networks)| {
25✔
337
                let minisc = $crate::miniscript::Miniscript::from_ast(
25✔
338
                    $crate::miniscript::miniscript::decode::Terminal::$terminal_variant(
25✔
339
                        $crate::alloc::sync::Arc::new(minisc),
25✔
340
                    ),
25✔
341
                )?;
25✔
342

×
343
                minisc.check_miniscript()?;
25✔
344

×
345
                Ok((minisc, keymap, networks))
25✔
346
            })
25✔
347
    }};
×
348

×
349
    ( a: $inner:expr ) => {{
×
350
        $crate::apply_modifier!(Alt, $inner)
×
351
    }};
×
352
    ( s: $inner:expr ) => {{
×
353
        $crate::apply_modifier!(Swap, $inner)
×
354
    }};
×
355
    ( c: $inner:expr ) => {{
×
356
        $crate::apply_modifier!(Check, $inner)
×
357
    }};
×
358
    ( d: $inner:expr ) => {{
×
359
        $crate::apply_modifier!(DupIf, $inner)
×
360
    }};
×
361
    ( v: $inner:expr ) => {{
×
362
        $crate::apply_modifier!(Verify, $inner)
×
363
    }};
×
364
    ( j: $inner:expr ) => {{
×
365
        $crate::apply_modifier!(NonZero, $inner)
×
366
    }};
×
367
    ( n: $inner:expr ) => {{
×
368
        $crate::apply_modifier!(ZeroNotEqual, $inner)
×
369
    }};
×
370

×
371
    // Modifiers expanded to other operators
×
372
    ( t: $inner:expr ) => {{
×
373
        $inner.and_then(|(a_minisc, a_keymap, a_networks)| {
×
374
            $crate::impl_leaf_opcode_value_two!(
×
375
                AndV,
×
376
                $crate::alloc::sync::Arc::new(a_minisc),
×
377
                $crate::alloc::sync::Arc::new($crate::fragment!(true).unwrap().0)
×
378
            )
×
379
            .map(|(minisc, _, _)| (minisc, a_keymap, a_networks))
×
380
        })
×
381
    }};
×
382
    ( l: $inner:expr ) => {{
×
383
        $inner.and_then(|(a_minisc, a_keymap, a_networks)| {
×
384
            $crate::impl_leaf_opcode_value_two!(
×
385
                OrI,
×
386
                $crate::alloc::sync::Arc::new($crate::fragment!(false).unwrap().0),
×
387
                $crate::alloc::sync::Arc::new(a_minisc)
×
388
            )
×
389
            .map(|(minisc, _, _)| (minisc, a_keymap, a_networks))
×
390
        })
×
391
    }};
×
392
    ( u: $inner:expr ) => {{
×
393
        $inner.and_then(|(a_minisc, a_keymap, a_networks)| {
×
394
            $crate::impl_leaf_opcode_value_two!(
×
395
                OrI,
×
396
                $crate::alloc::sync::Arc::new(a_minisc),
×
397
                $crate::alloc::sync::Arc::new($crate::fragment!(false).unwrap().0)
×
398
            )
×
399
            .map(|(minisc, _, _)| (minisc, a_keymap, a_networks))
×
400
        })
×
401
    }};
×
402
}
×
403

×
404
/// Macro to write full descriptors with code
×
405
///
×
406
/// This macro expands to a `Result` of
×
407
/// [`DescriptorTemplateOut`](super::template::DescriptorTemplateOut) and [`DescriptorError`](crate::descriptor::DescriptorError)
×
408
///
×
409
/// The syntax is very similar to the normal descriptor syntax, with the exception that modifiers
×
410
/// cannot be grouped together. For instance, a descriptor fragment like `sdv:older(144)` has to be
×
411
/// broken up to `s:d:v:older(144)`.
×
412
///
×
413
/// The `pk()`, `pk_k()` and `pk_h()` operands can take as argument any type that implements
×
414
/// [`IntoDescriptorKey`]. This means that keys can also be written inline as strings, but in that
×
415
/// case they must be wrapped in quotes, which is another difference compared to the standard
×
416
/// descriptor syntax.
×
417
///
×
418
/// [`IntoDescriptorKey`]: crate::keys::IntoDescriptorKey
×
419
///
×
420
/// ## Example
×
421
///
×
422
/// Signature plus timelock descriptor:
×
423
///
×
424
/// ```
×
425
/// # use std::str::FromStr;
×
426
/// let (my_descriptor, my_keys_map, networks) = bdk_wallet::descriptor!(sh(wsh(and_v(v:pk("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy"),older(50)))))?;
×
427
/// # Ok::<(), Box<dyn std::error::Error>>(())
×
428
/// ```
×
429
///
×
430
/// -------
×
431
///
×
432
/// 2-of-3 that becomes a 1-of-3 after a timelock has expired. Both `descriptor_a` and `descriptor_b` are equivalent: the first
×
433
/// syntax is more suitable for a fixed number of items known at compile time, while the other accepts a
×
434
/// [`Vec`] of items, which makes it more suitable for writing dynamic descriptors.
×
435
///
×
436
/// They both produce the descriptor: `wsh(thresh(2,pk(...),s:pk(...),sndv:older(...)))`
×
437
///
×
438
/// ```
×
439
/// # use std::str::FromStr;
×
440
/// let my_key_1 = bitcoin::PublicKey::from_str(
×
441
///     "02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c",
×
442
/// )?;
×
443
/// let my_key_2 =
×
444
///     bitcoin::PrivateKey::from_wif("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy")?;
×
445
/// let my_timelock = 50;
×
446
///
×
447
/// let (descriptor_a, key_map_a, networks) = bdk_wallet::descriptor! {
×
448
///     wsh (
×
449
///         thresh(2, pk(my_key_1), s:pk(my_key_2), s:n:d:v:older(my_timelock))
×
450
///     )
×
451
/// }?;
×
452
///
×
453
/// #[rustfmt::skip]
×
454
/// let b_items = vec![
×
455
///     bdk_wallet::fragment!(pk(my_key_1))?,
×
456
///     bdk_wallet::fragment!(s:pk(my_key_2))?,
×
457
///     bdk_wallet::fragment!(s:n:d:v:older(my_timelock))?,
×
458
/// ];
×
459
/// let (descriptor_b, mut key_map_b, networks) =
×
460
///     bdk_wallet::descriptor!(wsh(thresh_vec(2, b_items)))?;
×
461
///
×
462
/// assert_eq!(descriptor_a, descriptor_b);
×
463
/// assert_eq!(key_map_a.len(), key_map_b.len());
×
464
/// # Ok::<(), Box<dyn std::error::Error>>(())
×
465
/// ```
×
466
///
×
467
/// ------
×
468
///
×
469
/// Simple 2-of-2 multi-signature, equivalent to: `wsh(multi(2, ...))`
×
470
///
×
471
/// ```
×
472
/// # use std::str::FromStr;
×
473
/// let my_key_1 = bitcoin::PublicKey::from_str(
×
474
///     "02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c",
×
475
/// )?;
×
476
/// let my_key_2 =
×
477
///     bitcoin::PrivateKey::from_wif("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy")?;
×
478
///
×
479
/// let (descriptor, key_map, networks) = bdk_wallet::descriptor! {
×
480
///     wsh (
×
481
///         multi(2, my_key_1, my_key_2)
×
482
///     )
×
483
/// }?;
×
484
/// # Ok::<(), Box<dyn std::error::Error>>(())
×
485
/// ```
×
486
///
×
487
/// ------
×
488
///
×
489
/// Native-Segwit single-sig, equivalent to: `wpkh(...)`
×
490
///
×
491
/// ```
×
492
/// let my_key =
×
493
///     bitcoin::PrivateKey::from_wif("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy")?;
×
494
///
×
495
/// let (descriptor, key_map, networks) = bdk_wallet::descriptor!(wpkh(my_key))?;
×
496
/// # Ok::<(), Box<dyn std::error::Error>>(())
×
497
/// ```
×
498
///
×
499
/// [`Vec`]: alloc::vec::Vec
×
500
#[macro_export]
×
501
macro_rules! descriptor {
×
502
    ( bare ( $( $minisc:tt )* ) ) => ({
×
503
        $crate::impl_top_level_sh!(Bare, new, new, Legacy, $( $minisc )*)
×
504
    });
×
505
    ( sh ( wsh ( $( $minisc:tt )* ) ) ) => ({
×
506
        $crate::descriptor!(shwsh ($( $minisc )*))
×
507
    });
×
508
    ( shwsh ( $( $minisc:tt )* ) ) => ({
×
509
        $crate::impl_top_level_sh!(Sh, new_wsh, new_wsh_sortedmulti, Segwitv0, $( $minisc )*)
×
510
    });
×
511
    ( pk ( $key:expr ) ) => ({
×
512
        // `pk()` is actually implemented as `bare(pk())`
×
513
        $crate::descriptor!( bare ( pk ( $key ) ) )
×
514
    });
×
515
    ( pkh ( $key:expr ) ) => ({
×
516
        use $crate::miniscript::descriptor::{Descriptor, DescriptorPublicKey};
×
517

×
518
        $crate::impl_top_level_pk!(Pkh, $crate::miniscript::Legacy, $key)
×
519
            .and_then(|(a, b, c)| Ok((a.map_err(|e| miniscript::Error::from(e))?, b, c)))
12✔
520
            .map(|(a, b, c)| (Descriptor::<DescriptorPublicKey>::Pkh(a), b, c))
12✔
521
    });
522
    ( wpkh ( $key:expr ) ) => ({
523
        use $crate::miniscript::descriptor::{Descriptor, DescriptorPublicKey};
524

525
        $crate::impl_top_level_pk!(Wpkh, $crate::miniscript::Segwitv0, $key)
526
            .and_then(|(a, b, c)| Ok((a.map_err(|e| miniscript::Error::from(e))?, b, c)))
21✔
527
            .map(|(a, b, c)| (Descriptor::<DescriptorPublicKey>::Wpkh(a), b, c))
21✔
528
    });
529
    ( sh ( wpkh ( $key:expr ) ) ) => ({
530
        $crate::descriptor!(shwpkh ( $key ))
531
    });
532
    ( shwpkh ( $key:expr ) ) => ({
533
        use $crate::miniscript::descriptor::{Descriptor, DescriptorPublicKey, Sh};
534

535
        $crate::impl_top_level_pk!(Wpkh, $crate::miniscript::Segwitv0, $key)
536
            .and_then(|(a, b, c)| Ok((a.map_err(|e| miniscript::Error::from(e))?, b, c)))
8✔
537
            .and_then(|(a, b, c)| Ok((Descriptor::<DescriptorPublicKey>::Sh(Sh::new_wpkh(a.into_inner())?), b, c)))
8✔
538
    });
539
    ( sh ( $( $minisc:tt )* ) ) => ({
540
        $crate::impl_top_level_sh!(Sh, new, new_sortedmulti, Legacy, $( $minisc )*)
541
    });
542
    ( wsh ( $( $minisc:tt )* ) ) => ({
543
        $crate::impl_top_level_sh!(Wsh, new, new_sortedmulti, Segwitv0, $( $minisc )*)
544
    });
545

546
    ( tr ( $internal_key:expr ) ) => ({
547
        $crate::impl_top_level_tr!($internal_key, None)
548
    });
549
    ( tr ( $internal_key:expr, $( $taptree:tt )* ) ) => ({
550
        let tap_tree = $crate::parse_tap_tree!( $( $taptree )* );
551
        tap_tree
552
            .and_then(|tap_tree| $crate::impl_top_level_tr!($internal_key, Some(tap_tree)))
4✔
553
    });
554
}
555

556
#[doc(hidden)]
557
pub struct TupleTwo<A, B> {
558
    pub a: A,
559
    pub b: B,
560
}
561

562
impl<A, B> TupleTwo<A, B> {
563
    pub fn flattened(self) -> (A, B) {
×
564
        (self.a, self.b)
×
565
    }
×
566
}
567

568
impl<A, B> From<(A, (B, ()))> for TupleTwo<A, B> {
569
    fn from((a, (b, _)): (A, (B, ()))) -> Self {
×
570
        TupleTwo { a, b }
×
571
    }
×
572
}
573

574
#[doc(hidden)]
575
pub struct TupleThree<A, B, C> {
576
    pub a: A,
577
    pub b: B,
578
    pub c: C,
579
}
580

581
impl<A, B, C> TupleThree<A, B, C> {
582
    pub fn flattened(self) -> (A, B, C) {
2✔
583
        (self.a, self.b, self.c)
2✔
584
    }
2✔
585
}
586

587
impl<A, B, C> From<(A, (B, (C, ())))> for TupleThree<A, B, C> {
588
    fn from((a, (b, (c, _))): (A, (B, (C, ())))) -> Self {
2✔
589
        TupleThree { a, b, c }
2✔
590
    }
2✔
591
}
592

593
#[doc(hidden)]
594
#[macro_export]
595
macro_rules! group_multi_keys {
596
    ( $( $key:expr ),+ ) => {{
597
        use $crate::keys::IntoDescriptorKey;
598

599
        let keys = vec![
600
            $(
601
                $key.into_descriptor_key(),
602
            )*
603
        ];
604

605
        keys.into_iter().collect::<Result<$crate::alloc::vec::Vec<_>, _>>()
606
            .map_err($crate::descriptor::DescriptorError::Key)
607
    }};
608
}
609

610
#[doc(hidden)]
611
#[macro_export]
612
macro_rules! fragment_internal {
613
    // The @v prefix is used to parse a sequence of operands and return them in a vector. This is
614
    // used by operands that take a variable number of arguments, like `thresh()` and `multi()`.
615
    ( @v $op:ident ( $( $args:tt )* ) $( $tail:tt )* ) => ({
616
        let mut v = vec![$crate::fragment!( $op ( $( $args )* ) )];
617
        v.append(&mut $crate::fragment_internal!( @v $( $tail )* ));
618

619
        v
620
    });
621
    // Match modifiers
622
    ( @v $modif:tt : $( $tail:tt )* ) => ({
623
        let mut v = $crate::fragment_internal!( @v $( $tail )* );
624
        let first = v.drain(..1).next().unwrap();
625

626
        let first = $crate::apply_modifier!($modif:first);
627

628
        let mut v_final = vec![first];
629
        v_final.append(&mut v);
630

631
        v_final
632
    });
633
    // Remove commas between operands
634
    ( @v , $( $tail:tt )* ) => ({
635
        $crate::fragment_internal!( @v $( $tail )* )
636
    });
637
    ( @v ) => ({
638
        vec![]
639
    });
640

641
    // The @t prefix is used to parse a sequence of operands and return them in a tuple. This
642
    // allows checking at compile-time the number of arguments passed to an operand. For this
643
    // reason it's used by `and_*()`, `or_*()`, etc.
644
    //
645
    // Unfortunately, due to the fact that concatenating tuples is pretty hard, the final result
646
    // adds in the first spot the parsed operand and in the second spot the result of parsing
647
    // all the following ones. For two operands the type then corresponds to: (X, (X, ())). For
648
    // three operands it's (X, (X, (X, ()))), etc.
649
    //
650
    // To check that the right number of arguments has been passed we can "cast" those tuples to
651
    // more convenient structures like `TupleTwo`. If the conversion succeeds, the right number of
652
    // args was passed. Otherwise the compilation fails entirely.
653
    ( @t $op:ident ( $( $args:tt )* ) $( $tail:tt )* ) => ({
654
        ($crate::fragment!( $op ( $( $args )* ) ), $crate::fragment_internal!( @t $( $tail )* ))
655
    });
656
    // Match modifiers
657
    ( @t $modif:tt : $( $tail:tt )* ) => ({
658
        let (first, tail) = $crate::fragment_internal!( @t $( $tail )* );
659
        ($crate::apply_modifier!($modif:first), tail)
660
    });
661
    // Remove commas between operands
662
    ( @t , $( $tail:tt )* ) => ({
663
        $crate::fragment_internal!( @t $( $tail )* )
664
    });
665
    ( @t ) => ({});
666

667
    // Fallback to calling `fragment!()`
668
    ( $( $tokens:tt )* ) => ({
669
        $crate::fragment!($( $tokens )*)
670
    });
671
}
672

673
/// Macro to write descriptor fragments with code
674
///
675
/// This macro will be expanded to an object of type `Result<(Miniscript<DescriptorPublicKey, _>, KeyMap, ValidNetworks), DescriptorError>`. It allows writing
676
/// fragments of larger descriptors that can be pieced together using `fragment!(thresh_vec(m, ...))`.
677
///
678
/// The syntax to write macro fragment is the same as documented for the [`descriptor`] macro.
679
#[macro_export]
680
macro_rules! fragment {
681
    // Modifiers
682
    ( $modif:tt : $( $tail:tt )* ) => ({
683
        let op = $crate::fragment!( $( $tail )* );
684
        $crate::apply_modifier!($modif:op)
685
    });
686

687
    // Miniscript
688
    ( true ) => ({
689
        $crate::impl_leaf_opcode!(True)
690
    });
691
    ( false ) => ({
692
        $crate::impl_leaf_opcode!(False)
693
    });
694
    ( pk_k ( $key:expr ) ) => ({
695
        let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
696
        $crate::keys::make_pk($key, &secp)
697
    });
698
    ( pk ( $key:expr ) ) => ({
699
        $crate::fragment!(c:pk_k ( $key ))
700
    });
701
    ( pk_h ( $key:expr ) ) => ({
702
        let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
703
        $crate::keys::make_pkh($key, &secp)
704
    });
705
    ( after ( $value:expr ) ) => ({
706
        $crate::impl_leaf_opcode_value!(After, $crate::miniscript::AbsLockTime::from_consensus($value).expect("valid `AbsLockTime`"))
707
    });
708
    ( older ( $value:expr ) ) => ({
709
        $crate::impl_leaf_opcode_value!(Older, $crate::miniscript::RelLockTime::from_consensus($value).expect("valid `RelLockTime`")) // TODO!!
710
    });
711
    ( sha256 ( $hash:expr ) ) => ({
712
        $crate::impl_leaf_opcode_value!(Sha256, $hash)
713
    });
714
    ( hash256 ( $hash:expr ) ) => ({
715
        $crate::impl_leaf_opcode_value!(Hash256, $hash)
716
    });
717
    ( ripemd160 ( $hash:expr ) ) => ({
718
        $crate::impl_leaf_opcode_value!(Ripemd160, $hash)
719
    });
720
    ( hash160 ( $hash:expr ) ) => ({
721
        $crate::impl_leaf_opcode_value!(Hash160, $hash)
722
    });
723
    ( and_v ( $( $inner:tt )* ) ) => ({
724
        $crate::impl_node_opcode_two!(AndV, $( $inner )*)
725
    });
726
    ( and_b ( $( $inner:tt )* ) ) => ({
727
        $crate::impl_node_opcode_two!(AndB, $( $inner )*)
728
    });
729
    ( and_or ( $( $inner:tt )* ) ) => ({
730
        $crate::impl_node_opcode_three!(AndOr, $( $inner )*)
731
    });
732
    ( andor ( $( $inner:tt )* ) ) => ({
733
        $crate::impl_node_opcode_three!(AndOr, $( $inner )*)
734
    });
735
    ( or_b ( $( $inner:tt )* ) ) => ({
736
        $crate::impl_node_opcode_two!(OrB, $( $inner )*)
737
    });
738
    ( or_d ( $( $inner:tt )* ) ) => ({
739
        $crate::impl_node_opcode_two!(OrD, $( $inner )*)
740
    });
741
    ( or_c ( $( $inner:tt )* ) ) => ({
742
        $crate::impl_node_opcode_two!(OrC, $( $inner )*)
743
    });
744
    ( or_i ( $( $inner:tt )* ) ) => ({
745
        $crate::impl_node_opcode_two!(OrI, $( $inner )*)
746
    });
747
    ( thresh_vec ( $thresh:expr, $items:expr ) ) => ({
748
        use $crate::miniscript::descriptor::KeyMap;
749

750
        let (items, key_maps_networks): ($crate::alloc::vec::Vec<_>, $crate::alloc::vec::Vec<_>) = $items.into_iter().map(|(a, b, c)| (a, (b, c))).unzip();
6✔
751
        let items = items.into_iter().map($crate::alloc::sync::Arc::new).collect();
752

753
        let (key_maps, valid_networks) = key_maps_networks.into_iter().fold((KeyMap::default(), $crate::keys::any_network()), |(mut keys_acc, net_acc), (key, net)| {
6✔
754
            keys_acc.extend(key.into_iter());
6✔
755
            let net_acc = $crate::keys::merge_networks(&net_acc, &net);
6✔
756

6✔
757
            (keys_acc, net_acc)
6✔
758
        });
6✔
759

760
        let thresh = $crate::miniscript::Threshold::new($thresh, items).expect("valid threshold and pks collection");
761
        $crate::impl_leaf_opcode_value!(Thresh, thresh)
762
            .map(|(minisc, _, _)| (minisc, key_maps, valid_networks))
2✔
763
    });
764
    ( thresh ( $thresh:expr, $( $inner:tt )* ) ) => ({
765
        let items = $crate::fragment_internal!( @v $( $inner )* );
766

767
        items.into_iter().collect::<Result<$crate::alloc::vec::Vec<_>, _>>()
768
            .and_then(|items| $crate::fragment!(thresh_vec($thresh, items)))
2✔
769
    });
770
    ( multi_vec ( $thresh:expr, $keys:expr ) ) => ({
771
        let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
772

773
        let fun = |k, pks| {
14✔
774
            let thresh = $crate::miniscript::Threshold::new(k, pks).expect("valid threshold and pks collection");
14✔
775
            $crate::miniscript::Terminal::Multi(thresh)
14✔
776
        };
14✔
777

778
        $crate::keys::make_multi($thresh, fun, $keys, &secp)
779
    });
780
    ( multi ( $thresh:expr $(, $key:expr )+ ) ) => ({
781
        $crate::group_multi_keys!( $( $key ),* )
782
            .and_then(|keys| $crate::fragment!( multi_vec ( $thresh, keys ) ))
14✔
783
    });
784
    ( multi_a_vec ( $thresh:expr, $keys:expr ) ) => ({
785
        let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
786

787
        let fun = |k, pks| {
788
            let thresh = $crate::miniscript::Threshold::new(k, pks).expect("valid threshold and pks collection");
789
            $crate::miniscript::Terminal::MultiA(thresh)
790
        };
791

792
        $crate::keys::make_multi($thresh, fun, $keys, &secp)
793
    });
794
    ( multi_a ( $thresh:expr $(, $key:expr )+ ) ) => ({
795
        $crate::group_multi_keys!( $( $key ),* )
796
            .and_then(|keys| $crate::fragment!( multi_a_vec ( $thresh, keys ) ))
797
    });
798

799
    // `sortedmulti()` is handled separately
800
    ( sortedmulti ( $( $inner:tt )* ) ) => ({
801
        compile_error!("`sortedmulti` can only be used as the root operand of a descriptor");
802
    });
803
    ( sortedmulti_vec ( $( $inner:tt )* ) ) => ({
804
        compile_error!("`sortedmulti_vec` can only be used as the root operand of a descriptor");
805
    });
806
}
807

808
#[cfg(test)]
809
mod test {
810
    use alloc::string::ToString;
811
    use bitcoin::secp256k1::Secp256k1;
812
    use miniscript::descriptor::{DescriptorPublicKey, KeyMap};
813
    use miniscript::{Descriptor, Legacy, Segwitv0};
814

815
    use core::str::FromStr;
816

817
    use crate::descriptor::{DescriptorError, DescriptorMeta};
818
    use crate::keys::{DescriptorKey, IntoDescriptorKey, ValidNetworks};
819
    use bitcoin::bip32;
820
    use bitcoin::Network::{Bitcoin, Regtest, Signet, Testnet};
821
    use bitcoin::PrivateKey;
822

823
    // test the descriptor!() macro
824

825
    // verify descriptor generates expected script(s) (if bare or pk) or address(es)
826
    fn check(
19✔
827
        desc: Result<(Descriptor<DescriptorPublicKey>, KeyMap, ValidNetworks), DescriptorError>,
19✔
828
        is_witness: bool,
19✔
829
        is_fixed: bool,
19✔
830
        expected: &[&str],
19✔
831
    ) {
19✔
832
        let (desc, _key_map, _networks) = desc.unwrap();
19✔
833
        assert_eq!(desc.is_witness(), is_witness);
19✔
834
        assert_eq!(!desc.has_wildcard(), is_fixed);
19✔
835
        for i in 0..expected.len() {
48✔
836
            let child_desc = desc
48✔
837
                .at_derivation_index(i as u32)
48✔
838
                .expect("i is not hardened");
48✔
839
            let address = child_desc.address(Regtest);
48✔
840
            if let Ok(address) = address {
48✔
841
                assert_eq!(address.to_string(), *expected.get(i).unwrap());
43✔
842
            } else {
843
                let script = child_desc.script_pubkey();
5✔
844
                assert_eq!(script.to_hex_string(), *expected.get(i).unwrap());
5✔
845
            }
846
        }
847
    }
19✔
848

849
    // - at least one of each "type" of operator; i.e. one modifier, one leaf_opcode, one leaf_opcode_value, etc.
850
    // - mixing up key types that implement IntoDescriptorKey in multi() or thresh()
851

852
    // expected script for pk and bare manually created
853
    // expected addresses created with `bitcoin-cli getdescriptorinfo` (for hash) and `bitcoin-cli deriveaddresses`
854

855
    #[test]
856
    fn test_fixed_legacy_descriptors() {
1✔
857
        let pubkey1 = bitcoin::PublicKey::from_str(
1✔
858
            "03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd",
1✔
859
        )
1✔
860
        .unwrap();
1✔
861
        let pubkey2 = bitcoin::PublicKey::from_str(
1✔
862
            "032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af",
1✔
863
        )
1✔
864
        .unwrap();
1✔
865

1✔
866
        check(
1✔
867
            descriptor!(bare(multi(1,pubkey1,pubkey2))),
1✔
868
            false,
1✔
869
            true,
1✔
870
            &["512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd21032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af52ae"],
1✔
871
        );
1✔
872
        check(
1✔
873
            descriptor!(pk(pubkey1)),
1✔
874
            false,
1✔
875
            true,
1✔
876
            &["2103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bdac"],
1✔
877
        );
1✔
878
        check(
1✔
879
            descriptor!(pkh(pubkey1)),
1✔
880
            false,
1✔
881
            true,
1✔
882
            &["muZpTpBYhxmRFuCjLc7C6BBDF32C8XVJUi"],
1✔
883
        );
1✔
884
        check(
1✔
885
            descriptor!(sh(multi(1, pubkey1, pubkey2))),
1✔
886
            false,
1✔
887
            true,
1✔
888
            &["2MymURoV1bzuMnWMGiXzyomDkeuxXY7Suey"],
1✔
889
        );
1✔
890
    }
1✔
891

892
    #[test]
893
    fn test_fixed_segwitv0_descriptors() {
1✔
894
        let pubkey1 = bitcoin::PublicKey::from_str(
1✔
895
            "03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd",
1✔
896
        )
1✔
897
        .unwrap();
1✔
898
        let pubkey2 = bitcoin::PublicKey::from_str(
1✔
899
            "032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af",
1✔
900
        )
1✔
901
        .unwrap();
1✔
902

1✔
903
        check(
1✔
904
            descriptor!(wpkh(pubkey1)),
1✔
905
            true,
1✔
906
            true,
1✔
907
            &["bcrt1qngw83fg8dz0k749cg7k3emc7v98wy0c7azaa6h"],
1✔
908
        );
1✔
909
        check(
1✔
910
            descriptor!(sh(wpkh(pubkey1))),
1✔
911
            true,
1✔
912
            true,
1✔
913
            &["2N5LiC3CqzxDamRTPG1kiNv1FpNJQ7x28sb"],
1✔
914
        );
1✔
915
        check(
1✔
916
            descriptor!(wsh(multi(1, pubkey1, pubkey2))),
1✔
917
            true,
1✔
918
            true,
1✔
919
            &["bcrt1qgw8jvv2hsrvjfa6q66rk6har7d32lrqm5unnf5cl63q9phxfvgps5fyfqe"],
1✔
920
        );
1✔
921
        check(
1✔
922
            descriptor!(sh(wsh(multi(1, pubkey1, pubkey2)))),
1✔
923
            true,
1✔
924
            true,
1✔
925
            &["2NCidRJysy7apkmE6JF5mLLaJFkrN3Ub9iy"],
1✔
926
        );
1✔
927
    }
1✔
928

929
    #[test]
930
    fn test_fixed_threeop_descriptors() {
1✔
931
        let redeem_key = bitcoin::PublicKey::from_str(
1✔
932
            "03a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd",
1✔
933
        )
1✔
934
        .unwrap();
1✔
935
        let move_key = bitcoin::PublicKey::from_str(
1✔
936
            "032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af",
1✔
937
        )
1✔
938
        .unwrap();
1✔
939

1✔
940
        check(
1✔
941
            descriptor!(sh(wsh(and_or(pk(redeem_key), older(1000), pk(move_key))))),
1✔
942
            true,
1✔
943
            true,
1✔
944
            &["2MypGwr5eQWAWWJtiJgUEToVxc4zuokjQRe"],
1✔
945
        );
1✔
946
    }
1✔
947

948
    #[test]
949
    fn test_bip32_legacy_descriptors() {
1✔
950
        let xprv = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
1✔
951

1✔
952
        let path = bip32::DerivationPath::from_str("m/0").unwrap();
1✔
953
        let desc_key = (xprv, path.clone()).into_descriptor_key().unwrap();
1✔
954
        check(
1✔
955
            descriptor!(pk(desc_key)),
1✔
956
            false,
1✔
957
            false,
1✔
958
            &[
1✔
959
                "2102363ad03c10024e1b597a5b01b9982807fb638e00b06f3b2d4a89707de3b93c37ac",
1✔
960
                "2102063a21fd780df370ed2fc8c4b86aa5ea642630609c203009df631feb7b480dd2ac",
1✔
961
                "2102ba2685ad1fa5891cb100f1656b2ce3801822ccb9bac0336734a6f8c1b93ebbc0ac",
1✔
962
            ],
1✔
963
        );
1✔
964

1✔
965
        let desc_key = (xprv, path.clone()).into_descriptor_key().unwrap();
1✔
966
        check(
1✔
967
            descriptor!(pkh(desc_key)),
1✔
968
            false,
1✔
969
            false,
1✔
970
            &[
1✔
971
                "muvBdsVpJxpFuTHMKA47htJPdCvdt4F9DP",
1✔
972
                "mxQSHK7DL2t1DN3xFxov1janCoXSSkrSPj",
1✔
973
                "mfz43r15GiWo4nizmyzMNubsnkDpByFFAn",
1✔
974
            ],
1✔
975
        );
1✔
976

1✔
977
        let path2 = bip32::DerivationPath::from_str("m/2147483647'/0").unwrap();
1✔
978
        let desc_key1 = (xprv, path).into_descriptor_key().unwrap();
1✔
979
        let desc_key2 = (xprv, path2).into_descriptor_key().unwrap();
1✔
980

1✔
981
        check(
1✔
982
            descriptor!(sh(multi(1, desc_key1, desc_key2))),
1✔
983
            false,
1✔
984
            false,
1✔
985
            &[
1✔
986
                "2MtMDXsfwefZkEEhVViEPidvcKRUtJamJJ8",
1✔
987
                "2MwAUZ1NYyWjhVvGTethFL6n7nZhS8WE6At",
1✔
988
                "2MuT6Bj66HLwZd7s4SoD8XbK4GwriKEA6Gr",
1✔
989
            ],
1✔
990
        );
1✔
991
    }
1✔
992

993
    #[test]
994
    fn test_bip32_segwitv0_descriptors() {
1✔
995
        let xprv = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
1✔
996

1✔
997
        let path = bip32::DerivationPath::from_str("m/0").unwrap();
1✔
998
        let desc_key = (xprv, path.clone()).into_descriptor_key().unwrap();
1✔
999
        check(
1✔
1000
            descriptor!(wpkh(desc_key)),
1✔
1001
            true,
1✔
1002
            false,
1✔
1003
            &[
1✔
1004
                "bcrt1qnhm8w9fhc8cxzgqsmqdf9fyjccyvc0gltnymu0",
1✔
1005
                "bcrt1qhylfd55rn75w9fj06zspctad5w4hz33rf0ttad",
1✔
1006
                "bcrt1qq5sq3a6k9av9d8cne0k9wcldy4nqey5yt6889r",
1✔
1007
            ],
1✔
1008
        );
1✔
1009

1✔
1010
        let desc_key = (xprv, path.clone()).into_descriptor_key().unwrap();
1✔
1011
        check(
1✔
1012
            descriptor!(sh(wpkh(desc_key))),
1✔
1013
            true,
1✔
1014
            false,
1✔
1015
            &[
1✔
1016
                "2MxvjQCaLqZ5QxZ7XotZDQ63hZw3NPss763",
1✔
1017
                "2NDUoevN4QMzhvHDMGhKuiT2fN9HXbFRMwn",
1✔
1018
                "2NF4BEAY2jF1Fu8vqfN3NVKoFtom77pUxrx",
1✔
1019
            ],
1✔
1020
        );
1✔
1021

1✔
1022
        let path2 = bip32::DerivationPath::from_str("m/2147483647'/0").unwrap();
1✔
1023
        let desc_key1 = (xprv, path.clone()).into_descriptor_key().unwrap();
1✔
1024
        let desc_key2 = (xprv, path2.clone()).into_descriptor_key().unwrap();
1✔
1025
        check(
1✔
1026
            descriptor!(wsh(multi(1, desc_key1, desc_key2))),
1✔
1027
            true,
1✔
1028
            false,
1✔
1029
            &[
1✔
1030
                "bcrt1qfxv8mxmlv5sz8q2mnuyaqdfe9jr4vvmx0csjhn092p6f4qfygfkq2hng49",
1✔
1031
                "bcrt1qerj85g243e6jlcdxpmn9spk0gefcwvu7nw7ee059d5ydzpdhkm2qwfkf5k",
1✔
1032
                "bcrt1qxkl2qss3k58q9ktc8e89pwr4gnptfpw4hju4xstxcjc0hkcae3jstluty7",
1✔
1033
            ],
1✔
1034
        );
1✔
1035

1✔
1036
        let desc_key1 = (xprv, path).into_descriptor_key().unwrap();
1✔
1037
        let desc_key2 = (xprv, path2).into_descriptor_key().unwrap();
1✔
1038
        check(
1✔
1039
            descriptor!(sh(wsh(multi(1, desc_key1, desc_key2)))),
1✔
1040
            true,
1✔
1041
            false,
1✔
1042
            &[
1✔
1043
                "2NFCtXvx9q4ci2kvKub17iSTgvRXGctCGhz",
1✔
1044
                "2NB2PrFPv5NxWCpygas8tPrGJG2ZFgeuwJw",
1✔
1045
                "2N79ZAGo5cMi5Jt7Wo9L5YmF5GkEw7sjWdC",
1✔
1046
            ],
1✔
1047
        );
1✔
1048
    }
1✔
1049

1050
    #[test]
1051
    fn test_dsl_sortedmulti() {
1✔
1052
        let key_1 = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
1✔
1053
        let path_1 = bip32::DerivationPath::from_str("m/0").unwrap();
1✔
1054

1✔
1055
        let key_2 = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPegBHHnq7YEgM815dG24M2Jk5RVqipgDxF1HJ1tsnT815X5Fd5FRfMVUs8NZs9XCb6y9an8hRPThnhfwfXJ36intaekySHGF").unwrap();
1✔
1056
        let path_2 = bip32::DerivationPath::from_str("m/1").unwrap();
1✔
1057

1✔
1058
        let desc_key1 = (key_1, path_1);
1✔
1059
        let desc_key2 = (key_2, path_2);
1✔
1060

1✔
1061
        check(
1✔
1062
            descriptor!(sh(sortedmulti(1, desc_key1.clone(), desc_key2.clone()))),
1✔
1063
            false,
1✔
1064
            false,
1✔
1065
            &[
1✔
1066
                "2MsxzPEJDBzpGffJXPaDpfXZAUNnZhaMh2N",
1✔
1067
                "2My3x3DLPK3UbGWGpxrXr1RnbD8MNC4FpgS",
1✔
1068
                "2NByEuiQT7YLqHCTNxL5KwYjvtuCYcXNBSC",
1✔
1069
                "2N1TGbP81kj2VUKTSWgrwxoMfuWjvfUdyu7",
1✔
1070
                "2N3Bomq2fpAcLRNfZnD3bCWK9quan28CxCR",
1✔
1071
                "2N9nrZaEzEFDqEAU9RPvDnXGT6AVwBDKAQb",
1✔
1072
            ],
1✔
1073
        );
1✔
1074

1✔
1075
        check(
1✔
1076
            descriptor!(sh(wsh(sortedmulti(
1✔
1077
                1,
1078
                desc_key1.clone(),
1079
                desc_key2.clone()
1080
            )))),
1✔
1081
            true,
1✔
1082
            false,
1✔
1083
            &[
1✔
1084
                "2NCogc5YyM4N6ruv1hUa7WLMW1BPeCK7N9B",
1✔
1085
                "2N6mkSAKi1V2oaBXby7XHdvBMKEDRQcFpNe",
1✔
1086
                "2NFmTSttm9v6bXeoWaBvpMcgfPQcZhNn3Eh",
1✔
1087
                "2Mvib87RBPUHXNEpX5S5Kv1qqrhBfgBGsJM",
1✔
1088
                "2MtMv5mcK2EjcLsH8Txpx2JxLLzHr4ttczL",
1✔
1089
                "2MsWCB56rb4T6yPv8QudZGHERTwNgesE4f6",
1✔
1090
            ],
1✔
1091
        );
1✔
1092

1✔
1093
        check(
1✔
1094
            descriptor!(wsh(sortedmulti_vec(1, vec![desc_key1, desc_key2]))),
1✔
1095
            true,
1✔
1096
            false,
1✔
1097
            &[
1✔
1098
                "bcrt1qcvq0lg8q7a47ytrd7zk5y7uls7mulrenjgvflwylpppgwf8029es4vhpnj",
1✔
1099
                "bcrt1q80yn8sdt6l7pjvkz25lglyaqctlmsq9ugk80rmxt8yu0npdsj97sc7l4de",
1✔
1100
                "bcrt1qrvf6024v9s50qhffe3t2fr2q9ckdhx2g6jz32chm2pp24ymgtr5qfrdmct",
1✔
1101
                "bcrt1q6srfmra0ynypym35c7jvsxt2u4yrugeajq95kg2ps7lk6h2gaunsq9lzxn",
1✔
1102
                "bcrt1qhl8rrzzcdpu7tcup3lcg7tge52sqvwy5fcv4k78v6kxtwmqf3v6qpvyjza",
1✔
1103
                "bcrt1ql2elz9mhm9ll27ddpewhxs732xyl2fk2kpkqz9gdyh33wgcun4vstrd49k",
1✔
1104
            ],
1✔
1105
        );
1✔
1106
    }
1✔
1107

1108
    // - verify the valid_networks returned is correctly computed based on the keys present in the descriptor
1109
    #[test]
1110
    fn test_valid_networks() {
1✔
1111
        let xprv = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
1✔
1112
        let path = bip32::DerivationPath::from_str("m/0").unwrap();
1✔
1113
        let desc_key = (xprv, path).into_descriptor_key().unwrap();
1✔
1114

1✔
1115
        let (_desc, _key_map, valid_networks) = descriptor!(pkh(desc_key)).unwrap();
1✔
1116
        assert_eq!(
1✔
1117
            valid_networks,
1✔
1118
            [Testnet, Regtest, Signet].iter().cloned().collect()
1✔
1119
        );
1✔
1120

1121
        let xprv = bip32::Xpriv::from_str("xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi").unwrap();
1✔
1122
        let path = bip32::DerivationPath::from_str("m/10/20/30/40").unwrap();
1✔
1123
        let desc_key = (xprv, path).into_descriptor_key().unwrap();
1✔
1124

1✔
1125
        let (_desc, _key_map, valid_networks) = descriptor!(wpkh(desc_key)).unwrap();
1✔
1126
        assert_eq!(valid_networks, [Bitcoin].iter().cloned().collect());
1✔
1127
    }
1✔
1128

1129
    // - verify the key_maps are correctly merged together
1130
    #[test]
1131
    fn test_key_maps_merged() {
1✔
1132
        let secp = Secp256k1::new();
1✔
1133

1✔
1134
        let xprv1 = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
1✔
1135
        let path1 = bip32::DerivationPath::from_str("m/0").unwrap();
1✔
1136
        let desc_key1 = (xprv1, path1.clone()).into_descriptor_key().unwrap();
1✔
1137

1✔
1138
        let xprv2 = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPegBHHnq7YEgM815dG24M2Jk5RVqipgDxF1HJ1tsnT815X5Fd5FRfMVUs8NZs9XCb6y9an8hRPThnhfwfXJ36intaekySHGF").unwrap();
1✔
1139
        let path2 = bip32::DerivationPath::from_str("m/2147483647'/0").unwrap();
1✔
1140
        let desc_key2 = (xprv2, path2.clone()).into_descriptor_key().unwrap();
1✔
1141

1✔
1142
        let xprv3 = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPdZXrcHNLf5JAJWFAoJ2TrstMRdSKtEggz6PddbuSkvHKM9oKJyFgZV1B7rw8oChspxyYbtmEXYyg1AjfWbL3ho3XHDpHRZf").unwrap();
1✔
1143
        let path3 = bip32::DerivationPath::from_str("m/10/20/30/40").unwrap();
1✔
1144
        let desc_key3 = (xprv3, path3.clone()).into_descriptor_key().unwrap();
1✔
1145

1✔
1146
        let (_desc, key_map, _valid_networks) =
1✔
1147
            descriptor!(sh(wsh(multi(2, desc_key1, desc_key2, desc_key3)))).unwrap();
1✔
1148
        assert_eq!(key_map.len(), 3);
1✔
1149

1150
        let desc_key1: DescriptorKey<Segwitv0> = (xprv1, path1).into_descriptor_key().unwrap();
1✔
1151
        let desc_key2: DescriptorKey<Segwitv0> = (xprv2, path2).into_descriptor_key().unwrap();
1✔
1152
        let desc_key3: DescriptorKey<Segwitv0> = (xprv3, path3).into_descriptor_key().unwrap();
1✔
1153

1✔
1154
        let (key1, _key_map, _valid_networks) = desc_key1.extract(&secp).unwrap();
1✔
1155
        let (key2, _key_map, _valid_networks) = desc_key2.extract(&secp).unwrap();
1✔
1156
        let (key3, _key_map, _valid_networks) = desc_key3.extract(&secp).unwrap();
1✔
1157
        assert_eq!(key_map.get(&key1).unwrap().to_string(), "tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy/0/*");
1✔
1158
        assert_eq!(key_map.get(&key2).unwrap().to_string(), "tprv8ZgxMBicQKsPegBHHnq7YEgM815dG24M2Jk5RVqipgDxF1HJ1tsnT815X5Fd5FRfMVUs8NZs9XCb6y9an8hRPThnhfwfXJ36intaekySHGF/2147483647'/0/*");
1✔
1159
        assert_eq!(key_map.get(&key3).unwrap().to_string(), "tprv8ZgxMBicQKsPdZXrcHNLf5JAJWFAoJ2TrstMRdSKtEggz6PddbuSkvHKM9oKJyFgZV1B7rw8oChspxyYbtmEXYyg1AjfWbL3ho3XHDpHRZf/10/20/30/40/*");
1✔
1160
    }
1✔
1161

1162
    // - verify the ScriptContext is correctly validated (i.e. passing a type that only impl IntoDescriptorKey<Segwitv0> to a pkh() descriptor should throw a compilation error
1163
    #[test]
1164
    fn test_script_context_validation() {
1✔
1165
        // this compiles
1✔
1166
        let xprv = bip32::Xpriv::from_str("tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy").unwrap();
1✔
1167
        let path = bip32::DerivationPath::from_str("m/0").unwrap();
1✔
1168
        let desc_key: DescriptorKey<Legacy> = (xprv, path).into_descriptor_key().unwrap();
1✔
1169

1✔
1170
        let (desc, _key_map, _valid_networks) = descriptor!(pkh(desc_key)).unwrap();
1✔
1171
        assert_eq!(desc.to_string(), "pkh(tpubD6NzVbkrYhZ4WR7a4vY1VT3khMJMeAxVsfq9TBJyJWrNk247zCJtV7AWf6UJP7rAVsn8NNKdJi3gFyKPTmWZS9iukb91xbn2HbFSMQm2igY/0/*)#yrnz9pp2");
1✔
1172

1173
        // as expected this does not compile due to invalid context
1174
        //let desc_key:DescriptorKey<Segwitv0> = (xprv, path.clone()).into_descriptor_key().unwrap();
1175
        //let (desc, _key_map, _valid_networks) = descriptor!(pkh(desc_key)).unwrap();
1176
    }
1✔
1177

1178
    #[test]
1179
    fn test_dsl_modifiers() {
1✔
1180
        let private_key =
1✔
1181
            PrivateKey::from_wif("cSQPHDBwXGjVzWRqAHm6zfvQhaTuj1f2bFH58h55ghbjtFwvmeXR").unwrap();
1✔
1182
        let (descriptor, _, _) =
1✔
1183
            descriptor!(wsh(thresh(2,n:d:v:older(1),s:pk(private_key),s:pk(private_key)))).unwrap();
1✔
1184

1✔
1185
        assert_eq!(descriptor.to_string(), "wsh(thresh(2,ndv:older(1),s:pk(02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c),s:pk(02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c)))#zzk3ux8g")
1✔
1186
    }
1✔
1187

1188
    #[test]
1189
    #[should_panic(expected = "Miniscript(ContextError(UncompressedKeysNotAllowed))")]
1190
    fn test_dsl_miniscript_checks() {
1✔
1191
        let mut uncompressed_pk =
1✔
1192
            PrivateKey::from_wif("L5EZftvrYaSudiozVRzTqLcHLNDoVn7H5HSfM9BAN6tMJX8oTWz6").unwrap();
1✔
1193
        uncompressed_pk.compressed = false;
1✔
1194

1195
        descriptor!(wsh(v: pk(uncompressed_pk))).unwrap();
1✔
1196
    }
1✔
1197

1198
    #[test]
1199
    fn test_dsl_tr_only_key() {
1✔
1200
        let private_key =
1✔
1201
            PrivateKey::from_wif("cSQPHDBwXGjVzWRqAHm6zfvQhaTuj1f2bFH58h55ghbjtFwvmeXR").unwrap();
1✔
1202
        let (descriptor, _, _) = descriptor!(tr(private_key)).unwrap();
1✔
1203

1✔
1204
        assert_eq!(
1✔
1205
            descriptor.to_string(),
1✔
1206
            "tr(02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c)#heq9m95v"
1✔
1207
        )
1✔
1208
    }
1✔
1209

1210
    #[test]
1211
    fn test_dsl_tr_simple_tree() {
1✔
1212
        let private_key =
1✔
1213
            PrivateKey::from_wif("cSQPHDBwXGjVzWRqAHm6zfvQhaTuj1f2bFH58h55ghbjtFwvmeXR").unwrap();
1✔
1214
        let (descriptor, _, _) =
1✔
1215
            descriptor!(tr(private_key, { pk(private_key), pk(private_key) })).unwrap();
1✔
1216

1✔
1217
        assert_eq!(descriptor.to_string(), "tr(02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c,{pk(02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c),pk(02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c)})#xy5fjw6d")
1✔
1218
    }
1✔
1219

1220
    #[test]
1221
    fn test_dsl_tr_single_leaf() {
1✔
1222
        let private_key =
1✔
1223
            PrivateKey::from_wif("cSQPHDBwXGjVzWRqAHm6zfvQhaTuj1f2bFH58h55ghbjtFwvmeXR").unwrap();
1✔
1224
        let (descriptor, _, _) = descriptor!(tr(private_key, pk(private_key))).unwrap();
1✔
1225

1✔
1226
        assert_eq!(descriptor.to_string(), "tr(02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c,pk(02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c))#lzl2vmc7")
1✔
1227
    }
1✔
1228
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc