diff --git a/src/descriptor/dsl.rs b/src/descriptor/dsl.rs index caee94bd..4296b4d9 100644 --- a/src/descriptor/dsl.rs +++ b/src/descriptor/dsl.rs @@ -73,6 +73,38 @@ macro_rules! impl_top_level_pk { }}; } +#[doc(hidden)] +#[macro_export] +macro_rules! impl_top_level_tr { + ( $internal_key:expr, $tap_tree:expr ) => {{ + use $crate::miniscript::descriptor::{Descriptor, DescriptorPublicKey, Tr}; + use $crate::miniscript::Tap; + + #[allow(unused_imports)] + use $crate::keys::{DescriptorKey, IntoDescriptorKey}; + let secp = $crate::bitcoin::secp256k1::Secp256k1::new(); + + $internal_key + .into_descriptor_key() + .and_then(|key: DescriptorKey| key.extract(&secp)) + .map_err($crate::descriptor::DescriptorError::Key) + .and_then(|(pk, mut key_map, mut valid_networks)| { + let tap_tree = $tap_tree.map(|(tap_tree, tree_keymap, tree_networks)| { + key_map.extend(tree_keymap.into_iter()); + valid_networks = $crate::keys::merge_networks(&valid_networks, &tree_networks); + + tap_tree + }); + + Ok(( + Descriptor::::Tr(Tr::new(pk, tap_tree)?), + key_map, + valid_networks, + )) + }) + }}; +} + #[doc(hidden)] #[macro_export] macro_rules! impl_leaf_opcode { @@ -228,6 +260,62 @@ macro_rules! impl_sortedmulti { } +#[doc(hidden)] +#[macro_export] +macro_rules! parse_tap_tree { + ( @merge $tree_a:expr, $tree_b:expr) => {{ + use std::sync::Arc; + use $crate::miniscript::descriptor::TapTree; + + $tree_a + .and_then(|tree_a| Ok((tree_a, $tree_b?))) + .and_then(|((a_tree, mut a_keymap, a_networks), (b_tree, b_keymap, b_networks))| { + a_keymap.extend(b_keymap.into_iter()); + Ok((TapTree::Tree(Arc::new(a_tree), Arc::new(b_tree)), a_keymap, $crate::keys::merge_networks(&a_networks, &b_networks))) + }) + + }}; + + // Two sub-trees + ( { { $( $tree_a:tt )* }, { $( $tree_b:tt )* } } ) => {{ + let tree_a = $crate::parse_tap_tree!( { $( $tree_a )* } ); + let tree_b = $crate::parse_tap_tree!( { $( $tree_b )* } ); + + $crate::parse_tap_tree!(@merge tree_a, tree_b) + }}; + + // One leaf and a sub-tree + ( { $op_a:ident ( $( $minisc_a:tt )* ), { $( $tree_b:tt )* } } ) => {{ + let tree_a = $crate::parse_tap_tree!( $op_a ( $( $minisc_a )* ) ); + let tree_b = $crate::parse_tap_tree!( { $( $tree_b )* } ); + + $crate::parse_tap_tree!(@merge tree_a, tree_b) + }}; + ( { { $( $tree_a:tt )* }, $op_b:ident ( $( $minisc_b:tt )* ) } ) => {{ + let tree_a = $crate::parse_tap_tree!( { $( $tree_a )* } ); + let tree_b = $crate::parse_tap_tree!( $op_b ( $( $minisc_b )* ) ); + + $crate::parse_tap_tree!(@merge tree_a, tree_b) + }}; + + // Two leaves + ( { $op_a:ident ( $( $minisc_a:tt )* ), $op_b:ident ( $( $minisc_b:tt )* ) } ) => {{ + let tree_a = $crate::parse_tap_tree!( $op_a ( $( $minisc_a )* ) ); + let tree_b = $crate::parse_tap_tree!( $op_b ( $( $minisc_b )* ) ); + + $crate::parse_tap_tree!(@merge tree_a, tree_b) + }}; + + // Single leaf + ( $op:ident ( $( $minisc:tt )* ) ) => {{ + use std::sync::Arc; + use $crate::miniscript::descriptor::TapTree; + + $crate::fragment!( $op ( $( $minisc )* ) ) + .map(|(a_minisc, a_keymap, a_networks)| (TapTree::Leaf(Arc::new(a_minisc)), a_keymap, a_networks)) + }}; +} + #[doc(hidden)] #[macro_export] macro_rules! apply_modifier { @@ -441,6 +529,15 @@ macro_rules! descriptor { ( wsh ( $( $minisc:tt )* ) ) => ({ $crate::impl_top_level_sh!(Wsh, new, new_sortedmulti, Segwitv0, $( $minisc )*) }); + + ( tr ( $internal_key:expr ) ) => ({ + $crate::impl_top_level_tr!($internal_key, None) + }); + ( tr ( $internal_key:expr, $( $taptree:tt )* ) ) => ({ + let tap_tree = $crate::parse_tap_tree!( $( $taptree )* ); + tap_tree + .and_then(|tap_tree| $crate::impl_top_level_tr!($internal_key, Some(tap_tree))) + }); } #[doc(hidden)]