1818use  bitcoin:: hashes:: hex:: FromHex ; 
1919use  bitcoin:: hashes:: { hash160,  ripemd160,  sha256,  sha256d} ; 
2020use  std:: collections:: HashSet ; 
21- #[ cfg( feature = "compiler" ) ]  
22- use  std:: sync:: Arc ; 
2321use  std:: { error,  fmt,  str} ; 
2422
23+ #[ cfg( feature = "compiler" ) ]  
24+ use  super :: Liftable ; 
2525use  super :: ENTAILMENT_MAX_TERMINALS ; 
2626#[ cfg( feature = "compiler" ) ]  
2727use  descriptor:: TapTree ; 
@@ -32,9 +32,15 @@ use miniscript::types::extra_props::TimeLockInfo;
3232#[ cfg( feature = "compiler" ) ]  
3333use  miniscript:: ScriptContext ; 
3434#[ 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 ; 
3640#[ cfg( feature = "compiler" ) ]  
37- use  policy:: compiler:: CompilerError ; 
41+ use  std:: collections:: BinaryHeap ; 
42+ #[ cfg( feature = "compiler" ) ]  
43+ use  std:: sync:: Arc ; 
3844#[ cfg( feature = "compiler" ) ]  
3945use  Descriptor ; 
4046#[ cfg( feature = "compiler" ) ]  
@@ -137,30 +143,109 @@ impl fmt::Display for PolicyError {
137143} 
138144
139145impl < 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 
141206#[ 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) 
145215    } 
146-     /// Extract the Taproot internal_key from policy tree. 
216+ 
217+     /// Extract the internal_key from policy tree. 
147218#[ 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." ) ) , 
152239        } 
153240    } 
154241
155242    /// Compile the [`Tr`] descriptor into optimized [`TapTree`] implementation 
243+ // TODO: We might require other compile errors for Taproot. Will discuss and update. 
156244    #[ cfg( feature = "compiler" ) ]  
157245    pub  fn  compile_tr ( & self ,  unspendable_key :  Option < Pk > )  -> Result < Descriptor < Pk > ,  Error >  { 
158246        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 ( ) ; 
164249        Ok ( tree) 
165250    } 
166251
@@ -264,6 +349,30 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
264349        } 
265350    } 
266351
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+ 
267376    /// Get all keys in the policy 
268377pub  fn  keys ( & self )  -> Vec < & Pk >  { 
269378        match  * self  { 
0 commit comments