@@ -35,6 +35,7 @@ pub use self::concrete::Policy as Concrete;
35
35
/// Semantic policies are "abstract" policies elsewhere; but we
36
36
/// avoid this word because it is a reserved keyword in Rust
37
37
pub use self :: semantic:: Policy as Semantic ;
38
+ use Error ;
38
39
use MiniscriptKey ;
39
40
40
41
/// Policy entailment algorithm maximum number of terminals allowed
@@ -46,18 +47,25 @@ const ENTAILMENT_MAX_TERMINALS: usize = 20;
46
47
/// `Lift(Concrete) == Concrete -> Miniscript -> Script -> Miniscript -> Semantic`
47
48
pub trait Liftable < Pk : MiniscriptKey > {
48
49
/// Convert the object into an abstract policy
49
- fn lift ( & self ) -> Semantic < Pk > ;
50
+ fn lift ( & self ) -> Result < Semantic < Pk > , Error > ;
50
51
}
51
52
52
53
impl < Pk : MiniscriptKey , Ctx : ScriptContext > Liftable < Pk > for Miniscript < Pk , Ctx > {
53
- fn lift ( & self ) -> Semantic < Pk > {
54
+ fn lift ( & self ) -> Result < Semantic < Pk > , Error > {
55
+ // check whether the root miniscript can have a spending path that is
56
+ // a combination of heightlock and timelock
57
+ if self . ext . timelock_info . contains_unspendable_path ( ) {
58
+ return Err ( Error :: PolicyError (
59
+ concrete:: PolicyError :: HeightTimeLockCombination ,
60
+ ) ) ;
61
+ }
54
62
self . as_inner ( ) . lift ( )
55
63
}
56
64
}
57
65
58
66
impl < Pk : MiniscriptKey , Ctx : ScriptContext > Liftable < Pk > for Terminal < Pk , Ctx > {
59
- fn lift ( & self ) -> Semantic < Pk > {
60
- match * self {
67
+ fn lift ( & self ) -> Result < Semantic < Pk > , Error > {
68
+ let ret = match * self {
61
69
Terminal :: PkK ( ref pk) => Semantic :: KeyHash ( pk. to_pubkeyhash ( ) ) ,
62
70
Terminal :: PkH ( ref pkh) => Semantic :: KeyHash ( pkh. clone ( ) ) ,
63
71
Terminal :: After ( t) => Semantic :: After ( t) ,
@@ -74,25 +82,27 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Liftable<Pk> for Terminal<Pk, Ctx> {
74
82
| Terminal :: DupIf ( ref sub)
75
83
| Terminal :: Verify ( ref sub)
76
84
| Terminal :: NonZero ( ref sub)
77
- | Terminal :: ZeroNotEqual ( ref sub) => sub. node . lift ( ) ,
85
+ | Terminal :: ZeroNotEqual ( ref sub) => sub. node . lift ( ) ? ,
78
86
Terminal :: AndV ( ref left, ref right) | Terminal :: AndB ( ref left, ref right) => {
79
- Semantic :: Threshold ( 2 , vec ! [ left. node. lift( ) , right. node. lift( ) ] )
87
+ Semantic :: Threshold ( 2 , vec ! [ left. node. lift( ) ? , right. node. lift( ) ? ] )
80
88
}
81
89
Terminal :: AndOr ( ref a, ref b, ref c) => Semantic :: Threshold (
82
90
1 ,
83
91
vec ! [
84
- Semantic :: Threshold ( 2 , vec![ a. node. lift( ) , c. node. lift( ) ] ) ,
85
- b. node. lift( ) ,
92
+ Semantic :: Threshold ( 2 , vec![ a. node. lift( ) ? , c. node. lift( ) ? ] ) ,
93
+ b. node. lift( ) ? ,
86
94
] ,
87
95
) ,
88
96
Terminal :: OrB ( ref left, ref right)
89
97
| Terminal :: OrD ( ref left, ref right)
90
98
| Terminal :: OrC ( ref left, ref right)
91
99
| Terminal :: OrI ( ref left, ref right) => {
92
- Semantic :: Threshold ( 1 , vec ! [ left. node. lift( ) , right. node. lift( ) ] )
100
+ Semantic :: Threshold ( 1 , vec ! [ left. node. lift( ) ? , right. node. lift( ) ? ] )
93
101
}
94
102
Terminal :: Thresh ( k, ref subs) => {
95
- Semantic :: Threshold ( k, subs. into_iter ( ) . map ( |s| s. node . lift ( ) ) . collect ( ) )
103
+ let semantic_subs: Result < _ , Error > =
104
+ subs. into_iter ( ) . map ( |s| s. node . lift ( ) ) . collect ( ) ;
105
+ Semantic :: Threshold ( k, semantic_subs?)
96
106
}
97
107
Terminal :: Multi ( k, ref keys) => Semantic :: Threshold (
98
108
k,
@@ -101,32 +111,36 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Liftable<Pk> for Terminal<Pk, Ctx> {
101
111
. collect ( ) ,
102
112
) ,
103
113
}
104
- . normalized ( )
114
+ . normalized ( ) ;
115
+ Ok ( ret)
105
116
}
106
117
}
107
118
108
119
impl < Pk : MiniscriptKey > Liftable < Pk > for Descriptor < Pk > {
109
- fn lift ( & self ) -> Semantic < Pk > {
110
- match * self {
111
- Descriptor :: Bare ( ref d) | Descriptor :: Sh ( ref d) => d. node . lift ( ) ,
112
- Descriptor :: Wsh ( ref d) | Descriptor :: ShWsh ( ref d) => d. node . lift ( ) ,
120
+ fn lift ( & self ) -> Result < Semantic < Pk > , Error > {
121
+ Ok ( match * self {
122
+ Descriptor :: Bare ( ref d) | Descriptor :: Sh ( ref d) => d. node . lift ( ) ? ,
123
+ Descriptor :: Wsh ( ref d) | Descriptor :: ShWsh ( ref d) => d. node . lift ( ) ? ,
113
124
Descriptor :: Pk ( ref p)
114
125
| Descriptor :: Pkh ( ref p)
115
126
| Descriptor :: Wpkh ( ref p)
116
127
| Descriptor :: ShWpkh ( ref p) => Semantic :: KeyHash ( p. to_pubkeyhash ( ) ) ,
117
- }
128
+ } )
118
129
}
119
130
}
120
131
121
132
impl < Pk : MiniscriptKey > Liftable < Pk > for Semantic < Pk > {
122
- fn lift ( & self ) -> Semantic < Pk > {
123
- self . clone ( )
133
+ fn lift ( & self ) -> Result < Semantic < Pk > , Error > {
134
+ Ok ( self . clone ( ) )
124
135
}
125
136
}
126
137
127
138
impl < Pk : MiniscriptKey > Liftable < Pk > for Concrete < Pk > {
128
- fn lift ( & self ) -> Semantic < Pk > {
129
- match * self {
139
+ fn lift ( & self ) -> Result < Semantic < Pk > , Error > {
140
+ // do not lift if there is a possible satisfaction
141
+ // involving combination of timelocks and heightlocks
142
+ self . check_timelocks ( ) ?;
143
+ let ret = match * self {
130
144
Concrete :: Key ( ref pk) => Semantic :: KeyHash ( pk. to_pubkeyhash ( ) ) ,
131
145
Concrete :: After ( t) => Semantic :: After ( t) ,
132
146
Concrete :: Older ( t) => Semantic :: Older ( t) ,
@@ -135,16 +149,21 @@ impl<Pk: MiniscriptKey> Liftable<Pk> for Concrete<Pk> {
135
149
Concrete :: Ripemd160 ( h) => Semantic :: Ripemd160 ( h) ,
136
150
Concrete :: Hash160 ( h) => Semantic :: Hash160 ( h) ,
137
151
Concrete :: And ( ref subs) => {
138
- Semantic :: Threshold ( subs. len ( ) , subs. iter ( ) . map ( Liftable :: lift) . collect ( ) )
152
+ let semantic_subs: Result < _ , Error > = subs. iter ( ) . map ( Liftable :: lift) . collect ( ) ;
153
+ Semantic :: Threshold ( 2 , semantic_subs?)
139
154
}
140
155
Concrete :: Or ( ref subs) => {
141
- Semantic :: Threshold ( 1 , subs. iter ( ) . map ( |& ( _, ref sub) | sub. lift ( ) ) . collect ( ) )
156
+ let semantic_subs: Result < _ , Error > =
157
+ subs. iter ( ) . map ( |& ( ref _p, ref sub) | sub. lift ( ) ) . collect ( ) ;
158
+ Semantic :: Threshold ( 1 , semantic_subs?)
142
159
}
143
160
Concrete :: Threshold ( k, ref subs) => {
144
- Semantic :: Threshold ( k, subs. iter ( ) . map ( Liftable :: lift) . collect ( ) )
161
+ let semantic_subs: Result < _ , Error > = subs. iter ( ) . map ( Liftable :: lift) . collect ( ) ;
162
+ Semantic :: Threshold ( k, semantic_subs?)
145
163
}
146
164
}
147
- . normalized ( )
165
+ . normalized ( ) ;
166
+ Ok ( ret)
148
167
}
149
168
}
150
169
@@ -169,6 +188,21 @@ mod tests {
169
188
assert_eq ! ( s. to_lowercase( ) , output. to_lowercase( ) ) ;
170
189
}
171
190
191
+ #[ test]
192
+ fn test_timelock_validity ( ) {
193
+ // only height
194
+ assert ! ( ConcretePol :: from_str( "after(100)" ) . is_ok( ) ) ;
195
+ // only time
196
+ assert ! ( ConcretePol :: from_str( "after(1000000000)" ) . is_ok( ) ) ;
197
+ // disjunction
198
+ assert ! ( ConcretePol :: from_str( "or(after(1000000000),after(100))" ) . is_ok( ) ) ;
199
+ // conjunction
200
+ assert ! ( ConcretePol :: from_str( "and(after(1000000000),after(100))" ) . is_err( ) ) ;
201
+ // thresh with k = 1
202
+ assert ! ( ConcretePol :: from_str( "thresh(1,pk(),after(1000000000),after(100))" ) . is_ok( ) ) ;
203
+ // thresh with k = 2
204
+ assert ! ( ConcretePol :: from_str( "thresh(2,after(1000000000),after(100),pk())" ) . is_err( ) ) ;
205
+ }
172
206
#[ test]
173
207
fn policy_rtt_tests ( ) {
174
208
concrete_policy_rtt ( "pk()" ) ;
0 commit comments