@@ -22,7 +22,117 @@ use core::fmt;
2222use std:: error;
2323
2424use crate :: prelude:: * ;
25- use crate :: { Miniscript , MiniscriptKey , ScriptContext } ;
25+ use crate :: { Miniscript , MiniscriptKey , ScriptContext , Terminal } ;
26+
27+ /// Params for parsing miniscripts that either non-sane or non-specified(experimental) in the spec.
28+ /// Used as a parameter [`Miniscript::from_str_ext`] and [`Miniscript::parse_with_ext`].
29+ ///
30+ /// This allows parsing miniscripts if
31+ /// 1. It is unsafe(does not require a digital signature to spend it)
32+ /// 2. It contains a unspendable path because of either
33+ /// a. Resource limitations
34+ /// b. Timelock Mixing
35+ /// 3. The script is malleable and thereby some of satisfaction weight
36+ /// guarantees are not satisfied.
37+ /// 4. It has repeated public keys
38+ /// 5. raw pkh fragments without the pk. This could be obtained when parsing miniscript from script
39+ #[ derive( Debug , PartialEq , Eq , PartialOrd , Ord , Clone , Copy , Default ) ]
40+ pub struct ExtParams {
41+ /// Allow parsing of non-safe miniscripts
42+ pub top_unsafe : bool ,
43+ /// Allow parsing of miniscripts with unspendable paths
44+ pub resource_limitations : bool ,
45+ /// Allow parsing of miniscripts with timelock mixing
46+ pub timelock_mixing : bool ,
47+ /// Allow parsing of malleable miniscripts
48+ pub malleability : bool ,
49+ /// Allow parsing of miniscripts with repeated public keys
50+ pub repeated_pk : bool ,
51+ /// Allow parsing of miniscripts with raw pkh fragments without the pk.
52+ /// This could be obtained when parsing miniscript from script
53+ pub raw_pkh : bool ,
54+ }
55+
56+ impl ExtParams {
57+ /// Create a new ExtParams that with all the sanity rules
58+ pub fn new ( ) -> ExtParams {
59+ ExtParams {
60+ top_unsafe : false ,
61+ resource_limitations : false ,
62+ timelock_mixing : false ,
63+ malleability : false ,
64+ repeated_pk : false ,
65+ raw_pkh : false ,
66+ }
67+ }
68+
69+ /// Create a new ExtParams that allows all the sanity rules
70+ pub fn sane ( ) -> ExtParams {
71+ ExtParams :: new ( )
72+ }
73+
74+ /// Create a new ExtParams that insanity rules
75+ /// This enables parsing well specified but "insane" miniscripts.
76+ /// Refer to the [`ExtParams`] documentation for more details on "insane" miniscripts.
77+ pub fn insane ( ) -> ExtParams {
78+ ExtParams {
79+ top_unsafe : true ,
80+ resource_limitations : true ,
81+ timelock_mixing : true ,
82+ malleability : true ,
83+ repeated_pk : true ,
84+ raw_pkh : false ,
85+ }
86+ }
87+
88+ /// Enable all non-sane rules and experimental rules
89+ pub fn allow_all ( ) -> ExtParams {
90+ ExtParams {
91+ top_unsafe : true ,
92+ resource_limitations : true ,
93+ timelock_mixing : true ,
94+ malleability : true ,
95+ repeated_pk : true ,
96+ raw_pkh : true ,
97+ }
98+ }
99+
100+ /// Builder that allows non-safe miniscripts.
101+ pub fn top_unsafe ( mut self ) -> ExtParams {
102+ self . top_unsafe = true ;
103+ self
104+ }
105+
106+ /// Builder that allows miniscripts with exceed resource limitations.
107+ pub fn exceed_resource_limitations ( mut self ) -> ExtParams {
108+ self . resource_limitations = true ;
109+ self
110+ }
111+
112+ /// Builder that allows miniscripts with timelock mixing.
113+ pub fn timelock_mixing ( mut self ) -> ExtParams {
114+ self . timelock_mixing = true ;
115+ self
116+ }
117+
118+ /// Builder that allows malleable miniscripts.
119+ pub fn malleability ( mut self ) -> ExtParams {
120+ self . malleability = true ;
121+ self
122+ }
123+
124+ /// Builder that allows miniscripts with repeated public keys.
125+ pub fn repeated_pk ( mut self ) -> ExtParams {
126+ self . repeated_pk = true ;
127+ self
128+ }
129+
130+ /// Builder that allows miniscripts with raw pkh fragments.
131+ pub fn raw_pkh ( mut self ) -> ExtParams {
132+ self . raw_pkh = true ;
133+ self
134+ }
135+ }
26136
27137/// Possible reasons Miniscript guarantees can fail
28138/// We currently mark Miniscript as Non-Analyzable if
@@ -45,6 +155,8 @@ pub enum AnalysisError {
45155 HeightTimelockCombination ,
46156 /// Malleable script
47157 Malleable ,
158+ /// Contains partial descriptor raw pkh
159+ ContainsRawPkh ,
48160}
49161
50162impl fmt:: Display for AnalysisError {
@@ -62,7 +174,8 @@ impl fmt::Display for AnalysisError {
62174 AnalysisError :: HeightTimelockCombination => {
63175 f. write_str ( "Contains a combination of heightlock and timelock" )
64176 }
65- AnalysisError :: Malleable => f. write_str ( "Miniscript is malleable" )
177+ AnalysisError :: Malleable => f. write_str ( "Miniscript is malleable" ) ,
178+ AnalysisError :: ContainsRawPkh => f. write_str ( "Miniscript contains raw pkh" ) ,
66179 }
67180 }
68181}
@@ -77,7 +190,8 @@ impl error::Error for AnalysisError {
77190 | RepeatedPubkeys
78191 | BranchExceedResouceLimits
79192 | HeightTimelockCombination
80- | Malleable => None ,
193+ | Malleable
194+ | ContainsRawPkh => None ,
81195 }
82196 }
83197}
@@ -116,6 +230,14 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
116230 unique_pkhs_len != all_pkhs_len
117231 }
118232
233+ /// Whether the given miniscript contains a raw pkh fragment
234+ pub fn contains_raw_pkh ( & self ) -> bool {
235+ self . iter ( ) . any ( |ms| match ms. node {
236+ Terminal :: RawPkH ( _) => true ,
237+ _ => false ,
238+ } )
239+ }
240+
119241 /// Check whether the underlying Miniscript is safe under the current context
120242 /// Lifting these polices would create a semantic representation that does
121243 /// not represent the underlying semantics when miniscript is spent.
@@ -140,4 +262,23 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
140262 Ok ( ( ) )
141263 }
142264 }
265+
266+ /// Check whether the miniscript follows the given Extra policy [`ExtParams`]
267+ pub fn ext_check ( & self , ext : & ExtParams ) -> Result < ( ) , AnalysisError > {
268+ if !ext. top_unsafe && !self . requires_sig ( ) {
269+ Err ( AnalysisError :: SiglessBranch )
270+ } else if !ext. malleability && !self . is_non_malleable ( ) {
271+ Err ( AnalysisError :: Malleable )
272+ } else if !ext. resource_limitations && !self . within_resource_limits ( ) {
273+ Err ( AnalysisError :: BranchExceedResouceLimits )
274+ } else if !ext. repeated_pk && self . has_repeated_keys ( ) {
275+ Err ( AnalysisError :: RepeatedPubkeys )
276+ } else if !ext. timelock_mixing && self . has_mixed_timelocks ( ) {
277+ Err ( AnalysisError :: HeightTimelockCombination )
278+ } else if !ext. raw_pkh && self . contains_raw_pkh ( ) {
279+ Err ( AnalysisError :: ContainsRawPkh )
280+ } else {
281+ Ok ( ( ) )
282+ }
283+ }
143284}
0 commit comments