]> Untitled Git - bdk/commitdiff
[descriptor] Make the syntax of `descriptor!()` more consistent
authorAlekos Filini <alekos.filini@gmail.com>
Wed, 16 Dec 2020 15:10:22 +0000 (16:10 +0100)
committerAlekos Filini <alekos.filini@gmail.com>
Wed, 16 Dec 2020 18:00:55 +0000 (19:00 +0100)
The syntax now is pretty much the same as the normal descriptor syntax,
with the only difference that modifiers cannot be grouped together (i.e.
`sdv:older(144)` must be turned into `s:d:v:older(144)`.

src/descriptor/dsl.rs
src/descriptor/mod.rs
src/descriptor/policy.rs
src/wallet/signer.rs

index e75e1b58ce2cc4c4fef1c609792c8856a00775b7..71f099e5e381e98d111a72d7f54dd95bcac76f7b 100644 (file)
 macro_rules! impl_top_level_sh {
     // disallow `sortedmulti` in `bare()`
     ( Bare, Bare, sortedmulti $( $inner:tt )* ) => {
-        compile_error!("`bare()` descriptors can't contain any `sortedmulti` operands");
+        compile_error!("`bare()` descriptors can't contain any `sortedmulti()` operands");
     };
     ( Bare, Bare, sortedmulti_vec $( $inner:tt )* ) => {
-        compile_error!("`bare()` descriptors can't contain any `sortedmulti_vec` operands");
+        compile_error!("`bare()` descriptors can't contain any `sortedmulti_vec()` operands");
     };
 
     ( $descriptor_variant:ident, $sortedmulti_variant:ident, sortedmulti $( $inner:tt )* ) => {
@@ -72,16 +72,6 @@ macro_rules! impl_top_level_pk {
     }};
 }
 
-#[doc(hidden)]
-#[macro_export]
-macro_rules! impl_modifier {
-    ( $terminal_variant:ident, $( $inner:tt )* ) => {
-        $crate::fragment!($( $inner )*)
-            .map_err(|e| -> $crate::Error { e.into() })
-            .and_then(|(minisc, keymap, networks)| Ok(($crate::miniscript::Miniscript::from_ast($crate::miniscript::miniscript::decode::Terminal::$terminal_variant(std::sync::Arc::new(minisc)))?, keymap, networks)))
-    };
-}
-
 #[doc(hidden)]
 #[macro_export]
 macro_rules! impl_leaf_opcode {
@@ -139,9 +129,12 @@ macro_rules! impl_leaf_opcode_value_two {
 #[doc(hidden)]
 #[macro_export]
 macro_rules! impl_node_opcode_two {
-    ( $terminal_variant:ident, ( $( $a:tt )* ), ( $( $b:tt )* ) ) => {
-        $crate::fragment!($( $a )*)
-            .and_then(|a| Ok((a, $crate::fragment!($( $b )*)?)))
+    ( $terminal_variant:ident, $( $inner:tt )* ) => ({
+        let inner = $crate::fragment_internal!( @t $( $inner )* );
+        let (a, b) = $crate::descriptor::dsl::TupleTwo::from(inner).flattened();
+
+        a
+            .and_then(|a| Ok((a, b?)))
             .and_then(|((a_minisc, mut a_keymap, a_networks), (b_minisc, b_keymap, b_networks))| {
                 // join key_maps
                 a_keymap.extend(b_keymap.into_iter());
@@ -151,15 +144,18 @@ macro_rules! impl_node_opcode_two {
                     std::sync::Arc::new(b_minisc),
                 ))?, a_keymap, $crate::keys::merge_networks(&a_networks, &b_networks)))
             })
-    };
+    });
 }
 
 #[doc(hidden)]
 #[macro_export]
 macro_rules! impl_node_opcode_three {
-    ( $terminal_variant:ident, ( $( $a:tt )* ), ( $( $b:tt )* ), ( $( $c:tt )* ) ) => {
-        $crate::fragment!($( $a )*)
-            .and_then(|a| Ok((a, $crate::fragment!($( $b )*)?, $crate::fragment!($( $c )*)?)))
+    ( $terminal_variant:ident, $( $inner:tt )* ) => {
+        let inner = $crate::fragment_internal!( @t $( $inner )* );
+        let (a, b, c) = $crate::descriptor::dsl::TupleThree::from(inner).flattened();
+
+        a
+            .and_then(|a| Ok((a, b?, c?)))
             .and_then(|((a_minisc, mut a_keymap, a_networks), (b_minisc, b_keymap, b_networks), (c_minisc, c_keymap, c_networks))| {
                 // join key_maps
                 a_keymap.extend(b_keymap.into_iter());
@@ -180,11 +176,11 @@ macro_rules! impl_node_opcode_three {
 #[doc(hidden)]
 #[macro_export]
 macro_rules! impl_sortedmulti {
-    ( sortedmulti_vec $thresh:expr, $keys:expr ) => ({
+    ( sortedmulti_vec ( $thresh:expr, $keys:expr ) ) => ({
         let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
         $crate::keys::make_sortedmulti_inner($thresh, $keys, &secp)
     });
-    ( sortedmulti $thresh:expr $(, $key:expr )+ ) => ({
+    ( sortedmulti ( $thresh:expr $(, $key:expr )+ ) ) => ({
         use $crate::keys::ToDescriptorKey;
         let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
 
@@ -199,11 +195,89 @@ macro_rules! impl_sortedmulti {
 
 }
 
+#[doc(hidden)]
+#[macro_export]
+macro_rules! apply_modifier {
+    ( $terminal_variant:ident, $inner:expr ) => {{
+        $inner
+            .map_err(|e| -> $crate::Error { e.into() })
+            .and_then(|(minisc, keymap, networks)| {
+                Ok((
+                    $crate::miniscript::Miniscript::from_ast(
+                        $crate::miniscript::miniscript::decode::Terminal::$terminal_variant(
+                            std::sync::Arc::new(minisc),
+                        ),
+                    )?,
+                    keymap,
+                    networks,
+                ))
+            })
+    }};
+
+    ( a: $inner:expr ) => {{
+        $crate::apply_modifier!(Alt, $inner)
+    }};
+    ( s: $inner:expr ) => {{
+        $crate::apply_modifier!(Swap, $inner)
+    }};
+    ( c: $inner:expr ) => {{
+        $crate::apply_modifier!(Check, $inner)
+    }};
+    ( d: $inner:expr ) => {{
+        $crate::apply_modifier!(DupIf, $inner)
+    }};
+    ( v: $inner:expr ) => {{
+        $crate::apply_modifier!(Verify, $inner)
+    }};
+    ( j: $inner:expr ) => {{
+        $crate::apply_modifier!(NonZero, $inner)
+    }};
+    ( n: $inner:expr ) => {{
+        $crate::apply_modifier!(ZeroNotEqual, $inner)
+    }};
+
+    // Modifiers expanded to other operators
+    ( t: $inner:expr ) => {{
+        $inner.and_then(|(a_minisc, a_keymap, a_networks)| {
+            $crate::impl_leaf_opcode_value_two!(
+                AndV,
+                std::sync::Arc::new(a_minisc),
+                std::sync::Arc::new($crate::fragment!(true).unwrap().0)
+            )
+            .map(|(minisc, _, _)| (minisc, a_keymap, a_networks))
+        })
+    }};
+    ( l: $inner:expr ) => {{
+        $inner.and_then(|(a_minisc, a_keymap, a_networks)| {
+            $crate::impl_leaf_opcode_value_two!(
+                OrI,
+                std::sync::Arc::new($crate::fragment!(false).unwrap().0),
+                std::sync::Arc::new(a_minisc)
+            )
+            .map(|(minisc, _, _)| (minisc, a_keymap, a_networks))
+        })
+    }};
+    ( u: $inner:expr ) => {{
+        $inner.and_then(|(a_minisc, a_keymap, a_networks)| {
+            $crate::impl_leaf_opcode_value_two!(
+                OrI,
+                std::sync::Arc::new(a_minisc),
+                std::sync::Arc::new($crate::fragment!(false).unwrap().0)
+            )
+            .map(|(minisc, _, _)| (minisc, a_keymap, a_networks))
+        })
+    }};
+}
+
 /// Macro to write full descriptors with code
 ///
 /// This macro expands to a `Result` of
 /// [`DescriptorTemplateOut`](super::template::DescriptorTemplateOut) and [`Error`](crate::Error)
 ///
+/// The syntax is very similar to the normal descriptor syntax, with the exception that modifiers
+/// cannot be grouped together. For instance, a descriptor fragment like `sdv:older(144)` has to be
+/// broken up to `s:d:v:older(144)`.
+///
 /// ## Example
 ///
 /// Signature plus timelock, equivalent to: `sh(wsh(and_v(v:pk(...), older(...))))`
@@ -212,7 +286,7 @@ macro_rules! impl_sortedmulti {
 /// # use std::str::FromStr;
 /// let my_key = bitcoin::PublicKey::from_str("02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c")?;
 /// let my_timelock = 50;
-/// let (my_descriptor, my_keys_map, networks) = bdk::descriptor!(sh ( wsh ( and_v (+v pk my_key), ( older my_timelock ))))?;
+/// let (my_descriptor, my_keys_map, networks) = bdk::descriptor!(sh(wsh(and_v(v:pk(my_key),older(my_timelock)))))?;
 /// # Ok::<(), Box<dyn std::error::Error>>(())
 /// ```
 ///
@@ -232,16 +306,16 @@ macro_rules! impl_sortedmulti {
 ///
 /// let (descriptor_a, key_map_a, networks) = bdk::descriptor! {
 ///     wsh (
-///         thresh 2, (pk my_key_1), (+s pk my_key_2), (+s+d+v older my_timelock)
+///         thresh(2, pk(my_key_1), s:pk(my_key_2), s:d:v:older(my_timelock))
 ///     )
 /// }?;
 ///
 /// let b_items = vec![
-///     bdk::fragment!(pk my_key_1)?,
-///     bdk::fragment!(+s pk my_key_2)?,
-///     bdk::fragment!(+s+d+v older my_timelock)?,
+///     bdk::fragment!(pk(my_key_1))?,
+///     bdk::fragment!(s:pk(my_key_2))?,
+///     bdk::fragment!(s:d:v:older(my_timelock))?,
 /// ];
-/// let (descriptor_b, mut key_map_b, networks) = bdk::descriptor!( wsh ( thresh_vec 2, b_items ) )?;
+/// let (descriptor_b, mut key_map_b, networks) = bdk::descriptor!(wsh(thresh_vec(2,b_items)))?;
 ///
 /// assert_eq!(descriptor_a, descriptor_b);
 /// assert_eq!(key_map_a.len(), key_map_b.len());
@@ -259,7 +333,7 @@ macro_rules! impl_sortedmulti {
 ///
 /// let (descriptor, key_map, networks) = bdk::descriptor! {
 ///     wsh (
-///         multi 2, my_key_1, my_key_2
+///         multi(2, my_key_1, my_key_2)
 ///     )
 /// }?;
 /// # Ok::<(), Box<dyn std::error::Error>>(())
@@ -286,13 +360,13 @@ macro_rules! descriptor {
     ( shwsh ( $( $minisc:tt )* ) ) => ({
         $crate::impl_top_level_sh!(ShWsh, ShWshSortedMulti, $( $minisc )*)
     });
-    ( pk $key:expr ) => ({
+    ( pk ( $key:expr ) ) => ({
         $crate::impl_top_level_pk!(Pk, $crate::miniscript::Legacy, $key)
     });
-    ( pkh $key:expr ) => ({
+    ( pkh ( $key:expr ) ) => ({
         $crate::impl_top_level_pk!(Pkh,$crate::miniscript::Legacy, $key)
     });
-    ( wpkh $key:expr ) => ({
+    ( wpkh ( $key:expr ) ) => ({
         $crate::impl_top_level_pk!(Wpkh, $crate::miniscript::Segwitv0, $key)
     });
     ( sh ( wpkh ( $key:expr ) ) ) => ({
@@ -309,42 +383,120 @@ macro_rules! descriptor {
     });
 }
 
-/// Macro to write descriptor fragments with code
-///
-/// This macro will be expanded to an object of type `Result<(Miniscript<DescriptorPublicKey, _>, KeyMap, ValidNetworks), Error>`. It allows writing
-/// fragments of larger descriptors that can be pieced together using `fragment!(thresh_vec ...)`.
+#[doc(hidden)]
+pub struct TupleTwo<A, B> {
+    pub a: A,
+    pub b: B,
+}
+
+impl<A, B> TupleTwo<A, B> {
+    pub fn flattened(self) -> (A, B) {
+        (self.a, self.b)
+    }
+}
+
+impl<A, B> From<(A, (B, ()))> for TupleTwo<A, B> {
+    fn from((a, (b, _)): (A, (B, ()))) -> Self {
+        TupleTwo { a, b }
+    }
+}
+
+#[doc(hidden)]
+pub struct TupleThree<A, B, C> {
+    pub a: A,
+    pub b: B,
+    pub c: C,
+}
+
+impl<A, B, C> TupleThree<A, B, C> {
+    pub fn flattened(self) -> (A, B, C) {
+        (self.a, self.b, self.c)
+    }
+}
+
+impl<A, B, C> From<(A, (B, (C, ())))> for TupleThree<A, B, C> {
+    fn from((a, (b, (c, _))): (A, (B, (C, ())))) -> Self {
+        TupleThree { a, b, c }
+    }
+}
+
+#[doc(hidden)]
 #[macro_export]
-macro_rules! fragment {
-    // Modifiers
-    ( +a $( $inner:tt )* ) => ({
-        $crate::impl_modifier!(Alt, $( $inner )*)
+macro_rules! fragment_internal {
+    // The @v prefix is used to parse a sequence of operands and return them in a vector. This is
+    // used by operands that take a variable number of arguments, like `thresh()` and `multi()`.
+    ( @v $op:ident ( $( $args:tt )* ) $( $tail:tt )* ) => ({
+        let mut v = vec![$crate::fragment!( $op ( $( $args )* ) )];
+        v.append(&mut $crate::fragment_internal!( @v $( $tail )* ));
+
+        v
     });
-    ( +s $( $inner:tt )* ) => ({
-        $crate::impl_modifier!(Swap, $( $inner )*)
+    // Match modifiers
+    ( @v $modif:tt : $( $tail:tt )* ) => ({
+        let mut v = $crate::fragment_internal!( @v $( $tail )* );
+        let first = v.drain(..1).next().unwrap();
+
+        let first = $crate::apply_modifier!($modif:first);
+
+        let mut v_final = vec![first];
+        v_final.append(&mut v);
+
+        v_final
     });
-    ( +c $( $inner:tt )* ) => ({
-        $crate::impl_modifier!(Check, $( $inner )*)
+    // Remove commas between operands
+    ( @v , $( $tail:tt )* ) => ({
+        $crate::fragment_internal!( @v $( $tail )* )
     });
-    ( +d $( $inner:tt )* ) => ({
-        $crate::impl_modifier!(DupIf, $( $inner )*)
+    ( @v ) => ({
+        vec![]
     });
-    ( +v $( $inner:tt )* ) => ({
-        $crate::impl_modifier!(Verify, $( $inner )*)
+
+    // The @t prefix is used to parse a sequence of operands and return them in a tuple. This
+    // allows checking at compile-time the number of arguments passed to an operand. For this
+    // reason it's used by `and_*()`, `or_*()`, etc.
+    //
+    // Unfortunately, due to the fact that concatenating tuples is pretty hard, the final result
+    // adds in the first spot the parsed operand and in the second spot the result of parsing
+    // all the following ones. For two operands the type then corresponds to: (X, (X, ())). For
+    // three operands it's (X, (X, (X, ()))), etc.
+    //
+    // To check that the right number of arguments has been passed we can "cast" those tuples to
+    // more convenient structures like `TupleTwo`. If the conversion succedes, the right number of
+    // args was passed. Otherwise the compilation fails entirely.
+    ( @t $op:ident ( $( $args:tt )* ) $( $tail:tt )* ) => ({
+        ($crate::fragment!( $op ( $( $args )* ) ), $crate::fragment_internal!( @t $( $tail )* ))
     });
-    ( +j $( $inner:tt )* ) => ({
-        $crate::impl_modifier!(NonZero, $( $inner )*)
+    // Match modifiers
+    ( @t $modif:tt : $( $tail:tt )* ) => ({
+        let (first, tail) = $crate::fragment_internal!( @t $( $tail )* );
+        ($crate::apply_modifier!($modif:first), tail)
     });
-    ( +n $( $inner:tt )* ) => ({
-        $crate::impl_modifier!(ZeroNotEqual, $( $inner )*)
+    // Remove commas between operands
+    ( @t , $( $tail:tt )* ) => ({
+        $crate::fragment_internal!( @t $( $tail )* )
     });
-    ( +t $( $inner:tt )* ) => ({
-        $crate::fragment!(and_v ( $( $inner )* ), ( true ) )
+    ( @t ) => ({
+        ()
     });
-    ( +l $( $inner:tt )* ) => ({
-        $crate::fragment!(or_i ( false ), ( $( $inner )* ) )
+
+    // Fallback to calling `fragment!()`
+    ( $( $tokens:tt )* ) => ({
+        $crate::fragment!($( $tokens )*)
     });
-    ( +u $( $inner:tt )* ) => ({
-        $crate::fragment!(or_i ( $( $inner )* ), ( false ) )
+}
+
+/// Macro to write descriptor fragments with code
+///
+/// This macro will be expanded to an object of type `Result<(Miniscript<DescriptorPublicKey, _>, KeyMap, ValidNetworks), Error>`. It allows writing
+/// fragments of larger descriptors that can be pieced together using `fragment!(thresh_vec(m, ...))`.
+///
+/// The syntax to write macro fragment is the same as documented for the [`descriptor`] macro.
+#[macro_export]
+macro_rules! fragment {
+    // Modifiers
+    ( $modif:tt : $( $tail:tt )* ) => ({
+        let op = $crate::fragment!( $( $tail )* );
+        $crate::apply_modifier!($modif:op)
     });
 
     // Miniscript
@@ -354,56 +506,56 @@ macro_rules! fragment {
     ( false ) => ({
         $crate::impl_leaf_opcode!(False)
     });
-    ( pk_k $key:expr ) => ({
+    ( pk_k ( $key:expr ) ) => ({
         let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
         $crate::keys::make_pk($key, &secp)
     });
-    ( pk $key:expr ) => ({
-        $crate::fragment!(+c pk_k $key)
+    ( pk ( $key:expr ) ) => ({
+        $crate::fragment!(c:pk_k ( $key ))
     });
-    ( pk_h $key_hash:expr ) => ({
+    ( pk_h ( $key_hash:expr ) ) => ({
         $crate::impl_leaf_opcode_value!(PkH, $key_hash)
     });
-    ( after $value:expr ) => ({
+    ( after ( $value:expr ) ) => ({
         $crate::impl_leaf_opcode_value!(After, $value)
     });
-    ( older $value:expr ) => ({
+    ( older ( $value:expr ) ) => ({
         $crate::impl_leaf_opcode_value!(Older, $value)
     });
-    ( sha256 $hash:expr ) => ({
+    ( sha256 ( $hash:expr ) ) => ({
         $crate::impl_leaf_opcode_value!(Sha256, $hash)
     });
-    ( hash256 $hash:expr ) => ({
+    ( hash256 ( $hash:expr ) ) => ({
         $crate::impl_leaf_opcode_value!(Hash256, $hash)
     });
-    ( ripemd160 $hash:expr ) => ({
+    ( ripemd160 ( $hash:expr ) ) => ({
         $crate::impl_leaf_opcode_value!(Ripemd160, $hash)
     });
-    ( hash160 $hash:expr ) => ({
+    ( hash160 ( $hash:expr ) ) => ({
         $crate::impl_leaf_opcode_value!(Hash160, $hash)
     });
-    ( and_v ( $( $a:tt )* ), ( $( $b:tt )* ) ) => ({
-        $crate::impl_node_opcode_two!(AndV, ( $( $a )* ), ( $( $b )* ))
+    ( and_v ( $( $inner:tt )* ) ) => ({
+        $crate::impl_node_opcode_two!(AndV, $( $inner )*)
     });
-    ( and_b ( $( $a:tt )* ), ( $( $b:tt )* ) ) => ({
-        $crate::impl_node_opcode_two!(AndB, ( $( $a )* ), ( $( $b )* ))
+    ( and_b ( $( $inner:tt )* ) ) => ({
+        $crate::impl_node_opcode_two!(AndB, $( $inner )*)
     });
-    ( and_or ( $( $a:tt )* ), ( $( $b:tt )* ), ( $( $c:tt )* ) ) => ({
-        $crate::impl_node_opcode_three!(AndOr, ( $( $a )* ), ( $( $b )* ), ( $( $c )* ))
+    ( and_or ( $( $inner:tt )* ) ) => ({
+        $crate::impl_node_opcode_three!(AndOr, $( $inner )*)
     });
-    ( or_b ( $( $a:tt )* ), ( $( $b:tt )* ) ) => ({
-        $crate::impl_node_opcode_two!(OrB, ( $( $a )* ), ( $( $b )* ))
+    ( or_b ( $( $inner:tt )* ) ) => ({
+        $crate::impl_node_opcode_two!(OrB, $( $inner )*)
     });
-    ( or_d ( $( $a:tt )* ), ( $( $b:tt )* ) ) => ({
-        $crate::impl_node_opcode_two!(OrD, ( $( $a )* ), ( $( $b )* ))
+    ( or_d ( $( $inner:tt )* ) ) => ({
+        $crate::impl_node_opcode_two!(OrD, $( $inner )*)
     });
-    ( or_c ( $( $a:tt )* ), ( $( $b:tt )* ) ) => ({
-        $crate::impl_node_opcode_two!(OrC, ( $( $a )* ), ( $( $b )* ))
+    ( or_c ( $( $inner:tt )* ) ) => ({
+        $crate::impl_node_opcode_two!(OrC, $( $inner )*)
     });
-    ( or_i ( $( $a:tt )* ), ( $( $b:tt )* ) ) => ({
-        $crate::impl_node_opcode_two!(OrI, ( $( $a )* ), ( $( $b )* ))
+    ( or_i ( $( $inner:tt )* ) ) => ({
+        $crate::impl_node_opcode_two!(OrI, $( $inner )*)
     });
-    ( thresh_vec $thresh:expr, $items:expr ) => ({
+    ( thresh_vec ( $thresh:expr, $items:expr ) ) => ({
         use $crate::miniscript::descriptor::KeyMap;
 
         let (items, key_maps_networks): (Vec<_>, Vec<_>) = $items.into_iter().map(|(a, b, c)| (a, (b, c))).unzip();
@@ -419,19 +571,16 @@ macro_rules! fragment {
         $crate::impl_leaf_opcode_value_two!(Thresh, $thresh, items)
             .map(|(minisc, _, _)| (minisc, key_maps, valid_networks))
     });
-    ( thresh $thresh:expr $(, ( $( $item:tt )* ) )+ ) => ({
-        let mut items = vec![];
-        $(
-            items.push($crate::fragment!($( $item )*));
-        )*
+    ( thresh ( $thresh:expr, $( $inner:tt )* ) ) => ({
+        let items = $crate::fragment_internal!( @v $( $inner )* );
 
         items.into_iter().collect::<Result<Vec<_>, _>>()
-            .and_then(|items| $crate::fragment!(thresh_vec $thresh, items))
+            .and_then(|items| $crate::fragment!(thresh_vec($thresh, items)))
     });
-    ( multi_vec $thresh:expr, $keys:expr ) => ({
+    ( multi_vec ( $thresh:expr, $keys:expr ) ) => ({
         $crate::keys::make_multi($thresh, $keys)
     });
-    ( multi $thresh:expr $(, $key:expr )+ ) => ({
+    ( multi ( $thresh:expr $(, $key:expr )+ ) ) => ({
         use $crate::keys::ToDescriptorKey;
         let secp = $crate::bitcoin::secp256k1::Secp256k1::new();
 
@@ -445,10 +594,10 @@ macro_rules! fragment {
     });
 
     // `sortedmulti()` is handled separately
-    ( sortedmulti $( $inner:tt )* ) => ({
+    ( sortedmulti ( $( $inner:tt )* ) ) => ({
         compile_error!("`sortedmulti` can only be used as the root operand of a descriptor");
     });
-    ( sortedmulti_vec $( $inner:tt )* ) => ({
+    ( sortedmulti_vec ( $( $inner:tt )* ) ) => ({
         compile_error!("`sortedmulti_vec` can only be used as the root operand of a descriptor");
     });
 }
@@ -467,6 +616,7 @@ mod test {
     use bitcoin::network::constants::Network::{Bitcoin, Regtest, Testnet};
     use bitcoin::util::bip32;
     use bitcoin::util::bip32::ChildNumber;
+    use bitcoin::PrivateKey;
 
     // test the descriptor!() macro
 
@@ -518,7 +668,7 @@ mod test {
         .unwrap();
 
         check(
-            descriptor!(bare(multi 1,pubkey1,pubkey2)),
+            descriptor!(bare(multi(1,pubkey1,pubkey2))),
             false,
             true,
             &["512103a34b99f22c790c4e36b2b3c2c35a36db06226e41c692fc82b8b56ac1c540c5bd21032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af52ae"],
@@ -536,7 +686,7 @@ mod test {
             &["muZpTpBYhxmRFuCjLc7C6BBDF32C8XVJUi"],
         );
         check(
-            descriptor!(sh(multi 1,pubkey1,pubkey2)),
+            descriptor!(sh(multi(1, pubkey1, pubkey2))),
             false,
             true,
             &["2MymURoV1bzuMnWMGiXzyomDkeuxXY7Suey"],
@@ -567,13 +717,13 @@ mod test {
             &["2N5LiC3CqzxDamRTPG1kiNv1FpNJQ7x28sb"],
         );
         check(
-            descriptor!(wsh(multi 1,pubkey1,pubkey2)),
+            descriptor!(wsh(multi(1, pubkey1, pubkey2))),
             true,
             true,
             &["bcrt1qgw8jvv2hsrvjfa6q66rk6har7d32lrqm5unnf5cl63q9phxfvgps5fyfqe"],
         );
         check(
-            descriptor!(sh(wsh(multi 1,pubkey1,pubkey2))),
+            descriptor!(sh(wsh(multi(1, pubkey1, pubkey2)))),
             true,
             true,
             &["2NCidRJysy7apkmE6JF5mLLaJFkrN3Ub9iy"],
@@ -614,7 +764,7 @@ mod test {
         let desc_key2 = (xprv, path2).to_descriptor_key().unwrap();
 
         check(
-            descriptor!(sh(multi 1,desc_key1,desc_key2)),
+            descriptor!(sh(multi(1, desc_key1, desc_key2))),
             false,
             false,
             &[
@@ -658,7 +808,7 @@ mod test {
         let desc_key1 = (xprv, path.clone()).to_descriptor_key().unwrap();
         let desc_key2 = (xprv, path2.clone()).to_descriptor_key().unwrap();
         check(
-            descriptor!(wsh(multi 1,desc_key1,desc_key2)),
+            descriptor!(wsh(multi(1, desc_key1, desc_key2))),
             true,
             false,
             &[
@@ -671,7 +821,7 @@ mod test {
         let desc_key1 = (xprv, path).to_descriptor_key().unwrap();
         let desc_key2 = (xprv, path2).to_descriptor_key().unwrap();
         check(
-            descriptor!(sh(wsh(multi 1,desc_key1,desc_key2))),
+            descriptor!(sh(wsh(multi(1, desc_key1, desc_key2)))),
             true,
             false,
             &[
@@ -694,7 +844,7 @@ mod test {
         let desc_key2 = (key_2, path_2);
 
         check(
-            descriptor!(sh(sortedmulti 1, desc_key1.clone(), desc_key2.clone())),
+            descriptor!(sh(sortedmulti(1, desc_key1.clone(), desc_key2.clone()))),
             false,
             false,
             &[
@@ -708,7 +858,11 @@ mod test {
         );
 
         check(
-            descriptor!(sh(wsh(sortedmulti 1, desc_key1.clone(), desc_key2.clone()))),
+            descriptor!(sh(wsh(sortedmulti(
+                1,
+                desc_key1.clone(),
+                desc_key2.clone()
+            )))),
             true,
             false,
             &[
@@ -722,7 +876,7 @@ mod test {
         );
 
         check(
-            descriptor!(wsh(sortedmulti_vec 1, vec![desc_key1, desc_key2])),
+            descriptor!(wsh(sortedmulti_vec(1, vec![desc_key1, desc_key2]))),
             true,
             false,
             &[
@@ -772,7 +926,7 @@ mod test {
         let desc_key3 = (xprv3, path3.clone()).to_descriptor_key().unwrap();
 
         let (_desc, key_map, _valid_networks) =
-            descriptor!(sh(wsh(multi 2,desc_key1,desc_key2,desc_key3))).unwrap();
+            descriptor!(sh(wsh(multi(2, desc_key1, desc_key2, desc_key3)))).unwrap();
         assert_eq!(key_map.len(), 3);
 
         let desc_key1: DescriptorKey<Segwitv0> =
@@ -805,4 +959,14 @@ mod test {
         //let desc_key:DescriptorKey<Segwitv0> = (xprv, path.clone()).to_descriptor_key().unwrap();
         //let (desc, _key_map, _valid_networks) = descriptor!(pkh(desc_key)).unwrap();
     }
+
+    #[test]
+    fn test_dsl_modifiers() {
+        let private_key =
+            PrivateKey::from_wif("cSQPHDBwXGjVzWRqAHm6zfvQhaTuj1f2bFH58h55ghbjtFwvmeXR").unwrap();
+        let (descriptor, _, _) =
+            descriptor!(wsh(thresh(2,d:v:older(1),s:pk(private_key),s:pk(private_key)))).unwrap();
+
+        assert_eq!(descriptor.to_string(), "wsh(thresh(2,dv:older(1),s:pk(02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c),s:pk(02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c)))")
+    }
 }
index 83870135b786765426021f058b971bc15755c4f0..97c22839897943ba07ed65565534cccf562e8d19 100644 (file)
@@ -42,7 +42,8 @@ pub use miniscript::{
 };
 
 pub mod checksum;
-mod dsl;
+#[doc(hidden)]
+pub mod dsl;
 pub mod error;
 pub mod policy;
 pub mod template;
index 2ba9fd065248fba668a9e2c2bb5cefd1bb10236b..f90b012567fe72e1b173c9019c63252789384e8d 100644 (file)
@@ -1018,7 +1018,7 @@ mod test {
     fn test_extract_policy_for_sh_multi_complete_1of2() {
         let (_prvkey0, pubkey0, fingerprint0) = setup_keys(TPRV0_STR);
         let (prvkey1, _pubkey1, fingerprint1) = setup_keys(TPRV1_STR);
-        let desc = descriptor!(sh(multi 1, pubkey0, prvkey1)).unwrap();
+        let desc = descriptor!(sh(multi(1, pubkey0, prvkey1))).unwrap();
         let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap();
         let signers_container = Arc::new(SignersContainer::from(keymap));
         let policy = wallet_desc
@@ -1046,7 +1046,7 @@ mod test {
     fn test_extract_policy_for_sh_multi_complete_2of2() {
         let (prvkey0, _pubkey0, fingerprint0) = setup_keys(TPRV0_STR);
         let (prvkey1, _pubkey1, fingerprint1) = setup_keys(TPRV1_STR);
-        let desc = descriptor!(sh(multi 2, prvkey0, prvkey1)).unwrap();
+        let desc = descriptor!(sh(multi(2, prvkey0, prvkey1))).unwrap();
         let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap();
         let signers_container = Arc::new(SignersContainer::from(keymap));
         let policy = wallet_desc
@@ -1111,7 +1111,7 @@ mod test {
     fn test_extract_policy_for_single_wsh_multi_complete_1of2() {
         let (_prvkey0, pubkey0, fingerprint0) = setup_keys(TPRV0_STR);
         let (prvkey1, _pubkey1, fingerprint1) = setup_keys(TPRV1_STR);
-        let desc = descriptor!(sh(multi 1, pubkey0, prvkey1)).unwrap();
+        let desc = descriptor!(sh(multi(1, pubkey0, prvkey1))).unwrap();
         let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap();
         let single_key = wallet_desc.derive(ChildNumber::from_normal_idx(0).unwrap());
         let signers_container = Arc::new(SignersContainer::from(keymap));
@@ -1143,9 +1143,12 @@ mod test {
         let (prvkey0, _pubkey0, _fingerprint0) = setup_keys(TPRV0_STR);
         let (_prvkey1, pubkey1, _fingerprint1) = setup_keys(TPRV1_STR);
         let sequence = 50;
-        let desc = descriptor!(wsh (
-            thresh 2, (pk prvkey0), (+s pk pubkey1), (+s+d+v older sequence)
-        ))
+        let desc = descriptor!(wsh(thresh(
+            2,
+            pk(prvkey0),
+            s: pk(pubkey1),
+            s: d: v: older(sequence)
+        )))
         .unwrap();
 
         let (wallet_desc, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap();
index dde2e1a621f8e79db855b1375227f90753ac7f43..194a24241978493c0511c483a270902c9e7a1990 100644 (file)
@@ -557,7 +557,7 @@ mod signers_container_tests {
     fn signers_with_same_ordering() {
         let (prvkey1, _, _) = setup_keys(TPRV0_STR);
         let (prvkey2, _, _) = setup_keys(TPRV1_STR);
-        let desc = descriptor!(sh(multi 2, prvkey1, prvkey2)).unwrap();
+        let desc = descriptor!(sh(multi(2, prvkey1, prvkey2))).unwrap();
         let (_, keymap) = desc.to_wallet_descriptor(Network::Testnet).unwrap();
 
         let signers = SignersContainer::from(keymap);