@@ -27,8 +27,14 @@ use miniscript::limits::{HEIGHT_TIME_THRESHOLD, SEQUENCE_LOCKTIME_TYPE_FLAG};
2727use  miniscript:: types:: extra_props:: TimeLockInfo ; 
2828#[ cfg( feature = "compiler" ) ]  
2929use  { 
30-     descriptor:: TapTree ,  miniscript:: ScriptContext ,  policy:: compiler, 
31-     policy:: compiler:: CompilerError ,  std:: sync:: Arc ,  Descriptor ,  Miniscript ,  Tap , 
30+     descriptor:: TapTree , 
31+     miniscript:: ScriptContext , 
32+     policy:: compiler:: { CompilerError ,  OrdF64 } , 
33+     policy:: { compiler,  Liftable ,  Semantic } , 
34+     std:: cmp:: Reverse , 
35+     std:: collections:: BinaryHeap , 
36+     std:: sync:: Arc , 
37+     Descriptor ,  Miniscript ,  Tap , 
3238} ; 
3339use  { Error ,  ForEach ,  ForEachKey ,  MiniscriptKey } ; 
3440
@@ -126,27 +132,118 @@ impl fmt::Display for PolicyError {
126132} 
127133
128134impl < Pk :  MiniscriptKey >  Policy < Pk >  { 
129-     /// Single-Node compilation  
135+     /// Create a Huffman Tree from compiled [Miniscript] nodes  
130136#[ cfg( feature = "compiler" ) ]  
131-     fn  compile_leaf_taptree ( & self )  -> Result < TapTree < Pk > ,  Error >  { 
132-         let  compilation = self . compile :: < Tap > ( ) . unwrap ( ) ; 
133-         Ok ( TapTree :: Leaf ( Arc :: new ( compilation) ) ) 
137+     fn  with_huffman_tree < T > ( 
138+         ms :  Vec < ( OrdF64 ,  Miniscript < Pk ,  Tap > ) > , 
139+         f :  T , 
140+     )  -> Result < TapTree < Pk > ,  Error > 
141+     where 
142+         T :  Fn ( OrdF64 )  -> OrdF64 , 
143+     { 
144+         // Pattern match terminal Or/ Terminal (with equal odds) 
145+         let  mut  node_weights = BinaryHeap :: < ( Reverse < OrdF64 > ,  TapTree < Pk > ) > :: new ( ) ; 
146+         for  ( prob,  script)  in  ms { 
147+             node_weights. push ( ( Reverse ( f ( prob) ) ,  TapTree :: Leaf ( Arc :: new ( script) ) ) ) ; 
148+         } 
149+         if  node_weights. is_empty ( )  { 
150+             return  Err ( errstr ( "Empty Miniscript compilation" ) ) ; 
151+         } 
152+         while  node_weights. len ( )  > 1  { 
153+             let  ( p1,  s1)  = node_weights. pop ( ) . expect ( "len must atleast be two" ) ; 
154+             let  ( p2,  s2)  = node_weights. pop ( ) . expect ( "len must atleast be two" ) ; 
155+ 
156+             let  p = ( p1. 0 ) . 0  + ( p2. 0 ) . 0 ; 
157+             node_weights. push ( ( 
158+                 Reverse ( OrdF64 ( p) ) , 
159+                 TapTree :: Tree ( Arc :: from ( s1) ,  Arc :: from ( s2) ) , 
160+             ) ) ; 
161+         } 
162+ 
163+         debug_assert ! ( node_weights. len( )  == 1 ) ; 
164+         let  node = node_weights
165+             . pop ( ) 
166+             . expect ( "huffman tree algorithm is broken" ) 
167+             . 1 ; 
168+         Ok ( node) 
134169    } 
135170
136-     /// Extract the Taproot internal_key from policy tree. 
171+     /// Flatten the [`Policy`] tree structure into a Vector with corresponding leaf probability 
172+ // TODO: 1. Can try to push the maximum of scaling factors and accordingly update later for 
173+     // TODO: 1. integer metric. (Accordingly change metrics everywhere) 
137174    #[ cfg( feature = "compiler" ) ]  
138-     fn  extract_key ( & self ,  unspendable_key :  Option < Pk > )  -> Result < ( Pk ,  & Policy < Pk > ) ,  Error >  { 
139-         match  unspendable_key { 
140-             Some ( key)  => Ok ( ( key,  self ) ) , 
141-             None  => Err ( errstr ( "No internal key found" ) ) , 
175+     fn  to_tapleaf_prob_vec ( & self ,  prob :  f64 )  -> Vec < ( f64 ,  Policy < Pk > ) >  { 
176+         match  * self  { 
177+             Policy :: Or ( ref  subs)  => { 
178+                 let  total_odds:  usize  = subs. iter ( ) . map ( |( ref  k,  _) | k) . sum ( ) ; 
179+                 subs. iter ( ) 
180+                     . map ( |( k,  ref  policy) | { 
181+                         policy. to_tapleaf_prob_vec ( prob *  * k as  f64  / total_odds as  f64 ) 
182+                     } ) 
183+                     . flatten ( ) 
184+                     . collect :: < Vec < _ > > ( ) 
185+             } 
186+             Policy :: Threshold ( k,  ref  subs)  if  k == 1  => { 
187+                 let  total_odds = subs. len ( ) ; 
188+                 subs. iter ( ) 
189+                     . map ( |policy| policy. to_tapleaf_prob_vec ( prob / total_odds as  f64 ) ) 
190+                     . flatten ( ) 
191+                     . collect :: < Vec < _ > > ( ) 
192+             } 
193+             ref  x => vec ! [ ( prob,  x. clone( ) ) ] , 
194+         } 
195+     } 
196+ 
197+     /// Compile [`Policy::Or`] and [`Policy::Threshold`] according to odds 
198+ #[ cfg( feature = "compiler" ) ]  
199+     fn  compile_tr_policy ( & self )  -> Result < TapTree < Pk > ,  Error >  { 
200+         let  leaf_compilations:  Vec < _ >  = self 
201+             . to_tapleaf_prob_vec ( 1.0 ) 
202+             . into_iter ( ) 
203+             . map ( |( prob,  ref  policy) | ( OrdF64 ( prob) ,  policy. compile :: < Tap > ( ) . unwrap ( ) ) ) 
204+             . collect ( ) ; 
205+         let  taptree = Self :: with_huffman_tree ( leaf_compilations,  |x| x) . unwrap ( ) ; 
206+         Ok ( taptree) 
207+     } 
208+ 
209+     /// Extract the internal_key from policy tree. 
210+ #[ cfg( feature = "compiler" ) ]  
211+     fn  extract_key ( self ,  unspendable_key :  Option < Pk > )  -> Result < ( Pk ,  Policy < Pk > ) ,  Error >  { 
212+         // Making sure the borrow ends before you move the value. 
213+         let  mut  internal_key:  Option < Pk >  = None ; 
214+         { 
215+             let  semantic_policy = ( & self ) . lift ( ) ?; 
216+             let  concrete_keys = ( & self ) . keys ( ) . into_iter ( ) . collect :: < HashSet < _ > > ( ) ; 
217+             for  key in  concrete_keys. iter ( )  { 
218+                 if  semantic_policy
219+                     . clone ( ) 
220+                     . satisfy_constraint ( & Semantic :: KeyHash ( key. to_pubkeyhash ( ) ) ,  true ) 
221+                     == Semantic :: Trivial 
222+                 { 
223+                     internal_key = Some ( ( * key) . clone ( ) ) ; 
224+                     break ; 
225+                 } 
226+             } 
227+         } 
228+         match  ( internal_key,  unspendable_key)  { 
229+             ( Some ( ref  key) ,  _)  => Ok ( ( key. clone ( ) ,  self . translate_unsatisfiable_pk ( & key) ) ) , 
230+             ( _,  Some ( key) )  => Ok ( ( key,  self ) ) , 
231+             _ => Err ( errstr ( "No viable internal key found." ) ) , 
142232        } 
143233    } 
144234
145235    /// Compile the [`Tr`] descriptor into optimized [`TapTree`] implementation 
236+ // TODO: We might require other compile errors for Taproot. Will discuss and update. 
146237    #[ cfg( feature = "compiler" ) ]  
147238    pub  fn  compile_tr ( & self ,  unspendable_key :  Option < Pk > )  -> Result < Descriptor < Pk > ,  Error >  { 
148-         let  ( internal_key,  policy)  = self . extract_key ( unspendable_key) ?; 
149-         let  tree = Descriptor :: new_tr ( internal_key,  Some ( policy. compile_leaf_taptree ( ) ?) ) ?; 
239+         let  ( internal_key,  policy)  = self . clone ( ) . extract_key ( unspendable_key) ?; 
240+         let  tree = Descriptor :: new_tr ( 
241+             internal_key, 
242+             match  policy { 
243+                 Policy :: Trivial  => None , 
244+                 policy => Some ( policy. compile_tr_policy ( ) ?) , 
245+             } , 
246+         ) ?; 
150247        Ok ( tree) 
151248    } 
152249
@@ -250,6 +347,30 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
250347        } 
251348    } 
252349
350+     /// Translate `Semantic::Key(key)` to `Semantic::Unsatisfiable` when extracting TapKey 
351+ pub  fn  translate_unsatisfiable_pk ( self ,  key :  & Pk )  -> Policy < Pk >  { 
352+         match  self  { 
353+             Policy :: Key ( ref  k)  if  k. clone ( )  == * key => Policy :: Unsatisfiable , 
354+             Policy :: And ( subs)  => Policy :: And ( 
355+                 subs. into_iter ( ) 
356+                     . map ( |sub| sub. translate_unsatisfiable_pk ( key) ) 
357+                     . collect :: < Vec < _ > > ( ) , 
358+             ) , 
359+             Policy :: Or ( subs)  => Policy :: Or ( 
360+                 subs. into_iter ( ) 
361+                     . map ( |( k,  sub) | ( k,  sub. translate_unsatisfiable_pk ( key) ) ) 
362+                     . collect :: < Vec < _ > > ( ) , 
363+             ) , 
364+             Policy :: Threshold ( k,  subs)  => Policy :: Threshold ( 
365+                 k, 
366+                 subs. into_iter ( ) 
367+                     . map ( |sub| sub. translate_unsatisfiable_pk ( key) ) 
368+                     . collect :: < Vec < _ > > ( ) , 
369+             ) , 
370+             x => x, 
371+         } 
372+     } 
373+ 
253374    /// Get all keys in the policy 
254375pub  fn  keys ( & self )  -> Vec < & Pk >  { 
255376        match  * self  { 
0 commit comments