diff --git a/src/blanket_traits.rs b/src/blanket_traits.rs index bc6dab913..6e7496d0b 100644 --- a/src/blanket_traits.rs +++ b/src/blanket_traits.rs @@ -12,8 +12,8 @@ //! automatically implemented if you satisfy all the bounds. //! -use core::fmt; use core::str::FromStr; +use core::{fmt, hash}; use crate::MiniscriptKey; @@ -28,19 +28,43 @@ pub trait FromStrKey: > + FromStr { /// Dummy type. Do not use. - type _Sha256: FromStr; + type _Sha256: FromStr + + Clone + + Eq + + Ord + + fmt::Display + + fmt::Debug + + hash::Hash; /// Dummy type. Do not use. type _Sha256FromStrErr: fmt::Debug + fmt::Display; /// Dummy type. Do not use. - type _Hash256: FromStr; + type _Hash256: FromStr + + Clone + + Eq + + Ord + + fmt::Display + + fmt::Debug + + hash::Hash; /// Dummy type. Do not use. type _Hash256FromStrErr: fmt::Debug + fmt::Display; /// Dummy type. Do not use. - type _Ripemd160: FromStr; + type _Ripemd160: FromStr + + Clone + + Eq + + Ord + + fmt::Display + + fmt::Debug + + hash::Hash; /// Dummy type. Do not use. type _Ripemd160FromStrErr: fmt::Debug + fmt::Display; /// Dummy type. Do not use. - type _Hash160: FromStr; + type _Hash160: FromStr + + Clone + + Eq + + Ord + + fmt::Display + + fmt::Debug + + hash::Hash; /// Dummy type. Do not use. type _Hash160FromStrErr: fmt::Debug + fmt::Display; /// Dummy type. Do not use. diff --git a/src/descriptor/bare.rs b/src/descriptor/bare.rs index 79adb6b33..431b8b20a 100644 --- a/src/descriptor/bare.rs +++ b/src/descriptor/bare.rs @@ -22,8 +22,8 @@ use crate::policy::{semantic, Liftable}; use crate::prelude::*; use crate::util::{varint_len, witness_to_scriptsig}; use crate::{ - BareCtx, Error, ForEachKey, Miniscript, MiniscriptKey, Satisfier, ToPublicKey, TranslateErr, - TranslatePk, Translator, + BareCtx, Error, ForEachKey, FromStrKey, Miniscript, MiniscriptKey, Satisfier, ToPublicKey, + TranslateErr, TranslatePk, Translator, }; /// Create a Bare Descriptor. That is descriptor that is @@ -166,7 +166,7 @@ impl Liftable for Bare { fn lift(&self) -> Result, Error> { self.ms.lift() } } -impl FromTree for Bare { +impl FromTree for Bare { fn from_tree(top: &expression::Tree) -> Result { let sub = Miniscript::::from_tree(top)?; BareCtx::top_level_checks(&sub)?; @@ -174,7 +174,7 @@ impl FromTree for Bare { } } -impl core::str::FromStr for Bare { +impl core::str::FromStr for Bare { type Err = Error; fn from_str(s: &str) -> Result { let desc_str = verify_checksum(s)?; @@ -364,7 +364,7 @@ impl Liftable for Pkh { } } -impl FromTree for Pkh { +impl FromTree for Pkh { fn from_tree(top: &expression::Tree) -> Result { if top.name == "pkh" && top.args.len() == 1 { Ok(Pkh::new(expression::terminal(&top.args[0], |pk| Pk::from_str(pk))?)?) @@ -378,7 +378,7 @@ impl FromTree for Pkh { } } -impl core::str::FromStr for Pkh { +impl core::str::FromStr for Pkh { type Err = Error; fn from_str(s: &str) -> Result { let desc_str = verify_checksum(s)?; diff --git a/src/descriptor/mod.rs b/src/descriptor/mod.rs index 394e17f63..1059a3b3c 100644 --- a/src/descriptor/mod.rs +++ b/src/descriptor/mod.rs @@ -25,8 +25,8 @@ use crate::miniscript::{satisfy, Legacy, Miniscript, Segwitv0}; use crate::plan::{AssetProvider, Plan}; use crate::prelude::*; use crate::{ - expression, hash256, BareCtx, Error, ForEachKey, MiniscriptKey, Satisfier, ToPublicKey, - TranslateErr, TranslatePk, Translator, + expression, hash256, BareCtx, Error, ForEachKey, FromStrKey, MiniscriptKey, Satisfier, + ToPublicKey, TranslateErr, TranslatePk, Translator, }; mod bare; @@ -918,7 +918,7 @@ impl Descriptor { } } -impl crate::expression::FromTree for Descriptor { +impl crate::expression::FromTree for Descriptor { /// Parse an expression tree into a descriptor. fn from_tree(top: &expression::Tree) -> Result, Error> { Ok(match (top.name, top.args.len() as u32) { @@ -932,7 +932,7 @@ impl crate::expression::FromTree for Descriptor { } } -impl FromStr for Descriptor { +impl FromStr for Descriptor { type Err = Error; fn from_str(s: &str) -> Result, Error> { // tr tree parsing has special code diff --git a/src/descriptor/segwitv0.rs b/src/descriptor/segwitv0.rs index fa57eb582..541f0f0db 100644 --- a/src/descriptor/segwitv0.rs +++ b/src/descriptor/segwitv0.rs @@ -20,8 +20,8 @@ use crate::policy::{semantic, Liftable}; use crate::prelude::*; use crate::util::varint_len; use crate::{ - Error, ForEachKey, Miniscript, MiniscriptKey, Satisfier, Segwitv0, ToPublicKey, TranslateErr, - TranslatePk, Translator, + Error, ForEachKey, FromStrKey, Miniscript, MiniscriptKey, Satisfier, Segwitv0, ToPublicKey, + TranslateErr, TranslatePk, Translator, }; /// A Segwitv0 wsh descriptor #[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] @@ -231,7 +231,7 @@ impl Liftable for Wsh { } } -impl crate::expression::FromTree for Wsh { +impl crate::expression::FromTree for Wsh { fn from_tree(top: &expression::Tree) -> Result { if top.name == "wsh" && top.args.len() == 1 { let top = &top.args[0]; @@ -269,7 +269,7 @@ impl fmt::Display for Wsh { } } -impl core::str::FromStr for Wsh { +impl core::str::FromStr for Wsh { type Err = Error; fn from_str(s: &str) -> Result { let desc_str = verify_checksum(s)?; @@ -473,7 +473,7 @@ impl Liftable for Wpkh { } } -impl crate::expression::FromTree for Wpkh { +impl crate::expression::FromTree for Wpkh { fn from_tree(top: &expression::Tree) -> Result { if top.name == "wpkh" && top.args.len() == 1 { Ok(Wpkh::new(expression::terminal(&top.args[0], |pk| Pk::from_str(pk))?)?) @@ -487,7 +487,7 @@ impl crate::expression::FromTree for Wpkh { } } -impl core::str::FromStr for Wpkh { +impl core::str::FromStr for Wpkh { type Err = Error; fn from_str(s: &str) -> Result { let desc_str = verify_checksum(s)?; diff --git a/src/descriptor/sh.rs b/src/descriptor/sh.rs index 3f7e9cb08..da782abff 100644 --- a/src/descriptor/sh.rs +++ b/src/descriptor/sh.rs @@ -24,8 +24,8 @@ use crate::policy::{semantic, Liftable}; use crate::prelude::*; use crate::util::{varint_len, witness_to_scriptsig}; use crate::{ - push_opcode_size, Error, ForEachKey, Legacy, Miniscript, MiniscriptKey, Satisfier, Segwitv0, - ToPublicKey, TranslateErr, TranslatePk, Translator, + push_opcode_size, Error, ForEachKey, FromStrKey, Legacy, Miniscript, MiniscriptKey, Satisfier, + Segwitv0, ToPublicKey, TranslateErr, TranslatePk, Translator, }; /// A Legacy p2sh Descriptor @@ -81,7 +81,7 @@ impl fmt::Display for Sh { } } -impl crate::expression::FromTree for Sh { +impl crate::expression::FromTree for Sh { fn from_tree(top: &expression::Tree) -> Result { if top.name == "sh" && top.args.len() == 1 { let top = &top.args[0]; @@ -106,7 +106,7 @@ impl crate::expression::FromTree for Sh { } } -impl core::str::FromStr for Sh { +impl core::str::FromStr for Sh { type Err = Error; fn from_str(s: &str) -> Result { let desc_str = verify_checksum(s)?; diff --git a/src/descriptor/tr.rs b/src/descriptor/tr.rs index 70e133b6c..931ffaa1d 100644 --- a/src/descriptor/tr.rs +++ b/src/descriptor/tr.rs @@ -23,8 +23,8 @@ use crate::policy::Liftable; use crate::prelude::*; use crate::util::{varint_len, witness_size}; use crate::{ - errstr, Error, ForEachKey, MiniscriptKey, Satisfier, ScriptContext, Tap, ToPublicKey, - TranslateErr, TranslatePk, Translator, + errstr, Error, ForEachKey, FromStrKey, MiniscriptKey, Satisfier, ScriptContext, Tap, + ToPublicKey, TranslateErr, TranslatePk, Translator, }; /// A Taproot Tree representation. @@ -467,7 +467,7 @@ where } #[rustfmt::skip] -impl Tr { +impl Tr { // Helper function to parse taproot script path fn parse_tr_script_spend(tree: &expression::Tree,) -> Result, Error> { match tree { @@ -488,7 +488,7 @@ impl Tr { } } -impl crate::expression::FromTree for Tr { +impl crate::expression::FromTree for Tr { fn from_tree(top: &expression::Tree) -> Result { if top.name == "tr" { match top.args.len() { @@ -530,7 +530,7 @@ impl crate::expression::FromTree for Tr { } } -impl core::str::FromStr for Tr { +impl core::str::FromStr for Tr { type Err = Error; fn from_str(s: &str) -> Result { let desc_str = verify_checksum(s)?; diff --git a/src/miniscript/astelem.rs b/src/miniscript/astelem.rs index e30765548..28d5d8cbd 100644 --- a/src/miniscript/astelem.rs +++ b/src/miniscript/astelem.rs @@ -19,7 +19,8 @@ use crate::miniscript::{types, ScriptContext}; use crate::prelude::*; use crate::util::MsKeyBuilder; use crate::{ - errstr, expression, AbsLockTime, Error, Miniscript, MiniscriptKey, Terminal, ToPublicKey, + errstr, expression, AbsLockTime, Error, FromStrKey, Miniscript, MiniscriptKey, Terminal, + ToPublicKey, }; impl Terminal { @@ -240,15 +241,13 @@ impl fmt::Display for Terminal { } } -impl crate::expression::FromTree - for Arc> -{ +impl crate::expression::FromTree for Arc> { fn from_tree(top: &expression::Tree) -> Result>, Error> { Ok(Arc::new(expression::FromTree::from_tree(top)?)) } } -impl crate::expression::FromTree for Terminal { +impl crate::expression::FromTree for Terminal { fn from_tree(top: &expression::Tree) -> Result, Error> { let (frag_name, frag_wrap) = super::split_expression_name(top.name)?; let unwrapped = match (frag_name, top.args.len()) { diff --git a/src/miniscript/mod.rs b/src/miniscript/mod.rs index 053fc6da1..88a9e9a3f 100644 --- a/src/miniscript/mod.rs +++ b/src/miniscript/mod.rs @@ -45,7 +45,8 @@ use crate::miniscript::decode::Terminal; use crate::miniscript::types::extra_props::ExtData; use crate::miniscript::types::Type; use crate::{ - expression, plan, Error, ForEachKey, MiniscriptKey, ToPublicKey, TranslatePk, Translator, + expression, plan, Error, ForEachKey, FromStrKey, MiniscriptKey, ToPublicKey, TranslatePk, + Translator, }; #[cfg(test)] mod ms_tests; @@ -617,7 +618,7 @@ where Ok(ms) } -impl Miniscript { +impl Miniscript { /// Attempt to parse an insane(scripts don't clear sanity checks) /// from string into a Miniscript representation. /// Use this to parse scripts with repeated pubkeys, timelock mixing, malleable @@ -648,17 +649,13 @@ impl Miniscript { } } -impl crate::expression::FromTree - for Arc> -{ +impl crate::expression::FromTree for Arc> { fn from_tree(top: &expression::Tree) -> Result>, Error> { Ok(Arc::new(expression::FromTree::from_tree(top)?)) } } -impl crate::expression::FromTree - for Miniscript -{ +impl crate::expression::FromTree for Miniscript { /// Parse an expression tree into a Miniscript. As a general rule, this /// should not be called directly; rather go through the descriptor API. fn from_tree(top: &expression::Tree) -> Result, Error> { @@ -667,7 +664,7 @@ impl crate::expression::FromTree } } -impl str::FromStr for Miniscript { +impl str::FromStr for Miniscript { type Err = Error; /// Parse a Miniscript from string and perform sanity checks /// See [Miniscript::from_str_insane] to parse scripts from string that @@ -705,7 +702,7 @@ mod tests { use sync::Arc; use super::{Miniscript, ScriptContext, Segwitv0, Tap}; - use crate::miniscript::types::{self, ExtData, Property, Type}; + use crate::miniscript::types::{self, ExtData, Type}; use crate::miniscript::Terminal; use crate::policy::Liftable; use crate::prelude::*; @@ -893,8 +890,8 @@ mod tests { let pk_node = Terminal::Check(Arc::new(Miniscript { node: Terminal::PkK(String::from("")), - ty: Type::from_pk_k::(), - ext: types::extra_props::ExtData::from_pk_k::(), + ty: Type::pk_k(), + ext: types::extra_props::ExtData::pk_k::(), phantom: PhantomData, })); let pkk_ms: Miniscript = Miniscript::from_ast(pk_node).unwrap(); @@ -902,8 +899,8 @@ mod tests { let pkh_node = Terminal::Check(Arc::new(Miniscript { node: Terminal::PkH(String::from("")), - ty: Type::from_pk_h::(), - ext: types::extra_props::ExtData::from_pk_h::(), + ty: Type::pk_h(), + ext: types::extra_props::ExtData::pk_h::(), phantom: PhantomData, })); let pkh_ms: Miniscript = Miniscript::from_ast(pkh_node).unwrap(); @@ -923,8 +920,8 @@ mod tests { let pkk_node = Terminal::Check(Arc::new(Miniscript { node: Terminal::PkK(pk), - ty: Type::from_pk_k::(), - ext: types::extra_props::ExtData::from_pk_k::(), + ty: Type::pk_k(), + ext: types::extra_props::ExtData::pk_k::(), phantom: PhantomData, })); let pkk_ms: Segwitv0Script = Miniscript::from_ast(pkk_node).unwrap(); @@ -938,12 +935,12 @@ mod tests { let pkh_ms: Segwitv0Script = Miniscript { node: Terminal::Check(Arc::new(Miniscript { node: Terminal::RawPkH(hash), - ty: Type::from_pk_h::(), - ext: types::extra_props::ExtData::from_pk_h::(), + ty: Type::pk_h(), + ext: types::extra_props::ExtData::pk_h::(), phantom: PhantomData, })), - ty: Type::cast_check(Type::from_pk_h::()).unwrap(), - ext: ExtData::cast_check(ExtData::from_pk_h::()).unwrap(), + ty: Type::cast_check(Type::pk_h()).unwrap(), + ext: ExtData::cast_check(ExtData::pk_h::()), phantom: PhantomData, }; diff --git a/src/miniscript/types/correctness.rs b/src/miniscript/types/correctness.rs index 4b6365a66..ad7597f5f 100644 --- a/src/miniscript/types/correctness.rs +++ b/src/miniscript/types/correctness.rs @@ -2,8 +2,7 @@ //! Correctness/Soundness type properties -use super::{ErrorKind, Property}; -use crate::ScriptContext; +use super::ErrorKind; /// Basic type representing where the fragment can go #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] @@ -47,12 +46,24 @@ pub enum Input { } impl Input { + // FIXME rustc should eventually support derived == on enums in constfns + const fn constfn_eq(self, other: Self) -> bool { + matches!( + (self, other), + (Input::Zero, Input::Zero) + | (Input::One, Input::One) + | (Input::Any, Input::Any) + | (Input::OneNonZero, Input::OneNonZero) + | (Input::AnyNonZero, Input::AnyNonZero) + ) + } + /// Check whether given `Input` is a subtype of `other`. That is, /// if some Input is `OneNonZero` then it must be `One`, hence `OneNonZero` is /// a subtype if `One`. Returns `true` for `a.is_subtype(a)`. - fn is_subtype(&self, other: Self) -> bool { + const fn is_subtype(&self, other: Self) -> bool { match (*self, other) { - (x, y) if x == y => true, + (x, y) if x.constfn_eq(y) => true, (Input::OneNonZero, Input::One) | (Input::OneNonZero, Input::AnyNonZero) | (_, Input::Any) => true, @@ -95,16 +106,15 @@ impl Correctness { /// This checks whether the argument `other` has attributes which are present /// in the given `Type`. This returns `true` on same arguments /// `a.is_subtype(a)` is `true`. - pub fn is_subtype(&self, other: Self) -> bool { - self.base == other.base + pub const fn is_subtype(&self, other: Self) -> bool { + self.base as u8 == other.base as u8 && self.input.is_subtype(other.input) && self.dissatisfiable >= other.dissatisfiable && self.unit >= other.unit } -} -impl Property for Correctness { - fn sanity_checks(&self) { + /// Confirm invariants of the correctness checker. + pub fn sanity_checks(&self) { match self.base { Base::B => {} Base::K => { @@ -115,21 +125,19 @@ impl Property for Correctness { debug_assert!(!self.dissatisfiable); } Base::W => { - debug_assert!(self.input != Input::OneNonZero); - debug_assert!(self.input != Input::AnyNonZero); + debug_assert!(!self.input.constfn_eq(Input::OneNonZero)); + debug_assert!(!self.input.constfn_eq(Input::AnyNonZero)); } } } - fn from_true() -> Self { Self::TRUE } - - fn from_false() -> Self { Self::FALSE } - - fn from_pk_k() -> Self { + /// Constructor for the correctness properties of the `pk_k` fragment. + pub const fn pk_k() -> Self { Correctness { base: Base::K, input: Input::OneNonZero, dissatisfiable: true, unit: true } } - fn from_pk_h() -> Self { + /// Constructor for the correctness properties of the `pk_h` fragment. + pub const fn pk_h() -> Self { Correctness { base: Base::K, input: Input::AnyNonZero, @@ -138,23 +146,28 @@ impl Property for Correctness { } } - fn from_multi(_: usize, _: usize) -> Self { + /// Constructor for the correctness properties of the `multi` fragment. + pub const fn multi() -> Self { Correctness { base: Base::B, input: Input::AnyNonZero, dissatisfiable: true, unit: true } } - fn from_multi_a(_: usize, _: usize) -> Self { + /// Constructor for the correctness properties of the `multi_a` fragment. + pub const fn multi_a() -> Self { Correctness { base: Base::B, input: Input::Any, dissatisfiable: true, unit: true } } - fn from_hash() -> Self { + /// Constructor for the correctness properties of any of the hash fragments. + pub const fn hash() -> Self { Correctness { base: Base::B, input: Input::OneNonZero, dissatisfiable: true, unit: true } } - fn from_time(_: u32) -> Self { + /// Constructor for the correctness properties of either of the time fragments. + pub const fn time() -> Self { Correctness { base: Base::B, input: Input::Zero, dissatisfiable: false, unit: false } } - fn cast_alt(self) -> Result { + /// Constructor for the correctness properties of the `a:` fragment. + pub const fn cast_alt(self) -> Result { Ok(Correctness { base: match self.base { Base::B => Base::W, @@ -166,7 +179,8 @@ impl Property for Correctness { }) } - fn cast_swap(self) -> Result { + /// Constructor for the correctness properties of the `s:` fragment. + pub const fn cast_swap(self) -> Result { Ok(Correctness { base: match self.base { Base::B => Base::W, @@ -181,7 +195,8 @@ impl Property for Correctness { }) } - fn cast_check(self) -> Result { + /// Constructor for the correctness properties of the `c:` fragment. + pub const fn cast_check(self) -> Result { Ok(Correctness { base: match self.base { Base::K => Base::B, @@ -193,7 +208,8 @@ impl Property for Correctness { }) } - fn cast_dupif(self) -> Result { + /// Constructor for the correctness properties of the `d:` fragment. + pub const fn cast_dupif(self) -> Result { Ok(Correctness { base: match self.base { Base::V => Base::B, @@ -208,7 +224,8 @@ impl Property for Correctness { }) } - fn cast_verify(self) -> Result { + /// Constructor for the correctness properties of the `v:` fragment. + pub const fn cast_verify(self) -> Result { Ok(Correctness { base: match self.base { Base::B => Base::V, @@ -220,8 +237,9 @@ impl Property for Correctness { }) } - fn cast_nonzero(self) -> Result { - if self.input != Input::OneNonZero && self.input != Input::AnyNonZero { + /// Constructor for the correctness properties of the `j:` fragment. + pub const fn cast_nonzero(self) -> Result { + if !self.input.constfn_eq(Input::OneNonZero) && !self.input.constfn_eq(Input::AnyNonZero) { return Err(ErrorKind::NonZeroZero); } Ok(Correctness { @@ -235,7 +253,8 @@ impl Property for Correctness { }) } - fn cast_zeronotequal(self) -> Result { + /// Constructor for the correctness properties of the `n:` fragment. + pub const fn cast_zeronotequal(self) -> Result { Ok(Correctness { base: match self.base { Base::B => Base::B, @@ -247,7 +266,8 @@ impl Property for Correctness { }) } - fn cast_true(self) -> Result { + /// Constructor for the correctness properties of the `t:` fragment. + pub const fn cast_true(self) -> Result { Ok(Correctness { base: match self.base { Base::V => Base::B, @@ -259,7 +279,8 @@ impl Property for Correctness { }) } - fn cast_or_i_false(self) -> Result { + /// Constructor for the correctness properties of the `l:` and `u:` fragments. + pub const fn cast_or_i_false(self) -> Result { Ok(Correctness { base: match self.base { Base::B => Base::B, @@ -276,7 +297,8 @@ impl Property for Correctness { }) } - fn and_b(left: Self, right: Self) -> Result { + /// Constructor for the correctness properties of the `and_b` fragment + pub const fn and_b(left: Self, right: Self) -> Result { Ok(Correctness { base: match (left.base, right.base) { (Base::B, Base::W) => Base::B, @@ -298,7 +320,8 @@ impl Property for Correctness { }) } - fn and_v(left: Self, right: Self) -> Result { + /// Constructor for the correctness properties of the `and_v` fragment + pub const fn and_v(left: Self, right: Self) -> Result { Ok(Correctness { base: match (left.base, right.base) { (Base::V, Base::B) => Base::B, @@ -322,7 +345,8 @@ impl Property for Correctness { }) } - fn or_b(left: Self, right: Self) -> Result { + /// Constructor for the correctness properties of the `or_b` fragment + pub const fn or_b(left: Self, right: Self) -> Result { if !left.dissatisfiable { return Err(ErrorKind::LeftNotDissatisfiable); } @@ -347,7 +371,8 @@ impl Property for Correctness { }) } - fn or_d(left: Self, right: Self) -> Result { + /// Constructor for the correctness properties of the `or_d` fragment + pub const fn or_d(left: Self, right: Self) -> Result { if !left.dissatisfiable { return Err(ErrorKind::LeftNotDissatisfiable); } @@ -369,7 +394,8 @@ impl Property for Correctness { }) } - fn or_c(left: Self, right: Self) -> Result { + /// Constructor for the correctness properties of the `or_c` fragment + pub const fn or_c(left: Self, right: Self) -> Result { if !left.dissatisfiable { return Err(ErrorKind::LeftNotDissatisfiable); } @@ -391,7 +417,8 @@ impl Property for Correctness { }) } - fn or_i(left: Self, right: Self) -> Result { + /// Constructor for the correctness properties of the `or_i` fragment + pub const fn or_i(left: Self, right: Self) -> Result { Ok(Correctness { base: match (left.base, right.base) { (Base::B, Base::B) => Base::B, @@ -408,7 +435,8 @@ impl Property for Correctness { }) } - fn and_or(a: Self, b: Self, c: Self) -> Result { + /// Constructor for the correctness properties of the `andor` fragment + pub const fn and_or(a: Self, b: Self, c: Self) -> Result { if !a.dissatisfiable { return Err(ErrorKind::LeftNotDissatisfiable); } @@ -437,13 +465,15 @@ impl Property for Correctness { }) } - fn threshold(_k: usize, n: usize, mut sub_ck: S) -> Result + /// Constructor for the correctness properties of the `thresh` fragment + // Cannot be constfn because it takes a closure. + pub fn threshold(_k: usize, n: usize, mut sub_ck: S) -> Result where - S: FnMut(usize) -> Result, + S: FnMut(usize) -> Self, { let mut num_args = 0; for i in 0..n { - let subtype = sub_ck(i)?; + let subtype = sub_ck(i); num_args += match subtype.input { Input::Zero => 0, Input::One | Input::OneNonZero => 1, diff --git a/src/miniscript/types/extra_props.rs b/src/miniscript/types/extra_props.rs index 9d57b2df6..9d8c9274c 100644 --- a/src/miniscript/types/extra_props.rs +++ b/src/miniscript/types/extra_props.rs @@ -8,7 +8,7 @@ use core::iter::once; use bitcoin::{absolute, Sequence}; -use super::{Error, ErrorKind, Property, ScriptContext}; +use super::{Error, ErrorKind, ScriptContext}; use crate::miniscript::context::SigType; use crate::prelude::*; use crate::{script_num_size, MiniscriptKey, Terminal}; @@ -174,8 +174,9 @@ impl ExtData { }; } -impl Property for ExtData { - fn sanity_checks(&self) { +impl ExtData { + /// Confirm invariants of the extra property checker. + pub fn sanity_checks(&self) { debug_assert_eq!( self.stack_elem_count_sat.is_some(), self.exec_stack_elem_count_sat.is_some() @@ -186,11 +187,8 @@ impl Property for ExtData { ); } - fn from_true() -> Self { Self::TRUE } - - fn from_false() -> Self { Self::FALSE } - - fn from_pk_k() -> Self { + /// Extra properties for the `pk_k` fragment. + pub fn pk_k() -> Self { ExtData { pk_cost: match Ctx::sig_type() { SigType::Ecdsa => 34, @@ -211,7 +209,8 @@ impl Property for ExtData { } } - fn from_pk_h() -> Self { + /// Extra properties for the `pk_h` fragment. + pub fn pk_h() -> Self { ExtData { pk_cost: 24, has_free_verify: false, @@ -232,7 +231,8 @@ impl Property for ExtData { } } - fn from_multi(k: usize, n: usize) -> Self { + /// Extra properties for the `multi` fragment. + pub fn multi(k: usize, n: usize) -> Self { let num_cost = match (k > 16, n > 16) { (true, true) => 4, (false, true) => 3, @@ -249,13 +249,14 @@ impl Property for ExtData { stack_elem_count_dissat: Some(k + 1), max_sat_size: Some((1 + 73 * k, 1 + 73 * k)), max_dissat_size: Some((1 + k, 1 + k)), - timelock_info: TimelockInfo::default(), + timelock_info: TimelockInfo::new(), exec_stack_elem_count_sat: Some(n), // n pks exec_stack_elem_count_dissat: Some(n), } } - fn from_multi_a(k: usize, n: usize) -> Self { + /// Extra properties for the `multi_a` fragment. + pub fn multi_a(k: usize, n: usize) -> Self { let num_cost = match (k > 16, n > 16) { (true, true) => 4, (false, true) => 3, @@ -271,18 +272,14 @@ impl Property for ExtData { stack_elem_count_dissat: Some(n), max_sat_size: Some(((n - k) + 66 * k, (n - k) + 66 * k)), max_dissat_size: Some((n, n)), - timelock_info: TimelockInfo::default(), + timelock_info: TimelockInfo::new(), exec_stack_elem_count_sat: Some(2), // the two nums before num equal verify exec_stack_elem_count_dissat: Some(2), } } - fn from_hash() -> Self { - //never called directly - unreachable!() - } - - fn from_sha256() -> Self { + /// Extra properties for the `sha256` fragment. + pub const fn sha256() -> Self { ExtData { pk_cost: 33 + 6, has_free_verify: true, @@ -291,13 +288,14 @@ impl Property for ExtData { stack_elem_count_dissat: Some(1), max_sat_size: Some((33, 33)), max_dissat_size: Some((33, 33)), - timelock_info: TimelockInfo::default(), + timelock_info: TimelockInfo::new(), exec_stack_elem_count_sat: Some(2), // either size <32> or <32 byte> exec_stack_elem_count_dissat: Some(2), } } - fn from_hash256() -> Self { + /// Extra properties for the `hash256` fragment. + pub const fn hash256() -> Self { ExtData { pk_cost: 33 + 6, has_free_verify: true, @@ -306,13 +304,14 @@ impl Property for ExtData { stack_elem_count_dissat: Some(1), max_sat_size: Some((33, 33)), max_dissat_size: Some((33, 33)), - timelock_info: TimelockInfo::default(), + timelock_info: TimelockInfo::new(), exec_stack_elem_count_sat: Some(2), // either size <32> or <32 byte> exec_stack_elem_count_dissat: Some(2), } } - fn from_ripemd160() -> Self { + /// Extra properties for the `ripemd160` fragment. + pub const fn ripemd160() -> Self { ExtData { pk_cost: 21 + 6, has_free_verify: true, @@ -321,13 +320,14 @@ impl Property for ExtData { stack_elem_count_dissat: Some(1), max_sat_size: Some((33, 33)), max_dissat_size: Some((33, 33)), - timelock_info: TimelockInfo::default(), + timelock_info: TimelockInfo::new(), exec_stack_elem_count_sat: Some(2), // either size <32> or <20 byte> exec_stack_elem_count_dissat: Some(2), } } - fn from_hash160() -> Self { + /// Extra properties for the `hash160` fragment. + pub const fn hash160() -> Self { ExtData { pk_cost: 21 + 6, has_free_verify: true, @@ -336,15 +336,14 @@ impl Property for ExtData { stack_elem_count_dissat: Some(1), max_sat_size: Some((33, 33)), max_dissat_size: Some((33, 33)), - timelock_info: TimelockInfo::default(), + timelock_info: TimelockInfo::new(), exec_stack_elem_count_sat: Some(2), // either size <32> or <20 byte> exec_stack_elem_count_dissat: Some(2), } } - fn from_time(_t: u32) -> Self { unreachable!() } - - fn from_after(t: absolute::LockTime) -> Self { + /// Extra properties for the `after` fragment. + pub fn after(t: absolute::LockTime) -> Self { ExtData { pk_cost: script_num_size(t.to_consensus_u32() as usize) + 1, has_free_verify: false, @@ -365,7 +364,8 @@ impl Property for ExtData { } } - fn from_older(t: Sequence) -> Self { + /// Extra properties for the `older` fragment. + pub fn older(t: Sequence) -> Self { ExtData { pk_cost: script_num_size(t.to_consensus_u32() as usize) + 1, has_free_verify: false, @@ -386,8 +386,9 @@ impl Property for ExtData { } } - fn cast_alt(self) -> Result { - Ok(ExtData { + /// Extra properties for the `a:` fragment. + pub const fn cast_alt(self) -> Self { + ExtData { pk_cost: self.pk_cost + 2, has_free_verify: false, ops: OpLimits::new(2 + self.ops.count, self.ops.sat, self.ops.nsat), @@ -398,11 +399,12 @@ impl Property for ExtData { timelock_info: self.timelock_info, exec_stack_elem_count_sat: self.exec_stack_elem_count_sat, exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat, - }) + } } - fn cast_swap(self) -> Result { - Ok(ExtData { + /// Extra properties for the `s:` fragment. + pub const fn cast_swap(self) -> Self { + ExtData { pk_cost: self.pk_cost + 1, has_free_verify: self.has_free_verify, ops: OpLimits::new(1 + self.ops.count, self.ops.sat, self.ops.nsat), @@ -413,11 +415,12 @@ impl Property for ExtData { timelock_info: self.timelock_info, exec_stack_elem_count_sat: self.exec_stack_elem_count_sat, exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat, - }) + } } - fn cast_check(self) -> Result { - Ok(ExtData { + /// Extra properties for the `c:` fragment. + pub const fn cast_check(self) -> Self { + ExtData { pk_cost: self.pk_cost + 1, has_free_verify: true, ops: OpLimits::new(1 + self.ops.count, self.ops.sat, self.ops.nsat), @@ -428,11 +431,12 @@ impl Property for ExtData { timelock_info: self.timelock_info, exec_stack_elem_count_sat: self.exec_stack_elem_count_sat, exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat, - }) + } } - fn cast_dupif(self) -> Result { - Ok(ExtData { + /// Extra properties for the `d:` fragment. + pub fn cast_dupif(self) -> Self { + ExtData { pk_cost: self.pk_cost + 3, has_free_verify: false, ops: OpLimits::new(3 + self.ops.count, self.ops.sat, Some(0)), @@ -446,12 +450,13 @@ impl Property for ExtData { // Even all V types push something onto the stack and then remove them exec_stack_elem_count_sat: self.exec_stack_elem_count_sat, exec_stack_elem_count_dissat: Some(1), - }) + } } - fn cast_verify(self) -> Result { + /// Extra properties for the `v:` fragment. + pub fn cast_verify(self) -> Self { let verify_cost = usize::from(!self.has_free_verify); - Ok(ExtData { + ExtData { pk_cost: self.pk_cost + usize::from(!self.has_free_verify), has_free_verify: false, ops: OpLimits::new(verify_cost + self.ops.count, self.ops.sat, None), @@ -462,11 +467,12 @@ impl Property for ExtData { timelock_info: self.timelock_info, exec_stack_elem_count_sat: self.exec_stack_elem_count_sat, exec_stack_elem_count_dissat: None, - }) + } } - fn cast_nonzero(self) -> Result { - Ok(ExtData { + /// Extra properties for the `j:` fragment. + pub const fn cast_nonzero(self) -> Self { + ExtData { pk_cost: self.pk_cost + 4, has_free_verify: false, ops: OpLimits::new(4 + self.ops.count, self.ops.sat, Some(0)), @@ -477,11 +483,12 @@ impl Property for ExtData { timelock_info: self.timelock_info, exec_stack_elem_count_sat: self.exec_stack_elem_count_sat, exec_stack_elem_count_dissat: Some(1), - }) + } } - fn cast_zeronotequal(self) -> Result { - Ok(ExtData { + /// Extra properties for the `n:` fragment. + pub const fn cast_zeronotequal(self) -> Self { + ExtData { pk_cost: self.pk_cost + 1, has_free_verify: false, ops: OpLimits::new(1 + self.ops.count, self.ops.sat, self.ops.nsat), @@ -493,16 +500,23 @@ impl Property for ExtData { // Technically max(1, self.exec_stack_elem_count_sat), same rationale as cast_dupif exec_stack_elem_count_sat: self.exec_stack_elem_count_sat, exec_stack_elem_count_dissat: self.exec_stack_elem_count_dissat, - }) + } } - fn cast_or_i_false(self) -> Result { - // never called directly - unreachable!() - } + /// Cast by changing `[X]` to `AndV([X], True)` + pub fn cast_true(self) -> Self { Self::and_v(self, Self::TRUE) } + + /// Cast by changing `[X]` to `or_i([X], 0)`. Default implementation + /// simply passes through to `cast_or_i_false` + pub fn cast_unlikely(self) -> Self { Self::or_i(self, Self::FALSE) } - fn and_b(l: Self, r: Self) -> Result { - Ok(ExtData { + /// Cast by changing `[X]` to `or_i(0, [X])`. Default implementation + /// simply passes through to `cast_or_i_false` + pub fn cast_likely(self) -> Self { Self::or_i(Self::FALSE, self) } + + /// Extra properties for the `and_b` fragment. + pub fn and_b(l: Self, r: Self) -> Self { + ExtData { pk_cost: l.pk_cost + r.pk_cost + 1, has_free_verify: false, ops: OpLimits::new( @@ -533,11 +547,12 @@ impl Property for ExtData { l.exec_stack_elem_count_dissat, r.exec_stack_elem_count_dissat.map(|x| x + 1), ), - }) + } } - fn and_v(l: Self, r: Self) -> Result { - Ok(ExtData { + /// Extra properties for the `and_v` fragment. + pub fn and_v(l: Self, r: Self) -> Self { + ExtData { pk_cost: l.pk_cost + r.pk_cost, has_free_verify: r.has_free_verify, ops: OpLimits::new(l.ops.count + r.ops.count, opt_add(l.ops.sat, r.ops.sat), None), @@ -556,11 +571,12 @@ impl Property for ExtData { r.exec_stack_elem_count_sat, ), exec_stack_elem_count_dissat: None, - }) + } } - fn or_b(l: Self, r: Self) -> Result { - Ok(ExtData { + /// Extra properties for the `or_b` fragment. + pub fn or_b(l: Self, r: Self) -> Self { + ExtData { pk_cost: l.pk_cost + r.pk_cost + 1, has_free_verify: false, ops: OpLimits::new( @@ -595,11 +611,12 @@ impl Property for ExtData { l.exec_stack_elem_count_dissat, r.exec_stack_elem_count_dissat.map(|x| x + 1), ), - }) + } } - fn or_d(l: Self, r: Self) -> Result { - let res = ExtData { + /// Extra properties for the `or_d` fragment. + pub fn or_d(l: Self, r: Self) -> Self { + ExtData { pk_cost: l.pk_cost + r.pk_cost + 3, has_free_verify: false, ops: OpLimits::new( @@ -632,12 +649,12 @@ impl Property for ExtData { l.exec_stack_elem_count_dissat, r.exec_stack_elem_count_dissat.map(|x| x + 1), ), - }; - Ok(res) + } } - fn or_c(l: Self, r: Self) -> Result { - Ok(ExtData { + /// Extra properties for the `or_c` fragment. + pub fn or_c(l: Self, r: Self) -> Self { + ExtData { pk_cost: l.pk_cost + r.pk_cost + 2, has_free_verify: false, ops: OpLimits::new( @@ -663,11 +680,12 @@ impl Property for ExtData { opt_max(r.exec_stack_elem_count_sat, l.exec_stack_elem_count_dissat), ), exec_stack_elem_count_dissat: None, - }) + } } - fn or_i(l: Self, r: Self) -> Result { - Ok(ExtData { + /// Extra properties for the `or_i` fragment. + pub fn or_i(l: Self, r: Self) -> Self { + ExtData { pk_cost: l.pk_cost + r.pk_cost + 3, has_free_verify: false, ops: OpLimits::new( @@ -709,11 +727,12 @@ impl Property for ExtData { l.exec_stack_elem_count_dissat, r.exec_stack_elem_count_dissat, ), - }) + } } - fn and_or(a: Self, b: Self, c: Self) -> Result { - Ok(ExtData { + /// Extra properties for the `andor` fragment. + pub fn and_or(a: Self, b: Self, c: Self) -> Self { + ExtData { pk_cost: a.pk_cost + b.pk_cost + c.pk_cost + 3, has_free_verify: false, ops: OpLimits::new( @@ -751,12 +770,13 @@ impl Property for ExtData { a.exec_stack_elem_count_dissat, c.exec_stack_elem_count_dissat, ), - }) + } } - fn threshold(k: usize, n: usize, mut sub_ck: S) -> Result + /// Extra properties for the `thresh` fragment. + pub fn threshold(k: usize, n: usize, mut sub_ck: S) -> Self where - S: FnMut(usize) -> Result, + S: FnMut(usize) -> Self, { let mut pk_cost = 1 + script_num_size(k); //Equal and k let mut ops_count = 0; @@ -772,7 +792,7 @@ impl Property for ExtData { let mut exec_stack_elem_count_dissat = Some(0); for i in 0..n { - let sub = sub_ck(i)?; + let sub = sub_ck(i); pk_cost += sub.pk_cost; ops_count += sub.ops.count; @@ -854,7 +874,7 @@ impl Property for ExtData { } }); - Ok(ExtData { + ExtData { pk_cost: pk_cost + n - 1, //all pk cost + (n-1)*ADD has_free_verify: true, ops: OpLimits::new( @@ -869,11 +889,9 @@ impl Property for ExtData { timelock_info: TimelockInfo::combine_threshold(k, timelocks), exec_stack_elem_count_sat, exec_stack_elem_count_dissat, - }) + } } -} -impl ExtData { /// Compute the type of a fragment assuming all the children of /// Miniscript have been computed already. pub fn type_check(fragment: &Terminal) -> Result @@ -881,15 +899,11 @@ impl ExtData { Ctx: ScriptContext, Pk: MiniscriptKey, { - let wrap_err = |result: Result| { - result.map_err(|kind| Error { fragment_string: fragment.to_string(), error: kind }) - }; - let ret = match *fragment { - Terminal::True => Ok(Self::from_true()), - Terminal::False => Ok(Self::from_false()), - Terminal::PkK(..) => Ok(Self::from_pk_k::()), - Terminal::PkH(..) | Terminal::RawPkH(..) => Ok(Self::from_pk_h::()), + Terminal::True => Self::TRUE, + Terminal::False => Self::FALSE, + Terminal::PkK(..) => Self::pk_k::(), + Terminal::PkH(..) | Terminal::RawPkH(..) => Self::pk_h::(), Terminal::Multi(k, ref pks) | Terminal::MultiA(k, ref pks) => { if k == 0 { return Err(Error { @@ -904,8 +918,8 @@ impl ExtData { }); } match *fragment { - Terminal::Multi(..) => Ok(Self::from_multi(k, pks.len())), - Terminal::MultiA(..) => Ok(Self::from_multi_a(k, pks.len())), + Terminal::Multi(..) => Self::multi(k, pks.len()), + Terminal::MultiA(..) => Self::multi_a(k, pks.len()), _ => unreachable!(), } } @@ -919,7 +933,7 @@ impl ExtData { error: ErrorKind::InvalidTime, }); } - Ok(Self::from_after(t.into())) + Self::after(t.into()) } Terminal::Older(t) => { if t == Sequence::ZERO || !t.is_relative_lock_time() { @@ -928,54 +942,54 @@ impl ExtData { error: ErrorKind::InvalidTime, }); } - Ok(Self::from_older(t)) + Self::older(t) } - Terminal::Sha256(..) => Ok(Self::from_sha256()), - Terminal::Hash256(..) => Ok(Self::from_hash256()), - Terminal::Ripemd160(..) => Ok(Self::from_ripemd160()), - Terminal::Hash160(..) => Ok(Self::from_hash160()), - Terminal::Alt(ref sub) => wrap_err(Self::cast_alt(sub.ext)), - Terminal::Swap(ref sub) => wrap_err(Self::cast_swap(sub.ext)), - Terminal::Check(ref sub) => wrap_err(Self::cast_check(sub.ext)), - Terminal::DupIf(ref sub) => wrap_err(Self::cast_dupif(sub.ext)), - Terminal::Verify(ref sub) => wrap_err(Self::cast_verify(sub.ext)), - Terminal::NonZero(ref sub) => wrap_err(Self::cast_nonzero(sub.ext)), - Terminal::ZeroNotEqual(ref sub) => wrap_err(Self::cast_zeronotequal(sub.ext)), + Terminal::Sha256(..) => Self::sha256(), + Terminal::Hash256(..) => Self::hash256(), + Terminal::Ripemd160(..) => Self::ripemd160(), + Terminal::Hash160(..) => Self::hash160(), + Terminal::Alt(ref sub) => Self::cast_alt(sub.ext), + Terminal::Swap(ref sub) => Self::cast_swap(sub.ext), + Terminal::Check(ref sub) => Self::cast_check(sub.ext), + Terminal::DupIf(ref sub) => Self::cast_dupif(sub.ext), + Terminal::Verify(ref sub) => Self::cast_verify(sub.ext), + Terminal::NonZero(ref sub) => Self::cast_nonzero(sub.ext), + Terminal::ZeroNotEqual(ref sub) => Self::cast_zeronotequal(sub.ext), Terminal::AndB(ref l, ref r) => { let ltype = l.ext; let rtype = r.ext; - wrap_err(Self::and_b(ltype, rtype)) + Self::and_b(ltype, rtype) } Terminal::AndV(ref l, ref r) => { let ltype = l.ext; let rtype = r.ext; - wrap_err(Self::and_v(ltype, rtype)) + Self::and_v(ltype, rtype) } Terminal::OrB(ref l, ref r) => { let ltype = l.ext; let rtype = r.ext; - wrap_err(Self::or_b(ltype, rtype)) + Self::or_b(ltype, rtype) } Terminal::OrD(ref l, ref r) => { let ltype = l.ext; let rtype = r.ext; - wrap_err(Self::or_d(ltype, rtype)) + Self::or_d(ltype, rtype) } Terminal::OrC(ref l, ref r) => { let ltype = l.ext; let rtype = r.ext; - wrap_err(Self::or_c(ltype, rtype)) + Self::or_c(ltype, rtype) } Terminal::OrI(ref l, ref r) => { let ltype = l.ext; let rtype = r.ext; - wrap_err(Self::or_i(ltype, rtype)) + Self::or_i(ltype, rtype) } Terminal::AndOr(ref a, ref b, ref c) => { let atype = a.ext; let btype = b.ext; let ctype = c.ext; - wrap_err(Self::and_or(atype, btype, ctype)) + Self::and_or(atype, btype, ctype) } Terminal::Thresh(k, ref subs) => { if k == 0 { @@ -991,15 +1005,11 @@ impl ExtData { }); } - let res = Self::threshold(k, subs.len(), |n| Ok(subs[n].ext)); - - res.map_err(|kind| Error { fragment_string: fragment.to_string(), error: kind }) + Self::threshold(k, subs.len(), |n| subs[n].ext) } }; - if let Ok(ref ret) = ret { - ret.sanity_checks() - } - ret + ret.sanity_checks(); + Ok(ret) } } diff --git a/src/miniscript/types/malleability.rs b/src/miniscript/types/malleability.rs index 71d644d97..4285e2ac3 100644 --- a/src/miniscript/types/malleability.rs +++ b/src/miniscript/types/malleability.rs @@ -2,9 +2,6 @@ //! Malleability-related Type properties -use super::{ErrorKind, Property}; -use crate::ScriptContext; - /// Whether the fragment has a dissatisfaction, and if so, whether /// it is unique. Affects both correctness and malleability-freeness, /// since we assume 3rd parties are able to produce dissatisfactions @@ -27,11 +24,21 @@ pub enum Dissat { } impl Dissat { + // FIXME rustc should eventually support derived == on enums in constfns + const fn constfn_eq(self, other: Self) -> bool { + matches!( + (self, other), + (Dissat::None, Dissat::None) + | (Dissat::Unique, Dissat::Unique) + | (Dissat::Unknown, Dissat::Unknown) + ) + } + /// Check whether given `Dissat` is a subtype of `other`. That is, /// if some Dissat is `Unique` then it must be `Unknown`. - fn is_subtype(&self, other: Self) -> bool { + const fn is_subtype(&self, other: Self) -> bool { match (*self, other) { - (x, y) if x == y => true, + (x, y) if x.constfn_eq(y) => true, (_, Dissat::Unknown) => true, _ => false, } @@ -66,108 +73,108 @@ impl Malleability { /// This checks whether the argument `other` has attributes which are present /// in the given `Type`. This returns `true` on same arguments /// `a.is_subtype(a)` is `true`. - pub fn is_subtype(&self, other: Self) -> bool { + pub const fn is_subtype(&self, other: Self) -> bool { self.dissat.is_subtype(other.dissat) && self.safe >= other.safe && self.non_malleable >= other.non_malleable } } -impl Property for Malleability { - fn from_true() -> Self { - Malleability { dissat: Dissat::None, safe: false, non_malleable: true } - } - - fn from_false() -> Self { - Malleability { dissat: Dissat::Unique, safe: true, non_malleable: true } - } - - fn from_pk_k() -> Self { +impl Malleability { + /// Constructor for the malleabilitiy properties of the `pk_k` fragment. + pub const fn pk_k() -> Self { Malleability { dissat: Dissat::Unique, safe: true, non_malleable: true } } - fn from_pk_h() -> Self { + /// Constructor for the malleabilitiy properties of the `pk_h` fragment. + pub const fn pk_h() -> Self { Malleability { dissat: Dissat::Unique, safe: true, non_malleable: true } } - fn from_multi(_: usize, _: usize) -> Self { + /// Constructor for the malleabilitiy properties of the `multi` fragment. + pub const fn multi() -> Self { Malleability { dissat: Dissat::Unique, safe: true, non_malleable: true } } - fn from_multi_a(_: usize, _: usize) -> Self { + /// Constructor for the malleabilitiy properties of the `multi_a` fragment. + pub const fn multi_a() -> Self { Malleability { dissat: Dissat::Unique, safe: true, non_malleable: true } } - fn from_hash() -> Self { + /// Constructor for the malleabilitiy properties of any of the hash fragments. + pub const fn hash() -> Self { Malleability { dissat: Dissat::Unknown, safe: false, non_malleable: true } } - fn from_time(_: u32) -> Self { + /// Constructor for the malleabilitiy properties of either `after` or `older`. + pub const fn time() -> Self { Malleability { dissat: Dissat::None, safe: false, non_malleable: true } } - fn cast_alt(self) -> Result { Ok(self) } + /// Constructor for the malleabilitiy properties of the `a:` fragment. + pub const fn cast_alt(self) -> Self { self } - fn cast_swap(self) -> Result { Ok(self) } + /// Constructor for the malleabilitiy properties of the `s:` fragment. + pub const fn cast_swap(self) -> Self { self } - fn cast_check(self) -> Result { Ok(self) } + /// Constructor for the malleabilitiy properties of the `c:` fragment. + pub const fn cast_check(self) -> Self { self } - fn cast_dupif(self) -> Result { - Ok(Malleability { - dissat: if self.dissat == Dissat::None { + /// Constructor for the malleabilitiy properties of the `d:` fragment. + pub const fn cast_dupif(self) -> Self { + Malleability { + dissat: if self.dissat.constfn_eq(Dissat::None) { Dissat::Unique } else { Dissat::Unknown }, safe: self.safe, non_malleable: self.non_malleable, - }) + } } - fn cast_verify(self) -> Result { - Ok(Malleability { - dissat: Dissat::None, - safe: self.safe, - non_malleable: self.non_malleable, - }) + /// Constructor for the malleabilitiy properties of the `v:` fragment. + pub const fn cast_verify(self) -> Self { + Malleability { dissat: Dissat::None, safe: self.safe, non_malleable: self.non_malleable } } - fn cast_nonzero(self) -> Result { - Ok(Malleability { - dissat: if self.dissat == Dissat::None { + /// Constructor for the malleabilitiy properties of the `j:` fragment. + pub const fn cast_nonzero(self) -> Self { + Malleability { + dissat: if self.dissat.constfn_eq(Dissat::None) { Dissat::Unique } else { Dissat::Unknown }, safe: self.safe, non_malleable: self.non_malleable, - }) + } } - fn cast_zeronotequal(self) -> Result { Ok(self) } + /// Constructor for the malleabilitiy properties of the `n:` fragment. + pub const fn cast_zeronotequal(self) -> Self { self } - fn cast_true(self) -> Result { - Ok(Malleability { - dissat: Dissat::None, - safe: self.safe, - non_malleable: self.non_malleable, - }) + /// Constructor for the malleabilitiy properties of the `t:` fragment. + pub const fn cast_true(self) -> Self { + Malleability { dissat: Dissat::None, safe: self.safe, non_malleable: self.non_malleable } } - fn cast_or_i_false(self) -> Result { - Ok(Malleability { - dissat: if self.dissat == Dissat::None { + /// Constructor for the malleabilitiy properties of the `l:` or `u:` fragments. + pub const fn cast_or_i_false(self) -> Self { + Malleability { + dissat: if self.dissat.constfn_eq(Dissat::None) { Dissat::Unique } else { Dissat::Unknown }, safe: self.safe, non_malleable: self.non_malleable, - }) + } } - fn and_b(left: Self, right: Self) -> Result { - Ok(Malleability { + /// Constructor for the malleabilitiy properties of the `and_b` fragment. + pub const fn and_b(left: Self, right: Self) -> Self { + Malleability { dissat: match (left.dissat, right.dissat) { (Dissat::None, Dissat::None) => Dissat::None, (Dissat::None, _) if left.safe => Dissat::None, @@ -183,11 +190,12 @@ impl Property for Malleability { }, safe: left.safe || right.safe, non_malleable: left.non_malleable && right.non_malleable, - }) + } } - fn and_v(left: Self, right: Self) -> Result { - Ok(Malleability { + /// Constructor for the malleabilitiy properties of the `and_v` fragment. + pub const fn and_v(left: Self, right: Self) -> Self { + Malleability { dissat: match (left.safe, right.dissat) { (_, Dissat::None) => Dissat::None, // fy (true, _) => Dissat::None, // sx @@ -195,45 +203,49 @@ impl Property for Malleability { }, safe: left.safe || right.safe, non_malleable: left.non_malleable && right.non_malleable, - }) + } } - fn or_b(left: Self, right: Self) -> Result { - Ok(Malleability { + /// Constructor for the malleabilitiy properties of the `or_b` fragment. + pub const fn or_b(left: Self, right: Self) -> Self { + Malleability { dissat: Dissat::Unique, safe: left.safe && right.safe, non_malleable: left.non_malleable - && left.dissat == Dissat::Unique + && left.dissat.constfn_eq(Dissat::Unique) && right.non_malleable - && right.dissat == Dissat::Unique + && right.dissat.constfn_eq(Dissat::Unique) && (left.safe || right.safe), - }) + } } - fn or_d(left: Self, right: Self) -> Result { - Ok(Malleability { + /// Constructor for the malleabilitiy properties of the `or_d` fragment. + pub const fn or_d(left: Self, right: Self) -> Self { + Malleability { dissat: right.dissat, safe: left.safe && right.safe, non_malleable: left.non_malleable - && left.dissat == Dissat::Unique + && left.dissat.constfn_eq(Dissat::Unique) && right.non_malleable && (left.safe || right.safe), - }) + } } - fn or_c(left: Self, right: Self) -> Result { - Ok(Malleability { + /// Constructor for the malleabilitiy properties of the `or_c` fragment. + pub const fn or_c(left: Self, right: Self) -> Self { + Malleability { dissat: Dissat::None, safe: left.safe && right.safe, non_malleable: left.non_malleable - && left.dissat == Dissat::Unique + && left.dissat.constfn_eq(Dissat::Unique) && right.non_malleable && (left.safe || right.safe), - }) + } } - fn or_i(left: Self, right: Self) -> Result { - Ok(Malleability { + /// Constructor for the malleabilitiy properties of the `or_i` fragment. + pub const fn or_i(left: Self, right: Self) -> Self { + Malleability { dissat: match (left.dissat, right.dissat) { (Dissat::None, Dissat::None) => Dissat::None, (Dissat::Unique, Dissat::None) => Dissat::Unique, @@ -242,11 +254,12 @@ impl Property for Malleability { }, safe: left.safe && right.safe, non_malleable: left.non_malleable && right.non_malleable && (left.safe || right.safe), - }) + } } - fn and_or(a: Self, b: Self, c: Self) -> Result { - Ok(Malleability { + /// Constructor for the malleabilitiy properties of the `andor` fragment. + pub const fn and_or(a: Self, b: Self, c: Self) -> Self { + Malleability { dissat: match (a.safe, b.dissat, c.dissat) { (_, Dissat::None, Dissat::Unique) => Dissat::Unique, //E: ez fy (true, _, Dissat::Unique) => Dissat::Unique, // E: ez sx @@ -257,26 +270,28 @@ impl Property for Malleability { safe: (a.safe || b.safe) && c.safe, non_malleable: a.non_malleable && c.non_malleable - && a.dissat == Dissat::Unique + && a.dissat.constfn_eq(Dissat::Unique) && b.non_malleable && (a.safe || b.safe || c.safe), - }) + } } - fn threshold(k: usize, n: usize, mut sub_ck: S) -> Result + /// Constructor for the malleabilitiy properties of the `thresh` fragment. + // Cannot be constfn because it takes a closure. + pub fn threshold(k: usize, n: usize, mut sub_ck: S) -> Self where - S: FnMut(usize) -> Result, + S: FnMut(usize) -> Self, { let mut safe_count = 0; let mut all_are_dissat_unique = true; let mut all_are_non_malleable = true; for i in 0..n { - let subtype = sub_ck(i)?; + let subtype = sub_ck(i); safe_count += usize::from(subtype.safe); all_are_dissat_unique &= subtype.dissat == Dissat::Unique; all_are_non_malleable &= subtype.non_malleable; } - Ok(Malleability { + Malleability { dissat: if all_are_dissat_unique && safe_count == n { Dissat::Unique } else { @@ -284,6 +299,6 @@ impl Property for Malleability { }, safe: safe_count > n - k, non_malleable: all_are_non_malleable && safe_count >= n - k && all_are_dissat_unique, - }) + } } } diff --git a/src/miniscript/types/mod.rs b/src/miniscript/types/mod.rs index ae154e004..887aa8b8d 100644 --- a/src/miniscript/types/mod.rs +++ b/src/miniscript/types/mod.rs @@ -226,310 +226,251 @@ impl Type { /// This checks whether the argument `other` has attributes which are present /// in the given `Type`. This returns `true` on same arguments /// `a.is_subtype(a)` is `true`. - pub fn is_subtype(&self, other: Self) -> bool { + pub const fn is_subtype(&self, other: Self) -> bool { self.corr.is_subtype(other.corr) && self.mall.is_subtype(other.mall) } -} -/// Trait representing a type property, which defines how the property -/// propagates from terminals to the root of a Miniscript -pub trait Property: Sized { - /// Any extra sanity checks/assertions that should be applied after - /// typechecking - fn sanity_checks(&self) { - // no checks by default - } - - /// Type property of the `True` fragment - fn from_true() -> Self; - - /// Type property of the `False` fragment - fn from_false() -> Self; - - /// Type property of the `PkK` fragment - fn from_pk_k() -> Self; - - /// Type property of the `PkH` fragment - fn from_pk_h() -> Self; - - /// Type property of a `Multi` fragment - fn from_multi(k: usize, n: usize) -> Self; - - /// Type property of a `MultiA` fragment - fn from_multi_a(k: usize, n: usize) -> Self; - - /// Type property of a hash fragment - fn from_hash() -> Self; - - /// Type property of a `Sha256` hash. Default implementation simply - /// passes through to `from_hash` - fn from_sha256() -> Self { Self::from_hash() } - - /// Type property of a `Hash256` hash. Default implementation simply - /// passes through to `from_hash` - fn from_hash256() -> Self { Self::from_hash() } - - /// Type property of a `Ripemd160` hash. Default implementation simply - /// passes through to `from_hash` - fn from_ripemd160() -> Self { Self::from_hash() } - - /// Type property of a `Hash160` hash. Default implementation simply - /// passes through to `from_hash` - fn from_hash160() -> Self { Self::from_hash() } - - /// Type property of a timelock - fn from_time(t: u32) -> Self; - - /// Type property of an absolute timelock. Default implementation simply - /// passes through to `from_time` - fn from_after(t: absolute::LockTime) -> Self { Self::from_time(t.to_consensus_u32()) } - - /// Type property of a relative timelock. Default implementation simply - /// passes through to `from_time` - fn from_older(t: Sequence) -> Self { Self::from_time(t.to_consensus_u32()) } - - /// Cast using the `Alt` wrapper - fn cast_alt(self) -> Result; - - /// Cast using the `Swap` wrapper - fn cast_swap(self) -> Result; - - /// Cast using the `Check` wrapper - fn cast_check(self) -> Result; - - /// Cast using the `DupIf` wrapper - fn cast_dupif(self) -> Result; - - /// Cast using the `Verify` wrapper - fn cast_verify(self) -> Result; - - /// Cast using the `NonZero` wrapper - fn cast_nonzero(self) -> Result; - - /// Cast using the `ZeroNotEqual` wrapper - fn cast_zeronotequal(self) -> Result; - - /// Cast by changing `[X]` to `AndV([X], True)` - fn cast_true(self) -> Result { Self::and_v(self, Self::from_true()) } - - /// Cast by changing `[X]` to `or_i([X], 0)` or `or_i(0, [X])` - fn cast_or_i_false(self) -> Result; - - /// Cast by changing `[X]` to `or_i([X], 0)`. Default implementation - /// simply passes through to `cast_or_i_false` - fn cast_unlikely(self) -> Result { Self::or_i(self, Self::from_false()) } - - /// Cast by changing `[X]` to `or_i(0, [X])`. Default implementation - /// simply passes through to `cast_or_i_false` - fn cast_likely(self) -> Result { Self::or_i(Self::from_false(), self) } - - /// Computes the type of an `AndB` fragment - fn and_b(left: Self, right: Self) -> Result; - - /// Computes the type of an `AndV` fragment - fn and_v(left: Self, right: Self) -> Result; - - /// Computes the type of an `AndN` fragment - fn and_n(left: Self, right: Self) -> Result { - Self::and_or(left, right, Self::from_false()) - } - - /// Computes the type of an `OrB` fragment - fn or_b(left: Self, right: Self) -> Result; - - /// Computes the type of an `OrD` fragment - fn or_d(left: Self, right: Self) -> Result; - /// Computes the type of an `OrC` fragment - fn or_c(left: Self, right: Self) -> Result; - - /// Computes the type of an `OrI` fragment - fn or_i(left: Self, right: Self) -> Result; - - /// Computes the type of an `AndOr` fragment - fn and_or(a: Self, b: Self, c: Self) -> Result; - - /// Computes the type of an `Thresh` fragment - fn threshold(k: usize, n: usize, sub_ck: S) -> Result - where - S: FnMut(usize) -> Result; -} - -impl Property for Type { - fn sanity_checks(&self) { + /// Confirm invariants of the type checker. + pub fn sanity_checks(&self) { debug_assert!(!self.corr.dissatisfiable || self.mall.dissat != Dissat::None); debug_assert!(self.mall.dissat == Dissat::None || self.corr.base != Base::V); debug_assert!(self.mall.safe || self.corr.base != Base::K); debug_assert!(self.mall.non_malleable || self.corr.input != Input::Zero); } - fn from_true() -> Self { Type { corr: Property::from_true(), mall: Property::from_true() } } - - fn from_false() -> Self { Type { corr: Property::from_false(), mall: Property::from_false() } } + /// Constructor for the type of the `pk_k` fragment. + pub const fn pk_k() -> Self { Type { corr: Correctness::pk_k(), mall: Malleability::pk_k() } } - fn from_pk_k() -> Self { - Type { corr: Property::from_pk_k::(), mall: Property::from_pk_k::() } - } + /// Constructor for the type of the `pk_h` fragment. + pub const fn pk_h() -> Self { Type { corr: Correctness::pk_h(), mall: Malleability::pk_h() } } - fn from_pk_h() -> Self { - Type { corr: Property::from_pk_h::(), mall: Property::from_pk_h::() } + /// Constructor for the type of the `multi` fragment. + pub const fn multi() -> Self { + Type { corr: Correctness::multi(), mall: Malleability::multi() } } - fn from_multi(k: usize, n: usize) -> Self { - Type { corr: Property::from_multi(k, n), mall: Property::from_multi(k, n) } + /// Constructor for the type of the `multi_a` fragment. + pub const fn multi_a() -> Self { + Type { corr: Correctness::multi_a(), mall: Malleability::multi_a() } } - fn from_multi_a(k: usize, n: usize) -> Self { - Type { corr: Property::from_multi_a(k, n), mall: Property::from_multi_a(k, n) } - } + /// Constructor for the type of all the hash fragments. + pub const fn hash() -> Self { Type { corr: Correctness::hash(), mall: Malleability::hash() } } - fn from_hash() -> Self { Type { corr: Property::from_hash(), mall: Property::from_hash() } } - - fn from_sha256() -> Self { - Type { corr: Property::from_sha256(), mall: Property::from_sha256() } - } - - fn from_hash256() -> Self { - Type { corr: Property::from_hash256(), mall: Property::from_hash256() } - } - - fn from_ripemd160() -> Self { - Type { corr: Property::from_ripemd160(), mall: Property::from_ripemd160() } - } - - fn from_hash160() -> Self { - Type { corr: Property::from_hash160(), mall: Property::from_hash160() } - } + /// Constructor for the type of the `after` and `older` fragments. + pub const fn time() -> Self { Type { corr: Correctness::time(), mall: Malleability::time() } } - fn from_time(t: u32) -> Self { - Type { corr: Property::from_time(t), mall: Property::from_time(t) } - } - - fn from_after(t: absolute::LockTime) -> Self { - Type { corr: Property::from_after(t), mall: Property::from_after(t) } - } - - fn from_older(t: Sequence) -> Self { - Type { corr: Property::from_older(t), mall: Property::from_older(t) } - } - - fn cast_alt(self) -> Result { - Ok(Type { corr: Property::cast_alt(self.corr)?, mall: Property::cast_alt(self.mall)? }) - } - - fn cast_swap(self) -> Result { - Ok(Type { corr: Property::cast_swap(self.corr)?, mall: Property::cast_swap(self.mall)? }) + /// Constructor for the type of the `a:` fragment. + pub const fn cast_alt(self) -> Result { + // FIXME need to do manual `?` because ? is not supported in constfns. + Ok(Type { + corr: match Correctness::cast_alt(self.corr) { + Ok(x) => x, + Err(e) => return Err(e), + }, + mall: Malleability::cast_alt(self.mall), + }) } - fn cast_check(self) -> Result { - Ok(Type { corr: Property::cast_check(self.corr)?, mall: Property::cast_check(self.mall)? }) + /// Constructor for the type of the `s:` fragment. + pub const fn cast_swap(self) -> Result { + // FIXME need to do manual `?` because ? is not supported in constfns. + Ok(Type { + corr: match Correctness::cast_swap(self.corr) { + Ok(x) => x, + Err(e) => return Err(e), + }, + mall: Malleability::cast_swap(self.mall), + }) } - fn cast_dupif(self) -> Result { - Ok(Type { corr: Property::cast_dupif(self.corr)?, mall: Property::cast_dupif(self.mall)? }) + /// Constructor for the type of the `c:` fragment. + pub const fn cast_check(self) -> Result { + Ok(Type { + corr: match Correctness::cast_check(self.corr) { + Ok(x) => x, + Err(e) => return Err(e), + }, + mall: Malleability::cast_check(self.mall), + }) } - fn cast_verify(self) -> Result { + /// Constructor for the type of the `d:` fragment. + pub const fn cast_dupif(self) -> Result { + // FIXME need to do manual `?` because ? is not supported in constfns. Ok(Type { - corr: Property::cast_verify(self.corr)?, - mall: Property::cast_verify(self.mall)?, + corr: match Correctness::cast_dupif(self.corr) { + Ok(x) => x, + Err(e) => return Err(e), + }, + mall: Malleability::cast_dupif(self.mall), }) } - fn cast_nonzero(self) -> Result { + /// Constructor for the type of the `v:` fragment. + pub const fn cast_verify(self) -> Result { + // FIXME need to do manual `?` because ? is not supported in constfns. Ok(Type { - corr: Property::cast_nonzero(self.corr)?, - mall: Property::cast_nonzero(self.mall)?, + corr: match Correctness::cast_verify(self.corr) { + Ok(x) => x, + Err(e) => return Err(e), + }, + mall: Malleability::cast_verify(self.mall), }) } - fn cast_zeronotequal(self) -> Result { + /// Constructor for the type of the `j:` fragment. + pub const fn cast_nonzero(self) -> Result { + // FIXME need to do manual `?` because ? is not supported in constfns. Ok(Type { - corr: Property::cast_zeronotequal(self.corr)?, - mall: Property::cast_zeronotequal(self.mall)?, + corr: match Correctness::cast_nonzero(self.corr) { + Ok(x) => x, + Err(e) => return Err(e), + }, + mall: Malleability::cast_nonzero(self.mall), }) } - fn cast_true(self) -> Result { - Ok(Type { corr: Property::cast_true(self.corr)?, mall: Property::cast_true(self.mall)? }) + /// Constructor for the type of the `n:` fragment. + pub const fn cast_zeronotequal(self) -> Result { + // FIXME need to do manual `?` because ? is not supported in constfns. + Ok(Type { + corr: match Correctness::cast_zeronotequal(self.corr) { + Ok(x) => x, + Err(e) => return Err(e), + }, + mall: Malleability::cast_zeronotequal(self.mall), + }) } - fn cast_or_i_false(self) -> Result { + /// Constructor for the type of the `t:` fragment. + pub const fn cast_true(self) -> Result { + // FIXME need to do manual `?` because ? is not supported in constfns. Ok(Type { - corr: Property::cast_or_i_false(self.corr)?, - mall: Property::cast_or_i_false(self.mall)?, + corr: match Correctness::cast_true(self.corr) { + Ok(x) => x, + Err(e) => return Err(e), + }, + mall: Malleability::cast_true(self.mall), }) } - fn cast_unlikely(self) -> Result { + /// Constructor for the type of the `u:` fragment. + pub const fn cast_unlikely(self) -> Result { + // FIXME need to do manual `?` because ? is not supported in constfns. Ok(Type { - corr: Property::cast_unlikely(self.corr)?, - mall: Property::cast_unlikely(self.mall)?, + corr: match Correctness::cast_or_i_false(self.corr) { + Ok(x) => x, + Err(e) => return Err(e), + }, + mall: Malleability::cast_or_i_false(self.mall), }) } - fn cast_likely(self) -> Result { + /// Constructor for the type of the `l:` fragment. + pub const fn cast_likely(self) -> Result { + // FIXME need to do manual `?` because ? is not supported in constfns. Ok(Type { - corr: Property::cast_likely(self.corr)?, - mall: Property::cast_likely(self.mall)?, + corr: match Correctness::cast_or_i_false(self.corr) { + Ok(x) => x, + Err(e) => return Err(e), + }, + mall: Malleability::cast_or_i_false(self.mall), }) } - fn and_b(left: Self, right: Self) -> Result { + /// Constructor for the type of the `and_b` fragment. + pub const fn and_b(left: Self, right: Self) -> Result { + // FIXME need to do manual `?` because ? is not supported in constfns. Ok(Type { - corr: Property::and_b(left.corr, right.corr)?, - mall: Property::and_b(left.mall, right.mall)?, + corr: match Correctness::and_b(left.corr, right.corr) { + Ok(x) => x, + Err(e) => return Err(e), + }, + mall: Malleability::and_b(left.mall, right.mall), }) } - fn and_v(left: Self, right: Self) -> Result { + /// Constructor for the type of the `and_v` fragment. + pub const fn and_v(left: Self, right: Self) -> Result { + // FIXME need to do manual `?` because ? is not supported in constfns. Ok(Type { - corr: Property::and_v(left.corr, right.corr)?, - mall: Property::and_v(left.mall, right.mall)?, + corr: match Correctness::and_v(left.corr, right.corr) { + Ok(x) => x, + Err(e) => return Err(e), + }, + mall: Malleability::and_v(left.mall, right.mall), }) } - fn or_b(left: Self, right: Self) -> Result { + /// Constructor for the type of the `or_b` fragment. + pub const fn or_b(left: Self, right: Self) -> Result { + // FIXME need to do manual `?` because ? is not supported in constfns. Ok(Type { - corr: Property::or_b(left.corr, right.corr)?, - mall: Property::or_b(left.mall, right.mall)?, + corr: match Correctness::or_b(left.corr, right.corr) { + Ok(x) => x, + Err(e) => return Err(e), + }, + mall: Malleability::or_b(left.mall, right.mall), }) } - fn or_d(left: Self, right: Self) -> Result { + /// Constructor for the type of the `or_b` fragment. + pub const fn or_d(left: Self, right: Self) -> Result { + // FIXME need to do manual `?` because ? is not supported in constfns. Ok(Type { - corr: Property::or_d(left.corr, right.corr)?, - mall: Property::or_d(left.mall, right.mall)?, + corr: match Correctness::or_d(left.corr, right.corr) { + Ok(x) => x, + Err(e) => return Err(e), + }, + mall: Malleability::or_d(left.mall, right.mall), }) } - fn or_c(left: Self, right: Self) -> Result { + /// Constructor for the type of the `or_c` fragment. + pub const fn or_c(left: Self, right: Self) -> Result { + // FIXME need to do manual `?` because ? is not supported in constfns. Ok(Type { - corr: Property::or_c(left.corr, right.corr)?, - mall: Property::or_c(left.mall, right.mall)?, + corr: match Correctness::or_c(left.corr, right.corr) { + Ok(x) => x, + Err(e) => return Err(e), + }, + mall: Malleability::or_c(left.mall, right.mall), }) } - fn or_i(left: Self, right: Self) -> Result { + /// Constructor for the type of the `or_i` fragment. + pub const fn or_i(left: Self, right: Self) -> Result { Ok(Type { - corr: Property::or_i(left.corr, right.corr)?, - mall: Property::or_i(left.mall, right.mall)?, + corr: match Correctness::or_i(left.corr, right.corr) { + Ok(x) => x, + Err(e) => return Err(e), + }, + mall: Malleability::or_i(left.mall, right.mall), }) } - fn and_or(a: Self, b: Self, c: Self) -> Result { + /// Constructor for the type of the `and_or` fragment. + pub const fn and_or(a: Self, b: Self, c: Self) -> Result { + // FIXME need to do manual `?` because ? is not supported in constfns. Ok(Type { - corr: Property::and_or(a.corr, b.corr, c.corr)?, - mall: Property::and_or(a.mall, b.mall, c.mall)?, + corr: match Correctness::and_or(a.corr, b.corr, c.corr) { + Ok(x) => x, + Err(e) => return Err(e), + }, + mall: Malleability::and_or(a.mall, b.mall, c.mall), }) } - fn threshold(k: usize, n: usize, mut sub_ck: S) -> Result + /// Constructor for the type of the `thresh` fragment. + // Cannot be a constfn because it takes a closure. + pub fn threshold(k: usize, n: usize, mut sub_ck: S) -> Result where - S: FnMut(usize) -> Result, + S: FnMut(usize) -> Self, { Ok(Type { - corr: Property::threshold(k, n, |n| Ok(sub_ck(n)?.corr))?, - mall: Property::threshold(k, n, |n| Ok(sub_ck(n)?.mall))?, + corr: Correctness::threshold(k, n, |n| sub_ck(n).corr)?, + mall: Malleability::threshold(k, n, |n| sub_ck(n).mall), }) } } @@ -547,10 +488,10 @@ impl Type { }; let ret = match *fragment { - Terminal::True => Ok(Self::from_true()), - Terminal::False => Ok(Self::from_false()), - Terminal::PkK(..) => Ok(Self::from_pk_k::()), - Terminal::PkH(..) | Terminal::RawPkH(..) => Ok(Self::from_pk_h::()), + Terminal::True => Ok(Self::TRUE), + Terminal::False => Ok(Self::FALSE), + Terminal::PkK(..) => Ok(Self::pk_k()), + Terminal::PkH(..) | Terminal::RawPkH(..) => Ok(Self::pk_h()), Terminal::Multi(k, ref pks) | Terminal::MultiA(k, ref pks) => { if k == 0 { return Err(Error { @@ -565,8 +506,8 @@ impl Type { }); } match *fragment { - Terminal::Multi(..) => Ok(Self::from_multi(k, pks.len())), - Terminal::MultiA(..) => Ok(Self::from_multi_a(k, pks.len())), + Terminal::Multi(..) => Ok(Self::multi()), + Terminal::MultiA(..) => Ok(Self::multi_a()), _ => unreachable!(), } } @@ -580,7 +521,7 @@ impl Type { error: ErrorKind::InvalidTime, }); } - Ok(Self::from_after(t.into())) + Ok(Self::time()) } Terminal::Older(t) => { if t == Sequence::ZERO || !t.is_relative_lock_time() { @@ -589,12 +530,12 @@ impl Type { error: ErrorKind::InvalidTime, }); } - Ok(Self::from_older(t)) + Ok(Self::time()) } - Terminal::Sha256(..) => Ok(Self::from_sha256()), - Terminal::Hash256(..) => Ok(Self::from_hash256()), - Terminal::Ripemd160(..) => Ok(Self::from_ripemd160()), - Terminal::Hash160(..) => Ok(Self::from_hash160()), + Terminal::Sha256(..) => Ok(Self::hash()), + Terminal::Hash256(..) => Ok(Self::hash()), + Terminal::Ripemd160(..) => Ok(Self::hash()), + Terminal::Hash160(..) => Ok(Self::hash()), Terminal::Alt(ref sub) => wrap_err(Self::cast_alt(sub.ty)), Terminal::Swap(ref sub) => wrap_err(Self::cast_swap(sub.ty)), Terminal::Check(ref sub) => wrap_err(Self::cast_check(sub.ty)), @@ -652,7 +593,7 @@ impl Type { }); } - let res = Self::threshold(k, subs.len(), |n| Ok(subs[n].ty)); + let res = Self::threshold(k, subs.len(), |n| subs[n].ty); res.map_err(|kind| Error { fragment_string: fragment.to_string(), error: kind }) } diff --git a/src/policy/compiler.rs b/src/policy/compiler.rs index 1b1ced6e7..c24946d57 100644 --- a/src/policy/compiler.rs +++ b/src/policy/compiler.rs @@ -14,7 +14,7 @@ use sync::Arc; use crate::miniscript::context::SigType; use crate::miniscript::limits::MAX_PUBKEYS_PER_MULTISIG; -use crate::miniscript::types::{self, ErrorKind, ExtData, Property, Type}; +use crate::miniscript::types::{self, ErrorKind, ExtData, Type}; use crate::miniscript::ScriptContext; use crate::policy::Concrete; use crate::prelude::*; @@ -31,7 +31,7 @@ impl Eq for OrdF64 {} // We could derive PartialOrd, but we can't derive Ord, and clippy wants us // to derive both or neither. Better to be explicit. impl PartialOrd for OrdF64 { - fn partial_cmp(&self, other: &OrdF64) -> Option { self.0.partial_cmp(&other.0) } + fn partial_cmp(&self, other: &OrdF64) -> Option { Some(self.cmp(other)) } } impl Ord for OrdF64 { fn cmp(&self, other: &OrdF64) -> cmp::Ordering { @@ -145,16 +145,13 @@ struct CompilerExtData { dissat_cost: Option, } -impl Property for CompilerExtData { - fn from_true() -> Self { - CompilerExtData { branch_prob: None, sat_cost: 0.0, dissat_cost: None } - } +impl CompilerExtData { + const TRUE: Self = CompilerExtData { branch_prob: None, sat_cost: 0.0, dissat_cost: None }; - fn from_false() -> Self { - CompilerExtData { branch_prob: None, sat_cost: f64::MAX, dissat_cost: Some(0.0) } - } + const FALSE: Self = + CompilerExtData { branch_prob: None, sat_cost: f64::MAX, dissat_cost: Some(0.0) }; - fn from_pk_k() -> Self { + fn pk_k() -> Self { CompilerExtData { branch_prob: None, sat_cost: match Ctx::sig_type() { @@ -165,7 +162,7 @@ impl Property for CompilerExtData { } } - fn from_pk_h() -> Self { + fn pk_h() -> Self { CompilerExtData { branch_prob: None, sat_cost: match Ctx::sig_type() { @@ -181,7 +178,7 @@ impl Property for CompilerExtData { } } - fn from_multi(k: usize, _n: usize) -> Self { + fn multi(k: usize, _n: usize) -> Self { CompilerExtData { branch_prob: None, sat_cost: 1.0 + 73.0 * k as f64, @@ -189,7 +186,7 @@ impl Property for CompilerExtData { } } - fn from_multi_a(k: usize, n: usize) -> Self { + fn multi_a(k: usize, n: usize) -> Self { CompilerExtData { branch_prob: None, sat_cost: 66.0 * k as f64 + (n - k) as f64, @@ -197,158 +194,139 @@ impl Property for CompilerExtData { } } - fn from_hash() -> Self { + fn hash() -> Self { CompilerExtData { branch_prob: None, sat_cost: 33.0, dissat_cost: Some(33.0) } } - fn from_time(_t: u32) -> Self { - CompilerExtData { branch_prob: None, sat_cost: 0.0, dissat_cost: None } - } + fn time() -> Self { CompilerExtData { branch_prob: None, sat_cost: 0.0, dissat_cost: None } } - fn cast_alt(self) -> Result { - Ok(CompilerExtData { + fn cast_alt(self) -> Self { + CompilerExtData { branch_prob: None, sat_cost: self.sat_cost, dissat_cost: self.dissat_cost, - }) + } } - fn cast_swap(self) -> Result { - Ok(CompilerExtData { + fn cast_swap(self) -> Self { + CompilerExtData { branch_prob: None, sat_cost: self.sat_cost, dissat_cost: self.dissat_cost, - }) + } } - fn cast_check(self) -> Result { - Ok(CompilerExtData { + fn cast_check(self) -> Self { + CompilerExtData { branch_prob: None, sat_cost: self.sat_cost, dissat_cost: self.dissat_cost, - }) + } } - fn cast_dupif(self) -> Result { - Ok(CompilerExtData { - branch_prob: None, - sat_cost: 2.0 + self.sat_cost, - dissat_cost: Some(1.0), - }) + fn cast_dupif(self) -> Self { + CompilerExtData { branch_prob: None, sat_cost: 2.0 + self.sat_cost, dissat_cost: Some(1.0) } } - fn cast_verify(self) -> Result { - Ok(CompilerExtData { branch_prob: None, sat_cost: self.sat_cost, dissat_cost: None }) + fn cast_verify(self) -> Self { + CompilerExtData { branch_prob: None, sat_cost: self.sat_cost, dissat_cost: None } } - fn cast_nonzero(self) -> Result { - Ok(CompilerExtData { branch_prob: None, sat_cost: self.sat_cost, dissat_cost: Some(1.0) }) + fn cast_nonzero(self) -> Self { + CompilerExtData { branch_prob: None, sat_cost: self.sat_cost, dissat_cost: Some(1.0) } } - fn cast_zeronotequal(self) -> Result { - Ok(CompilerExtData { + fn cast_zeronotequal(self) -> Self { + CompilerExtData { branch_prob: None, sat_cost: self.sat_cost, dissat_cost: self.dissat_cost, - }) - } - - fn cast_true(self) -> Result { - Ok(CompilerExtData { branch_prob: None, sat_cost: self.sat_cost, dissat_cost: None }) + } } - fn cast_or_i_false(self) -> Result { - // never called directly - unreachable!() + fn cast_true(self) -> Self { + CompilerExtData { branch_prob: None, sat_cost: self.sat_cost, dissat_cost: None } } - fn cast_unlikely(self) -> Result { - Ok(CompilerExtData { - branch_prob: None, - sat_cost: 2.0 + self.sat_cost, - dissat_cost: Some(1.0), - }) + fn cast_unlikely(self) -> Self { + CompilerExtData { branch_prob: None, sat_cost: 2.0 + self.sat_cost, dissat_cost: Some(1.0) } } - fn cast_likely(self) -> Result { - Ok(CompilerExtData { - branch_prob: None, - sat_cost: 1.0 + self.sat_cost, - dissat_cost: Some(2.0), - }) + fn cast_likely(self) -> Self { + CompilerExtData { branch_prob: None, sat_cost: 1.0 + self.sat_cost, dissat_cost: Some(2.0) } } - fn and_b(left: Self, right: Self) -> Result { - Ok(CompilerExtData { + fn and_b(left: Self, right: Self) -> Self { + CompilerExtData { branch_prob: None, sat_cost: left.sat_cost + right.sat_cost, dissat_cost: match (left.dissat_cost, right.dissat_cost) { (Some(l), Some(r)) => Some(l + r), _ => None, }, - }) + } } - fn and_v(left: Self, right: Self) -> Result { - Ok(CompilerExtData { + fn and_v(left: Self, right: Self) -> Self { + CompilerExtData { branch_prob: None, sat_cost: left.sat_cost + right.sat_cost, dissat_cost: None, - }) + } } - fn or_b(l: Self, r: Self) -> Result { + fn or_b(l: Self, r: Self) -> Self { let lprob = l .branch_prob .expect("BUG: left branch prob must be set for disjunctions"); let rprob = r .branch_prob .expect("BUG: right branch prob must be set for disjunctions"); - Ok(CompilerExtData { + CompilerExtData { branch_prob: None, sat_cost: lprob * (l.sat_cost + r.dissat_cost.unwrap()) + rprob * (r.sat_cost + l.dissat_cost.unwrap()), dissat_cost: Some(l.dissat_cost.unwrap() + r.dissat_cost.unwrap()), - }) + } } - fn or_d(l: Self, r: Self) -> Result { + fn or_d(l: Self, r: Self) -> Self { let lprob = l .branch_prob .expect("BUG: left branch prob must be set for disjunctions"); let rprob = r .branch_prob .expect("BUG: right branch prob must be set for disjunctions"); - Ok(CompilerExtData { + CompilerExtData { branch_prob: None, sat_cost: lprob * l.sat_cost + rprob * (r.sat_cost + l.dissat_cost.unwrap()), dissat_cost: r.dissat_cost.map(|rd| l.dissat_cost.unwrap() + rd), - }) + } } - fn or_c(l: Self, r: Self) -> Result { + fn or_c(l: Self, r: Self) -> Self { let lprob = l .branch_prob .expect("BUG: left branch prob must be set for disjunctions"); let rprob = r .branch_prob .expect("BUG: right branch prob must be set for disjunctions"); - Ok(CompilerExtData { + CompilerExtData { branch_prob: None, sat_cost: lprob * l.sat_cost + rprob * (r.sat_cost + l.dissat_cost.unwrap()), dissat_cost: None, - }) + } } #[allow(clippy::manual_map)] // Complex if/let is better as is. - fn or_i(l: Self, r: Self) -> Result { + fn or_i(l: Self, r: Self) -> Self { let lprob = l .branch_prob .expect("BUG: left branch prob must be set for disjunctions"); let rprob = r .branch_prob .expect("BUG: right branch prob must be set for disjunctions"); - Ok(CompilerExtData { + CompilerExtData { branch_prob: None, sat_cost: lprob * (2.0 + l.sat_cost) + rprob * (1.0 + r.sat_cost), dissat_cost: if let (Some(ldis), Some(rdis)) = (l.dissat_cost, r.dissat_cost) { @@ -364,7 +342,7 @@ impl Property for CompilerExtData { } else { None }, - }) + } } fn and_or(a: Self, b: Self, c: Self) -> Result { @@ -386,14 +364,6 @@ impl Property for CompilerExtData { }) } - fn and_n(a: Self, b: Self) -> Result { - Ok(CompilerExtData { - branch_prob: None, - sat_cost: a.sat_cost + b.sat_cost, - dissat_cost: a.dissat_cost, - }) - } - fn threshold(k: usize, n: usize, mut sub_ck: S) -> Result where S: FnMut(usize) -> Result, @@ -452,16 +422,11 @@ impl CompilerExtData { Pk: MiniscriptKey, Ctx: ScriptContext, { - let wrap_err = |result: Result| { - result - .map_err(|kind| types::Error { fragment_string: fragment.to_string(), error: kind }) - }; - - let ret = match *fragment { - Terminal::True => Ok(Self::from_true()), - Terminal::False => Ok(Self::from_false()), - Terminal::PkK(..) => Ok(Self::from_pk_k::()), - Terminal::PkH(..) | Terminal::RawPkH(..) => Ok(Self::from_pk_h::()), + match *fragment { + Terminal::True => Ok(Self::TRUE), + Terminal::False => Ok(Self::FALSE), + Terminal::PkK(..) => Ok(Self::pk_k::()), + Terminal::PkH(..) | Terminal::RawPkH(..) => Ok(Self::pk_h::()), Terminal::Multi(k, ref pks) | Terminal::MultiA(k, ref pks) => { if k == 0 { return Err(types::Error { @@ -476,8 +441,8 @@ impl CompilerExtData { }); } match *fragment { - Terminal::Multi(..) => Ok(Self::from_multi(k, pks.len())), - Terminal::MultiA(..) => Ok(Self::from_multi_a(k, pks.len())), + Terminal::Multi(..) => Ok(Self::multi(k, pks.len())), + Terminal::MultiA(..) => Ok(Self::multi_a(k, pks.len())), _ => unreachable!(), } } @@ -491,7 +456,7 @@ impl CompilerExtData { error: types::ErrorKind::InvalidTime, }); } - Ok(Self::from_after(t.into())) + Ok(Self::time()) } Terminal::Older(t) => { if t == Sequence::ZERO || !t.is_relative_lock_time() { @@ -500,56 +465,59 @@ impl CompilerExtData { error: types::ErrorKind::InvalidTime, }); } - Ok(Self::from_older(t)) + Ok(Self::time()) } - Terminal::Sha256(..) => Ok(Self::from_sha256()), - Terminal::Hash256(..) => Ok(Self::from_hash256()), - Terminal::Ripemd160(..) => Ok(Self::from_ripemd160()), - Terminal::Hash160(..) => Ok(Self::from_hash160()), - Terminal::Alt(ref sub) => wrap_err(Self::cast_alt(get_child(&sub.node, 0)?)), - Terminal::Swap(ref sub) => wrap_err(Self::cast_swap(get_child(&sub.node, 0)?)), - Terminal::Check(ref sub) => wrap_err(Self::cast_check(get_child(&sub.node, 0)?)), - Terminal::DupIf(ref sub) => wrap_err(Self::cast_dupif(get_child(&sub.node, 0)?)), - Terminal::Verify(ref sub) => wrap_err(Self::cast_verify(get_child(&sub.node, 0)?)), - Terminal::NonZero(ref sub) => wrap_err(Self::cast_nonzero(get_child(&sub.node, 0)?)), + Terminal::Sha256(..) => Ok(Self::hash()), + Terminal::Hash256(..) => Ok(Self::hash()), + Terminal::Ripemd160(..) => Ok(Self::hash()), + Terminal::Hash160(..) => Ok(Self::hash()), + Terminal::Alt(ref sub) => Ok(Self::cast_alt(get_child(&sub.node, 0)?)), + Terminal::Swap(ref sub) => Ok(Self::cast_swap(get_child(&sub.node, 0)?)), + Terminal::Check(ref sub) => Ok(Self::cast_check(get_child(&sub.node, 0)?)), + Terminal::DupIf(ref sub) => Ok(Self::cast_dupif(get_child(&sub.node, 0)?)), + Terminal::Verify(ref sub) => Ok(Self::cast_verify(get_child(&sub.node, 0)?)), + Terminal::NonZero(ref sub) => Ok(Self::cast_nonzero(get_child(&sub.node, 0)?)), Terminal::ZeroNotEqual(ref sub) => { - wrap_err(Self::cast_zeronotequal(get_child(&sub.node, 0)?)) + Ok(Self::cast_zeronotequal(get_child(&sub.node, 0)?)) } Terminal::AndB(ref l, ref r) => { let ltype = get_child(&l.node, 0)?; let rtype = get_child(&r.node, 1)?; - wrap_err(Self::and_b(ltype, rtype)) + Ok(Self::and_b(ltype, rtype)) } Terminal::AndV(ref l, ref r) => { let ltype = get_child(&l.node, 0)?; let rtype = get_child(&r.node, 1)?; - wrap_err(Self::and_v(ltype, rtype)) + Ok(Self::and_v(ltype, rtype)) } Terminal::OrB(ref l, ref r) => { let ltype = get_child(&l.node, 0)?; let rtype = get_child(&r.node, 1)?; - wrap_err(Self::or_b(ltype, rtype)) + Ok(Self::or_b(ltype, rtype)) } Terminal::OrD(ref l, ref r) => { let ltype = get_child(&l.node, 0)?; let rtype = get_child(&r.node, 1)?; - wrap_err(Self::or_d(ltype, rtype)) + Ok(Self::or_d(ltype, rtype)) } Terminal::OrC(ref l, ref r) => { let ltype = get_child(&l.node, 0)?; let rtype = get_child(&r.node, 1)?; - wrap_err(Self::or_c(ltype, rtype)) + Ok(Self::or_c(ltype, rtype)) } Terminal::OrI(ref l, ref r) => { let ltype = get_child(&l.node, 0)?; let rtype = get_child(&r.node, 1)?; - wrap_err(Self::or_i(ltype, rtype)) + Ok(Self::or_i(ltype, rtype)) } Terminal::AndOr(ref a, ref b, ref c) => { let atype = get_child(&a.node, 0)?; let btype = get_child(&b.node, 1)?; let ctype = get_child(&c.node, 2)?; - wrap_err(Self::and_or(atype, btype, ctype)) + Self::and_or(atype, btype, ctype).map_err(|kind| types::Error { + fragment_string: fragment.to_string(), + error: kind, + }) } Terminal::Thresh(k, ref subs) => { if k == 0 { @@ -566,24 +534,16 @@ impl CompilerExtData { } let mut last_err_frag = None; - let res = Self::threshold(k, subs.len(), |n| match get_child(&subs[n].node, n) { + Self::threshold(k, subs.len(), |n| match get_child(&subs[n].node, n) { Ok(x) => Ok(x), Err(e) => { last_err_frag = Some(e.fragment_string); Err(e.error) } - }); - - res.map_err(|kind| types::Error { - fragment_string: last_err_frag.unwrap_or_else(|| fragment.to_string()), - error: kind, }) + .map_err(|kind| types::Error { fragment_string: fragment.to_string(), error: kind }) } - }; - if let Ok(ref ret) = ret { - ret.sanity_checks() } - ret } } @@ -671,8 +631,8 @@ impl AstElemExt { struct Cast { node: fn(Arc>) -> Terminal, ast_type: fn(types::Type) -> Result, - ext_data: fn(types::ExtData) -> Result, - comp_ext_data: fn(CompilerExtData) -> Result, + ext_data: fn(types::ExtData) -> types::ExtData, + comp_ext_data: fn(CompilerExtData) -> CompilerExtData, } impl Cast { @@ -681,9 +641,9 @@ impl Cast { ms: Arc::new(Miniscript::from_components_unchecked( (self.node)(Arc::clone(&ast.ms)), (self.ast_type)(ast.ms.ty)?, - (self.ext_data)(ast.ms.ext)?, + (self.ext_data)(ast.ms.ext), )), - comp_ext_data: (self.comp_ext_data)(ast.comp_ext_data)?, + comp_ext_data: (self.comp_ext_data)(ast.comp_ext_data), }) } } @@ -953,11 +913,7 @@ where compile_binary!(&mut right, &mut left, [1.0, 1.0], Terminal::AndV); let mut zero_comp = BTreeMap::new(); zero_comp.insert( - CompilationKey::from_type( - Type::from_false(), - ExtData::from_false().has_free_verify, - dissat_prob, - ), + CompilationKey::from_type(Type::FALSE, ExtData::FALSE.has_free_verify, dissat_prob), AstElemExt::terminal(Terminal::False), ); compile_tern!(&mut left, &mut q_zero_right, &mut zero_comp, [1.0, 0.0]); diff --git a/src/policy/concrete.rs b/src/policy/concrete.rs index 5e235bb4b..bfb40a85f 100644 --- a/src/policy/concrete.rs +++ b/src/policy/concrete.rs @@ -29,7 +29,7 @@ use crate::prelude::*; use crate::sync::Arc; #[cfg(all(doc, not(feature = "compiler")))] use crate::Descriptor; -use crate::{errstr, AbsLockTime, Error, ForEachKey, MiniscriptKey, Translator}; +use crate::{errstr, AbsLockTime, Error, ForEachKey, FromStrKey, MiniscriptKey, Translator}; /// Maximum TapLeafs allowed in a compiled TapTree #[cfg(feature = "compiler")] @@ -930,7 +930,7 @@ impl fmt::Display for Policy { } } -impl str::FromStr for Policy { +impl str::FromStr for Policy { type Err = Error; fn from_str(s: &str) -> Result, Error> { expression::check_valid_chars(s)?; @@ -945,7 +945,7 @@ impl str::FromStr for Policy { serde_string_impl_pk!(Policy, "a miniscript concrete policy"); #[rustfmt::skip] -impl Policy { +impl Policy { /// Helper function for `from_tree` to parse subexpressions with /// names of the form x@y fn from_tree_prob(top: &expression::Tree, allow_prob: bool,) @@ -1050,7 +1050,7 @@ impl Policy { } } -impl expression::FromTree for Policy { +impl expression::FromTree for Policy { fn from_tree(top: &expression::Tree) -> Result, Error> { Policy::from_tree_prob(top, false).map(|(_, result)| result) } @@ -1093,7 +1093,7 @@ fn with_huffman_tree( /// any one of the conditions exclusively. #[cfg(feature = "compiler")] fn generate_combination( - policy_vec: &Vec>>, + policy_vec: &[Arc>], prob: f64, k: usize, ) -> Vec<(f64, Arc>)> { diff --git a/src/policy/semantic.rs b/src/policy/semantic.rs index 6bed0f710..8b00d0bd8 100644 --- a/src/policy/semantic.rs +++ b/src/policy/semantic.rs @@ -15,7 +15,9 @@ use super::ENTAILMENT_MAX_TERMINALS; use crate::iter::{Tree, TreeLike}; use crate::prelude::*; use crate::sync::Arc; -use crate::{errstr, expression, AbsLockTime, Error, ForEachKey, MiniscriptKey, Translator}; +use crate::{ + errstr, expression, AbsLockTime, Error, ForEachKey, FromStrKey, MiniscriptKey, Translator, +}; /// Abstract policy which corresponds to the semantics of a miniscript and /// which allows complex forms of analysis, e.g. filtering and normalization. @@ -308,7 +310,7 @@ impl fmt::Display for Policy { } } -impl str::FromStr for Policy { +impl str::FromStr for Policy { type Err = Error; fn from_str(s: &str) -> Result, Error> { expression::check_valid_chars(s)?; @@ -320,7 +322,7 @@ impl str::FromStr for Policy { serde_string_impl_pk!(Policy, "a miniscript semantic policy"); -impl expression::FromTree for Policy { +impl expression::FromTree for Policy { fn from_tree(top: &expression::Tree) -> Result, Error> { match (top.name, top.args.len()) { ("UNSATISFIABLE", 0) => Ok(Policy::Unsatisfiable),