18
18
use bitcoin:: hashes:: hex:: FromHex ;
19
19
use bitcoin:: hashes:: { hash160, ripemd160, sha256, sha256d} ;
20
20
use std:: collections:: HashSet ;
21
- #[ cfg( feature = "compiler" ) ]
22
- use std:: sync:: Arc ;
23
21
use std:: { error, fmt, str} ;
24
22
23
+ #[ cfg( feature = "compiler" ) ]
24
+ use super :: Liftable ;
25
25
use super :: ENTAILMENT_MAX_TERMINALS ;
26
26
#[ cfg( feature = "compiler" ) ]
27
27
use descriptor:: TapTree ;
@@ -32,9 +32,15 @@ use miniscript::types::extra_props::TimeLockInfo;
32
32
#[ cfg( feature = "compiler" ) ]
33
33
use miniscript:: ScriptContext ;
34
34
#[ cfg( feature = "compiler" ) ]
35
- use policy:: compiler;
35
+ use policy:: compiler:: { CompilerError , OrdF64 } ;
36
+ #[ cfg( feature = "compiler" ) ]
37
+ use policy:: { compiler, Semantic } ;
38
+ #[ cfg( feature = "compiler" ) ]
39
+ use std:: cmp:: Reverse ;
36
40
#[ cfg( feature = "compiler" ) ]
37
- use policy:: compiler:: CompilerError ;
41
+ use std:: collections:: BinaryHeap ;
42
+ #[ cfg( feature = "compiler" ) ]
43
+ use std:: sync:: Arc ;
38
44
#[ cfg( feature = "compiler" ) ]
39
45
use Descriptor ;
40
46
#[ cfg( feature = "compiler" ) ]
@@ -137,30 +143,109 @@ impl fmt::Display for PolicyError {
137
143
}
138
144
139
145
impl < Pk : MiniscriptKey > Policy < Pk > {
140
- /// Single-Node compilation
146
+ /// Create a Huffman Tree from compiled [Miniscript] nodes
147
+ #[ cfg( feature = "compiler" ) ]
148
+ fn with_huffman_tree < T > (
149
+ ms : Vec < ( OrdF64 , Miniscript < Pk , Tap > ) > ,
150
+ f : T ,
151
+ ) -> Result < TapTree < Pk > , Error >
152
+ where
153
+ T : Fn ( OrdF64 ) -> OrdF64 ,
154
+ {
155
+ // Pattern match terminal Or/ Terminal (with equal odds)
156
+ let mut node_weights = BinaryHeap :: < ( Reverse < OrdF64 > , Arc < TapTree < Pk > > ) > :: new ( ) ;
157
+ for ( prob, script) in ms {
158
+ node_weights. push ( ( Reverse ( f ( prob) ) , Arc :: from ( TapTree :: Leaf ( Arc :: new ( script) ) ) ) ) ;
159
+ }
160
+ if node_weights. is_empty ( ) {
161
+ return Err ( errstr ( "Empty Miniscript compilation" ) ) ;
162
+ }
163
+ while node_weights. len ( ) > 1 {
164
+ let ( p1, s1) = node_weights. pop ( ) . expect ( "len must atleast be two" ) ;
165
+ let ( p2, s2) = node_weights. pop ( ) . expect ( "len must atleast be two" ) ;
166
+
167
+ let p = ( p1. 0 ) . 0 + ( p2. 0 ) . 0 ;
168
+ node_weights. push ( ( Reverse ( OrdF64 ( p) ) , Arc :: from ( TapTree :: Tree ( s1, s2) ) ) ) ;
169
+ }
170
+
171
+ debug_assert ! ( node_weights. len( ) == 1 ) ;
172
+ let node = node_weights
173
+ . pop ( )
174
+ . expect ( "huffman tree algorithm is broken" )
175
+ . 1 ;
176
+ Ok ( ( * node) . clone ( ) )
177
+ }
178
+
179
+ /// Flatten the [`Policy`] tree structure into a Vector with corresponding leaf probability
180
+ // TODO: 1. Can try to push the maximum of scaling factors and accordingly update later for
181
+ // TODO: 1. integer metric. (Accordingly change metrics everywhere)
182
+ #[ cfg( feature = "compiler" ) ]
183
+ fn flatten_policy ( & self , prob : f64 ) -> Vec < ( f64 , Policy < Pk > ) > {
184
+ match * self {
185
+ Policy :: Or ( ref subs) => {
186
+ let total_odds: usize = subs. iter ( ) . map ( |( ref k, _) | k) . sum ( ) ;
187
+ subs. iter ( )
188
+ . map ( |( k, ref policy) | {
189
+ policy. flatten_policy ( prob * * k as f64 / total_odds as f64 )
190
+ } )
191
+ . flatten ( )
192
+ . collect :: < Vec < _ > > ( )
193
+ }
194
+ Policy :: Threshold ( k, ref subs) if k == 1 => {
195
+ let total_odds = subs. len ( ) ;
196
+ subs. iter ( )
197
+ . map ( |policy| policy. flatten_policy ( prob / total_odds as f64 ) )
198
+ . flatten ( )
199
+ . collect :: < Vec < _ > > ( )
200
+ }
201
+ ref x => vec ! [ ( prob, x. clone( ) ) ] ,
202
+ }
203
+ }
204
+
205
+ /// Compile [`Policy::Or`] and [`Policy::Threshold`] according to odds
141
206
#[ cfg( feature = "compiler" ) ]
142
- fn compile_huffman_taptree ( policy : & Self ) -> Result < TapTree < Pk > , Error > {
143
- let compilation = policy. compile :: < Tap > ( ) . unwrap ( ) ;
144
- Ok ( TapTree :: Leaf ( Arc :: new ( compilation) ) )
207
+ fn compile_tr_policy ( & self ) -> Result < TapTree < Pk > , Error > {
208
+ let leaf_compilations: Vec < _ > = self
209
+ . flatten_policy ( 1.0 )
210
+ . into_iter ( )
211
+ . map ( |( prob, ref policy) | ( OrdF64 ( prob) , policy. compile :: < Tap > ( ) . unwrap ( ) ) )
212
+ . collect ( ) ;
213
+ let taptree = Self :: with_huffman_tree ( leaf_compilations, |x| x) . unwrap ( ) ;
214
+ Ok ( taptree)
145
215
}
146
- /// Extract the Taproot internal_key from policy tree.
216
+
217
+ /// Extract the internal_key from policy tree.
147
218
#[ cfg( feature = "compiler" ) ]
148
- fn extract_key ( policy : & Self , unspendable_key : Option < Pk > ) -> Result < ( Pk , & Policy < Pk > ) , Error > {
149
- match unspendable_key {
150
- Some ( key) => Ok ( ( key, policy) ) ,
151
- None => Err ( errstr ( "No internal key found" ) ) ,
219
+ fn extract_key ( policy : & Self , unspendable_key : Option < Pk > ) -> Result < ( Pk , Policy < Pk > ) , Error > {
220
+ let semantic_policy = policy. lift ( ) ?;
221
+ let concrete_keys = policy. keys ( ) . into_iter ( ) . collect :: < HashSet < _ > > ( ) ;
222
+ let mut internal_key: Option < Pk > = None ;
223
+
224
+ for key in concrete_keys. iter ( ) {
225
+ if semantic_policy
226
+ . clone ( )
227
+ . satisfy_constraint ( & Semantic :: KeyHash ( key. to_pubkeyhash ( ) ) , true )
228
+ == Semantic :: Trivial
229
+ {
230
+ internal_key = Some ( ( * key) . clone ( ) ) ;
231
+ break ;
232
+ }
233
+ }
234
+
235
+ match ( internal_key, unspendable_key) {
236
+ ( Some ( key) , _) => Ok ( ( key. clone ( ) , policy. translate_unsatisfiable_pk ( & key) ) ) ,
237
+ ( _, Some ( key) ) => Ok ( ( key, policy. clone ( ) ) ) ,
238
+ _ => Err ( errstr ( "No viable internal key found." ) ) ,
152
239
}
153
240
}
154
241
155
242
/// Compile the [`Tr`] descriptor into optimized [`TapTree`] implementation
243
+ // TODO: We might require other compile errors for Taproot. Will discuss and update.
156
244
#[ cfg( feature = "compiler" ) ]
157
245
pub fn compile_tr ( & self , unspendable_key : Option < Pk > ) -> Result < Descriptor < Pk > , Error > {
158
246
let ( internal_key, policy) = Self :: extract_key ( self , unspendable_key) . unwrap ( ) ;
159
- let tree = Descriptor :: new_tr (
160
- internal_key,
161
- Some ( Self :: compile_huffman_taptree ( policy) . unwrap ( ) ) ,
162
- )
163
- . unwrap ( ) ;
247
+ let tree =
248
+ Descriptor :: new_tr ( internal_key, Some ( policy. compile_tr_policy ( ) . unwrap ( ) ) ) . unwrap ( ) ;
164
249
Ok ( tree)
165
250
}
166
251
@@ -264,6 +349,30 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
264
349
}
265
350
}
266
351
352
+ /// Translate `Semantic::Key(key)` to `Semantic::Unsatisfiable` when extracting TapKey
353
+ pub fn translate_unsatisfiable_pk ( & self , key : & Pk ) -> Policy < Pk > {
354
+ match self {
355
+ Policy :: Key ( k) if * k == * key => Policy :: Unsatisfiable ,
356
+ Policy :: And ( ref subs) => Policy :: And (
357
+ subs. iter ( )
358
+ . map ( |sub| sub. translate_unsatisfiable_pk ( key) )
359
+ . collect :: < Vec < _ > > ( ) ,
360
+ ) ,
361
+ Policy :: Or ( ref subs) => Policy :: Or (
362
+ subs. iter ( )
363
+ . map ( |( k, sub) | ( * k, sub. translate_unsatisfiable_pk ( key) ) )
364
+ . collect :: < Vec < _ > > ( ) ,
365
+ ) ,
366
+ Policy :: Threshold ( k, ref subs) => Policy :: Threshold (
367
+ * k,
368
+ subs. iter ( )
369
+ . map ( |sub| sub. translate_unsatisfiable_pk ( key) )
370
+ . collect :: < Vec < _ > > ( ) ,
371
+ ) ,
372
+ x => x. clone ( ) ,
373
+ }
374
+ }
375
+
267
376
/// Get all keys in the policy
268
377
pub fn keys ( & self ) -> Vec < & Pk > {
269
378
match * self {
0 commit comments