@@ -22,7 +22,117 @@ use core::fmt;
22
22
use std:: error;
23
23
24
24
use 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
+ }
26
136
27
137
/// Possible reasons Miniscript guarantees can fail
28
138
/// We currently mark Miniscript as Non-Analyzable if
@@ -45,6 +155,8 @@ pub enum AnalysisError {
45
155
HeightTimelockCombination ,
46
156
/// Malleable script
47
157
Malleable ,
158
+ /// Contains partial descriptor raw pkh
159
+ ContainsRawPkh ,
48
160
}
49
161
50
162
impl fmt:: Display for AnalysisError {
@@ -62,7 +174,8 @@ impl fmt::Display for AnalysisError {
62
174
AnalysisError :: HeightTimelockCombination => {
63
175
f. write_str ( "Contains a combination of heightlock and timelock" )
64
176
}
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" ) ,
66
179
}
67
180
}
68
181
}
@@ -77,7 +190,8 @@ impl error::Error for AnalysisError {
77
190
| RepeatedPubkeys
78
191
| BranchExceedResouceLimits
79
192
| HeightTimelockCombination
80
- | Malleable => None ,
193
+ | Malleable
194
+ | ContainsRawPkh => None ,
81
195
}
82
196
}
83
197
}
@@ -116,6 +230,14 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
116
230
unique_pkhs_len != all_pkhs_len
117
231
}
118
232
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
+
119
241
/// Check whether the underlying Miniscript is safe under the current context
120
242
/// Lifting these polices would create a semantic representation that does
121
243
/// not represent the underlying semantics when miniscript is spent.
@@ -140,4 +262,23 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
140
262
Ok ( ( ) )
141
263
}
142
264
}
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
+ }
143
284
}
0 commit comments