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 )*)
|
|
|
|
.map(|(minisc, keymap)|($crate::miniscript::Descriptor::<$crate::miniscript::descriptor::DescriptorPublicKey>::$descriptor_variant(minisc), keymap))
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
#[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 ) => {{
|
|
|
|
use $crate::keys::{DescriptorKey, ToDescriptorKey};
|
|
|
|
|
2020-09-18 16:31:03 +02:00
|
|
|
$key.to_descriptor_key()
|
2020-09-19 12:08:30 +02:00
|
|
|
.and_then(|key: DescriptorKey<$ctx>| key.into_key_and_secret())
|
2020-09-18 16:31:03 +02:00
|
|
|
.map(|(pk, key_map)| {
|
|
|
|
(
|
|
|
|
$crate::miniscript::Descriptor::<
|
|
|
|
$crate::miniscript::descriptor::DescriptorPublicKey,
|
|
|
|
>::$descriptor_variant(pk),
|
|
|
|
key_map,
|
|
|
|
)
|
|
|
|
})
|
|
|
|
}};
|
|
|
|
}
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! impl_modifier {
|
|
|
|
( $terminal_variant:ident, $( $inner:tt )* ) => {
|
|
|
|
$crate::fragment!($( $inner )*)
|
|
|
|
.and_then(|(minisc, keymap)| Ok(($crate::miniscript::Miniscript::from_ast($crate::miniscript::miniscript::decode::Terminal::$terminal_variant(std::sync::Arc::new(minisc)))?, keymap)))
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
#[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)
|
|
|
|
.map(|minisc| (minisc, $crate::miniscript::descriptor::KeyMap::default()))
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
#[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)
|
|
|
|
.map(|minisc| (minisc, $crate::miniscript::descriptor::KeyMap::default()))
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
#[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)
|
|
|
|
.map(|minisc| (minisc, $crate::miniscript::descriptor::KeyMap::default()))
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
#[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 )*)?)))
|
|
|
|
.and_then(|((a_minisc, mut a_keymap), (b_minisc, b_keymap))| {
|
|
|
|
// 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),
|
|
|
|
))?, a_keymap))
|
|
|
|
})
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
#[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 )*)?)))
|
|
|
|
.and_then(|((a_minisc, mut a_keymap), (b_minisc, b_keymap), (c_minisc, c_keymap))| {
|
|
|
|
// join key_maps
|
|
|
|
a_keymap.extend(b_keymap.into_iter());
|
|
|
|
a_keymap.extend(c_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),
|
|
|
|
std::sync::Arc::new(c_minisc),
|
|
|
|
))?, a_keymap))
|
|
|
|
})
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Macro to write full descriptors with code
|
2020-09-16 14:32:55 +02:00
|
|
|
///
|
2020-09-18 16:31:03 +02:00
|
|
|
/// This macro expands to an object of type `Result<(Descriptor<DescriptorPublicKey>, KeyMap), 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-18 16:31:03 +02:00
|
|
|
/// let (my_descriptor, my_keys_map) = bdk::descriptor!(sh ( wsh ( and_v (+v pk my_key), ( older my_timelock ))))?;
|
|
|
|
/// # 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-18 16:31:03 +02:00
|
|
|
/// let (descriptor_a, key_map_a) = 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-18 16:31:03 +02:00
|
|
|
/// let (descriptor_b, mut key_map_b) = 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")?;
|
|
|
|
///
|
|
|
|
/// let (descriptor, key_map) = bdk::descriptor! {
|
|
|
|
/// 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(...)`
|
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use std::str::FromStr;
|
|
|
|
/// let my_key = bitcoin::PrivateKey::from_wif("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy")?;
|
|
|
|
///
|
|
|
|
/// let (descriptor, key_map) = bdk::descriptor!(wpkh ( my_key ) )?;
|
|
|
|
/// # 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-18 16:31:03 +02:00
|
|
|
$crate::descriptor!(shwpkh ($( $minisc )*))
|
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
|
|
|
|
///
|
|
|
|
/// This macro will be expanded to an object of type `Result<(Miniscript<DescriptorPublicKey, _>, KeyMap), Error>`. It allows writing
|
|
|
|
/// 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-18 16:31:03 +02:00
|
|
|
use $crate::keys::ToDescriptorKey;
|
2020-09-19 12:08:30 +02:00
|
|
|
$key.into_miniscript_and_secret()
|
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;
|
|
|
|
|
|
|
|
let (items, key_maps): (Vec<_>, Vec<_>) = $items.into_iter().unzip();
|
|
|
|
let items = items.into_iter().map(std::sync::Arc::new).collect();
|
|
|
|
let key_maps = key_maps.into_iter().fold(KeyMap::default(), |mut acc, map| {
|
|
|
|
acc.extend(map.into_iter());
|
|
|
|
acc
|
|
|
|
});
|
|
|
|
|
|
|
|
$crate::impl_leaf_opcode_value_two!(Thresh, $thresh, items)
|
|
|
|
.map(|(minisc, _)| (minisc, key_maps))
|
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
|
|
|
}
|