@@ -27,8 +27,14 @@ use miniscript::limits::{HEIGHT_TIME_THRESHOLD, SEQUENCE_LOCKTIME_TYPE_FLAG};
27
27
use miniscript:: types:: extra_props:: TimeLockInfo ;
28
28
#[ cfg( feature = "compiler" ) ]
29
29
use {
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 ,
32
38
} ;
33
39
use { Error , ForEach , ForEachKey , MiniscriptKey } ;
34
40
@@ -126,27 +132,118 @@ impl fmt::Display for PolicyError {
126
132
}
127
133
128
134
impl < Pk : MiniscriptKey > Policy < Pk > {
129
- /// Single-Node compilation
135
+ /// Create a Huffman Tree from compiled [Miniscript] nodes
130
136
#[ 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)
134
169
}
135
170
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)
137
174
#[ 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." ) ) ,
142
232
}
143
233
}
144
234
145
235
/// Compile the [`Tr`] descriptor into optimized [`TapTree`] implementation
236
+ // TODO: We might require other compile errors for Taproot. Will discuss and update.
146
237
#[ cfg( feature = "compiler" ) ]
147
238
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
+ ) ?;
150
247
Ok ( tree)
151
248
}
152
249
@@ -250,6 +347,30 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
250
347
}
251
348
}
252
349
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
+
253
374
/// Get all keys in the policy
254
375
pub fn keys ( & self ) -> Vec < & Pk > {
255
376
match * self {
0 commit comments