2020-09-16 14:32:55 +02:00
// Magical Bitcoin Library
// Written in 2020 by
// Alekos Filini <alekos.filini@gmail.com>
//
// Copyright (c) 2020 Magical Bitcoin
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
2020-09-18 16:31:03 +02:00
//! Descriptors DSL
2020-09-16 14:32:55 +02:00
2020-09-18 16:31:03 +02:00
#[ doc(hidden) ]
#[ macro_export ]
macro_rules ! impl_top_level_sh {
( $descriptor_variant :ident , $( $minisc :tt ) * ) = > {
$crate ::fragment! ( $( $minisc ) * )
2020-09-21 15:44:07 +02:00
. map ( | ( minisc , keymap , networks ) | ( $crate ::miniscript ::Descriptor ::< $crate ::miniscript ::descriptor ::DescriptorPublicKey > ::$descriptor_variant ( minisc ) , keymap , networks ) )
2020-09-18 16:31:03 +02:00
} ;
}
#[ doc(hidden) ]
#[ macro_export ]
macro_rules ! impl_top_level_pk {
2020-09-19 12:08:30 +02:00
( $descriptor_variant :ident , $ctx :ty , $key :expr ) = > { {
2020-09-22 16:12:09 +02:00
#[ allow(unused_imports) ]
2020-09-19 12:08:30 +02:00
use $crate ::keys ::{ DescriptorKey , ToDescriptorKey } ;
2020-09-18 16:31:03 +02:00
$key . to_descriptor_key ( )
2020-09-21 15:44:07 +02:00
. and_then ( | key : DescriptorKey < $ctx > | key . extract ( ) )
. map ( | ( pk , key_map , valid_networks ) | {
2020-09-18 16:31:03 +02:00
(
$crate ::miniscript ::Descriptor ::<
$crate ::miniscript ::descriptor ::DescriptorPublicKey ,
> ::$descriptor_variant ( pk ) ,
key_map ,
2020-09-21 15:44:07 +02:00
valid_networks ,
2020-09-18 16:31:03 +02:00
)
} )
} } ;
}
#[ doc(hidden) ]
#[ macro_export ]
macro_rules ! impl_modifier {
( $terminal_variant :ident , $( $inner :tt ) * ) = > {
$crate ::fragment! ( $( $inner ) * )
2020-09-21 15:44:07 +02:00
. 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 ) ) )
2020-09-18 16:31:03 +02:00
} ;
}
#[ doc(hidden) ]
#[ macro_export ]
macro_rules ! impl_leaf_opcode {
( $terminal_variant :ident ) = > {
$crate ::miniscript ::Miniscript ::from_ast (
$crate ::miniscript ::miniscript ::decode ::Terminal ::$terminal_variant ,
)
. map_err ( $crate ::Error ::Miniscript )
2020-09-21 15:44:07 +02:00
. map ( | minisc | {
(
minisc ,
$crate ::miniscript ::descriptor ::KeyMap ::default ( ) ,
$crate ::keys ::any_network ( ) ,
)
} )
2020-09-18 16:31:03 +02:00
} ;
}
#[ doc(hidden) ]
#[ macro_export ]
macro_rules ! impl_leaf_opcode_value {
( $terminal_variant :ident , $value :expr ) = > {
$crate ::miniscript ::Miniscript ::from_ast (
$crate ::miniscript ::miniscript ::decode ::Terminal ::$terminal_variant ( $value ) ,
)
. map_err ( $crate ::Error ::Miniscript )
2020-09-21 15:44:07 +02:00
. map ( | minisc | {
(
minisc ,
$crate ::miniscript ::descriptor ::KeyMap ::default ( ) ,
$crate ::keys ::any_network ( ) ,
)
} )
2020-09-18 16:31:03 +02:00
} ;
}
#[ doc(hidden) ]
#[ macro_export ]
macro_rules ! impl_leaf_opcode_value_two {
( $terminal_variant :ident , $one :expr , $two :expr ) = > {
$crate ::miniscript ::Miniscript ::from_ast (
$crate ::miniscript ::miniscript ::decode ::Terminal ::$terminal_variant ( $one , $two ) ,
)
. map_err ( $crate ::Error ::Miniscript )
2020-09-21 15:44:07 +02:00
. map ( | minisc | {
(
minisc ,
$crate ::miniscript ::descriptor ::KeyMap ::default ( ) ,
$crate ::keys ::any_network ( ) ,
)
} )
2020-09-18 16:31:03 +02:00
} ;
}
#[ 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 ) * ) ? ) ) )
2020-09-21 15:44:07 +02:00
. and_then ( | ( ( a_minisc , mut a_keymap , a_networks ) , ( b_minisc , b_keymap , b_networks ) ) | {
2020-09-18 16:31:03 +02:00
// join key_maps
a_keymap . extend ( b_keymap . into_iter ( ) ) ;
Ok ( ( $crate ::miniscript ::Miniscript ::from_ast ( $crate ::miniscript ::miniscript ::decode ::Terminal ::$terminal_variant (
std ::sync ::Arc ::new ( a_minisc ) ,
std ::sync ::Arc ::new ( b_minisc ) ,
2020-09-21 15:44:07 +02:00
) ) ? , a_keymap , $crate ::keys ::merge_networks ( & a_networks , & b_networks ) ) )
2020-09-18 16:31:03 +02:00
} )
} ;
}
#[ 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 ) * ) ? ) ) )
2020-09-21 15:44:07 +02:00
. and_then ( | ( ( a_minisc , mut a_keymap , a_networks ) , ( b_minisc , b_keymap , b_networks ) , ( c_minisc , c_keymap , c_networks ) ) | {
2020-09-18 16:31:03 +02:00
// join key_maps
a_keymap . extend ( b_keymap . into_iter ( ) ) ;
a_keymap . extend ( c_keymap . into_iter ( ) ) ;
2020-09-21 15:44:07 +02:00
let networks = $crate ::keys ::merge_networks ( & a_networks , & b_networks ) ;
let networks = $crate ::keys ::merge_networks ( & networks , & c_networks ) ;
2020-09-18 16:31:03 +02:00
Ok ( ( $crate ::miniscript ::Miniscript ::from_ast ( $crate ::miniscript ::miniscript ::decode ::Terminal ::$terminal_variant (
std ::sync ::Arc ::new ( a_minisc ) ,
std ::sync ::Arc ::new ( b_minisc ) ,
std ::sync ::Arc ::new ( c_minisc ) ,
2020-09-21 15:44:07 +02:00
) ) ? , a_keymap , networks ) )
2020-09-18 16:31:03 +02:00
} )
} ;
}
/// Macro to write full descriptors with code
2020-09-16 14:32:55 +02:00
///
2020-09-21 15:44:07 +02:00
/// This macro expands to an object of type `Result<(Descriptor<DescriptorPublicKey>, KeyMap, ValidNetworks), Error>`.
2020-09-16 14:32:55 +02:00
///
/// ## Example
///
/// Signature plus timelock, equivalent to: `sh(wsh(and_v(v:pk(...), older(...))))`
///
/// ```
/// # use std::str::FromStr;
2020-09-18 16:31:03 +02:00
/// let my_key = bitcoin::PublicKey::from_str("02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c")?;
2020-09-16 14:32:55 +02:00
/// let my_timelock = 50;
2020-09-21 15:44:07 +02:00
/// let (my_descriptor, my_keys_map, networks) = bdk::descriptor!(sh ( wsh ( and_v (+v pk my_key), ( older my_timelock ))))?;
2020-09-18 16:31:03 +02:00
/// # Ok::<(), Box<dyn std::error::Error>>(())
2020-09-16 14:32:55 +02:00
/// ```
///
2020-09-18 16:31:03 +02:00
/// -------
///
2020-09-16 14:32:55 +02:00
/// 2-of-3 that becomes a 1-of-3 after a timelock has expired. Both `descriptor_a` and `descriptor_b` are equivalent: the first
/// syntax is more suitable for a fixed number of items known at compile time, while the other accepts a
/// [`Vec`] of items, which makes it more suitable for writing dynamic descriptors.
///
/// They both produce the descriptor: `wsh(thresh(2,pk(...),s:pk(...),sdv:older(...)))`
///
/// ```
/// # use std::str::FromStr;
2020-09-18 16:31:03 +02:00
/// let my_key_1 = bitcoin::PublicKey::from_str("02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c")?;
/// let my_key_2 = bitcoin::PrivateKey::from_wif("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy")?;
2020-09-16 14:32:55 +02:00
/// let my_timelock = 50;
///
2020-09-21 15:44:07 +02:00
/// let (descriptor_a, key_map_a, networks) = bdk::descriptor! {
2020-09-16 14:32:55 +02:00
/// wsh (
2020-09-18 16:31:03 +02:00
/// thresh 2, (pk my_key_1), (+s pk my_key_2), (+s+d+v older my_timelock)
2020-09-16 14:32:55 +02:00
/// )
2020-09-18 16:31:03 +02:00
/// }?;
2020-09-16 14:32:55 +02:00
///
/// let b_items = vec![
2020-09-18 16:31:03 +02:00
/// bdk::fragment!(pk my_key_1)?,
/// bdk::fragment!(+s pk my_key_2)?,
/// bdk::fragment!(+s+d+v older my_timelock)?,
2020-09-16 14:32:55 +02:00
/// ];
2020-09-21 15:44:07 +02:00
/// let (descriptor_b, mut key_map_b, networks) = bdk::descriptor!( wsh ( thresh_vec 2, b_items ) )?;
2020-09-16 14:32:55 +02:00
///
/// assert_eq!(descriptor_a, descriptor_b);
2020-09-18 16:31:03 +02:00
/// assert_eq!(key_map_a.len(), key_map_b.len());
/// # Ok::<(), Box<dyn std::error::Error>>(())
2020-09-16 14:32:55 +02:00
/// ```
2020-09-18 17:26:58 +02:00
///
/// ------
///
/// Simple 2-of-2 multi-signature, equivalent to: `wsh(multi(2, ...))`
///
/// ```
/// # use std::str::FromStr;
/// let my_key_1 = bitcoin::PublicKey::from_str("02e96fe52ef0e22d2f131dd425ce1893073a3c6ad20e8cac36726393dfb4856a4c")?;
/// let my_key_2 = bitcoin::PrivateKey::from_wif("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy")?;
///
2020-09-21 15:44:07 +02:00
/// let (descriptor, key_map, networks) = bdk::descriptor! {
2020-09-18 17:26:58 +02:00
/// wsh (
/// multi 2, my_key_1, my_key_2
/// )
/// }?;
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
2020-09-19 12:08:30 +02:00
///
/// ------
///
/// Native-Segwit single-sig, equivalent to: `wpkh(...)`
///
/// ```
/// let my_key = bitcoin::PrivateKey::from_wif("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy")?;
///
2020-09-21 15:44:07 +02:00
/// let (descriptor, key_map, networks) = bdk::descriptor!(wpkh ( my_key ) )?;
2020-09-19 12:08:30 +02:00
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
2020-09-16 14:32:55 +02:00
#[ macro_export ]
2020-09-18 16:31:03 +02:00
macro_rules ! descriptor {
2020-09-16 14:32:55 +02:00
( bare ( $( $minisc :tt ) * ) ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::impl_top_level_sh! ( Bare , $( $minisc ) * )
2020-09-16 14:32:55 +02:00
} ) ;
( sh ( wsh ( $( $minisc :tt ) * ) ) ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::descriptor! ( shwsh ( $( $minisc ) * ) )
2020-09-16 14:32:55 +02:00
} ) ;
( shwsh ( $( $minisc :tt ) * ) ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::impl_top_level_sh! ( ShWsh , $( $minisc ) * )
2020-09-16 14:32:55 +02:00
} ) ;
2020-09-18 16:31:03 +02:00
( pk $key :expr ) = > ( {
2020-09-19 12:08:30 +02:00
$crate ::impl_top_level_pk! ( Pk , $crate ::miniscript ::Legacy , $key )
2020-09-16 14:32:55 +02:00
} ) ;
( pkh $key :expr ) = > ( {
2020-09-19 12:08:30 +02:00
$crate ::impl_top_level_pk! ( Pkh , $crate ::miniscript ::Legacy , $key )
2020-09-16 14:32:55 +02:00
} ) ;
( wpkh $key :expr ) = > ( {
2020-09-19 12:08:30 +02:00
$crate ::impl_top_level_pk! ( Wpkh , $crate ::miniscript ::Segwitv0 , $key )
2020-09-16 14:32:55 +02:00
} ) ;
( sh ( wpkh ( $key :expr ) ) ) = > ( {
2020-09-22 16:12:09 +02:00
$crate ::descriptor! ( shwpkh ( $key ) )
2020-09-16 14:32:55 +02:00
} ) ;
( shwpkh ( $key :expr ) ) = > ( {
2020-09-19 12:08:30 +02:00
$crate ::impl_top_level_pk! ( ShWpkh , $crate ::miniscript ::Segwitv0 , $key )
2020-09-16 14:32:55 +02:00
} ) ;
( sh ( $( $minisc :tt ) * ) ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::impl_top_level_sh! ( Sh , $( $minisc ) * )
2020-09-16 14:32:55 +02:00
} ) ;
( wsh ( $( $minisc :tt ) * ) ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::impl_top_level_sh! ( Wsh , $( $minisc ) * )
2020-09-16 14:32:55 +02:00
} ) ;
2020-09-18 16:31:03 +02:00
}
2020-09-16 14:32:55 +02:00
2020-09-18 16:31:03 +02:00
/// Macro to write descriptor fragments with code
///
2020-09-21 15:44:07 +02:00
/// This macro will be expanded to an object of type `Result<(Miniscript<DescriptorPublicKey, _>, KeyMap, ValidNetworks), Error>`. It allows writing
2020-09-18 16:31:03 +02:00
/// fragments of larger descriptors that can be pieced together using `fragment!(thresh_vec ...)`.
#[ macro_export ]
macro_rules ! fragment {
2020-09-16 14:32:55 +02:00
// Modifiers
( + a $( $inner :tt ) * ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::impl_modifier! ( Alt , $( $inner ) * )
2020-09-16 14:32:55 +02:00
} ) ;
( + s $( $inner :tt ) * ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::impl_modifier! ( Swap , $( $inner ) * )
2020-09-16 14:32:55 +02:00
} ) ;
( + c $( $inner :tt ) * ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::impl_modifier! ( Check , $( $inner ) * )
2020-09-16 14:32:55 +02:00
} ) ;
( + d $( $inner :tt ) * ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::impl_modifier! ( DupIf , $( $inner ) * )
2020-09-16 14:32:55 +02:00
} ) ;
( + v $( $inner :tt ) * ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::impl_modifier! ( Verify , $( $inner ) * )
2020-09-16 14:32:55 +02:00
} ) ;
( + j $( $inner :tt ) * ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::impl_modifier! ( NonZero , $( $inner ) * )
2020-09-16 14:32:55 +02:00
} ) ;
( + n $( $inner :tt ) * ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::impl_modifier! ( ZeroNotEqual , $( $inner ) * )
2020-09-16 14:32:55 +02:00
} ) ;
( + t $( $inner :tt ) * ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::fragment! ( and_v ( $( $inner ) * ) , ( true ) )
2020-09-16 14:32:55 +02:00
} ) ;
( + l $( $inner :tt ) * ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::fragment! ( or_i ( false ) , ( $( $inner ) * ) )
2020-09-16 14:32:55 +02:00
} ) ;
( + u $( $inner :tt ) * ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::fragment! ( or_i ( $( $inner ) * ) , ( false ) )
2020-09-16 14:32:55 +02:00
} ) ;
// Miniscript
( true ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::impl_leaf_opcode! ( True )
2020-09-16 14:32:55 +02:00
} ) ;
( false ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::impl_leaf_opcode! ( False )
2020-09-16 14:32:55 +02:00
} ) ;
( pk_k $key :expr ) = > ( {
2020-09-21 15:44:07 +02:00
$crate ::keys ::make_pk ( $key )
2020-09-16 14:32:55 +02:00
} ) ;
( pk $key :expr ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::fragment! ( + c pk_k $key )
2020-09-16 14:32:55 +02:00
} ) ;
( pk_h $key_hash :expr ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::impl_leaf_opcode_value! ( PkH , $key_hash )
2020-09-16 14:32:55 +02:00
} ) ;
( after $value :expr ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::impl_leaf_opcode_value! ( After , $value )
2020-09-16 14:32:55 +02:00
} ) ;
( older $value :expr ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::impl_leaf_opcode_value! ( Older , $value )
2020-09-16 14:32:55 +02:00
} ) ;
( sha256 $hash :expr ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::impl_leaf_opcode_value! ( Sha256 , $hash )
2020-09-16 14:32:55 +02:00
} ) ;
( hash256 $hash :expr ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::impl_leaf_opcode_value! ( Hash256 , $hash )
2020-09-16 14:32:55 +02:00
} ) ;
( ripemd160 $hash :expr ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::impl_leaf_opcode_value! ( Ripemd160 , $hash )
2020-09-16 14:32:55 +02:00
} ) ;
( hash160 $hash :expr ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::impl_leaf_opcode_value! ( Hash160 , $hash )
2020-09-16 14:32:55 +02:00
} ) ;
( and_v ( $( $a :tt ) * ) , ( $( $b :tt ) * ) ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::impl_node_opcode_two! ( AndV , ( $( $a ) * ) , ( $( $b ) * ) )
2020-09-16 14:32:55 +02:00
} ) ;
( and_b ( $( $a :tt ) * ) , ( $( $b :tt ) * ) ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::impl_node_opcode_two! ( AndB , ( $( $a ) * ) , ( $( $b ) * ) )
2020-09-16 14:32:55 +02:00
} ) ;
( and_or ( $( $a :tt ) * ) , ( $( $b :tt ) * ) , ( $( $c :tt ) * ) ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::impl_node_opcode_three! ( AndOr , ( $( $a ) * ) , ( $( $b ) * ) , ( $( $c ) * ) )
2020-09-16 14:32:55 +02:00
} ) ;
( or_b ( $( $a :tt ) * ) , ( $( $b :tt ) * ) ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::impl_node_opcode_two! ( OrB , ( $( $a ) * ) , ( $( $b ) * ) )
2020-09-16 14:32:55 +02:00
} ) ;
( or_d ( $( $a :tt ) * ) , ( $( $b :tt ) * ) ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::impl_node_opcode_two! ( OrD , ( $( $a ) * ) , ( $( $b ) * ) )
2020-09-16 14:32:55 +02:00
} ) ;
( or_c ( $( $a :tt ) * ) , ( $( $b :tt ) * ) ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::impl_node_opcode_two! ( OrC , ( $( $a ) * ) , ( $( $b ) * ) )
2020-09-16 14:32:55 +02:00
} ) ;
( or_i ( $( $a :tt ) * ) , ( $( $b :tt ) * ) ) = > ( {
2020-09-18 16:31:03 +02:00
$crate ::impl_node_opcode_two! ( OrI , ( $( $a ) * ) , ( $( $b ) * ) )
2020-09-16 14:32:55 +02:00
} ) ;
( thresh_vec $thresh :expr , $items :expr ) = > ( {
2020-09-18 16:31:03 +02:00
use $crate ::miniscript ::descriptor ::KeyMap ;
2020-09-21 15:44:07 +02:00
let ( items , key_maps_networks ) : ( Vec < _ > , Vec < _ > ) = $items . into_iter ( ) . map ( | ( a , b , c ) | ( a , ( b , c ) ) ) . unzip ( ) ;
2020-09-18 16:31:03 +02:00
let items = items . into_iter ( ) . map ( std ::sync ::Arc ::new ) . collect ( ) ;
2020-09-21 15:44:07 +02:00
let ( key_maps , valid_networks ) = key_maps_networks . into_iter ( ) . fold ( ( KeyMap ::default ( ) , $crate ::keys ::any_network ( ) ) , | ( mut keys_acc , net_acc ) , ( key , net ) | {
keys_acc . extend ( key . into_iter ( ) ) ;
let net_acc = $crate ::keys ::merge_networks ( & net_acc , & net ) ;
( keys_acc , net_acc )
2020-09-18 16:31:03 +02:00
} ) ;
$crate ::impl_leaf_opcode_value_two! ( Thresh , $thresh , items )
2020-09-21 15:44:07 +02:00
. map ( | ( minisc , _ , _ ) | ( minisc , key_maps , valid_networks ) )
2020-09-16 14:32:55 +02:00
} ) ;
( thresh $thresh :expr $(, ( $( $item :tt ) * ) ) + ) = > ( {
let mut items = vec! [ ] ;
$(
2020-09-18 16:31:03 +02:00
items . push ( $crate ::fragment! ( $( $item ) * ) ) ;
2020-09-16 14:32:55 +02:00
) *
2020-09-18 16:31:03 +02:00
items . into_iter ( ) . collect ::< Result < Vec < _ > , _ > > ( )
. and_then ( | items | $crate ::fragment! ( thresh_vec $thresh , items ) )
} ) ;
( multi_vec $thresh :expr , $keys :expr ) = > ( {
2020-09-19 12:08:30 +02:00
$crate ::keys ::make_multi ( $thresh , $keys )
2020-09-16 14:32:55 +02:00
} ) ;
2020-09-18 16:31:03 +02:00
( multi $thresh :expr $(, $key :expr ) + ) = > ( {
2020-09-18 17:26:58 +02:00
use $crate ::keys ::ToDescriptorKey ;
2020-09-18 16:31:03 +02:00
let mut keys = vec! [ ] ;
$(
2020-09-18 17:26:58 +02:00
keys . push ( $key . to_descriptor_key ( ) ) ;
2020-09-18 16:31:03 +02:00
) *
2020-09-18 17:26:58 +02:00
keys . into_iter ( ) . collect ::< Result < Vec < _ > , _ > > ( )
2020-09-19 12:08:30 +02:00
. and_then ( | keys | $crate ::keys ::make_multi ( $thresh , keys ) )
2020-09-16 14:32:55 +02:00
} ) ;
2020-09-18 16:31:03 +02:00
2020-09-16 14:32:55 +02:00
}
2020-10-03 14:48:13 -07:00
// test the descriptor!() macro
// - at least one of each "type" of operator; ie. one modifier, one leaf_opcode, one leaf_opcode_value, etc.
// - mixing up key types that implement ToDescriptorKey in multi() or thresh()
// - verify the valid_networks returned is correctly computed based on the keys present in the descriptor
// - verify the key_maps are correctly merged together
// - verify the ScriptContext is correctly validated (i.e. passing a type that only impl ToDescriptorKey<Segwitv0> to a pkh() descriptor should throw a compilation error