@@ -27,8 +27,15 @@ 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:: Concrete ,
34
+ policy:: { compiler, Liftable , Semantic } ,
35
+ std:: cmp:: Reverse ,
36
+ std:: collections:: { BinaryHeap , HashMap } ,
37
+ std:: sync:: Arc ,
38
+ Descriptor , Miniscript , Tap ,
32
39
} ;
33
40
use { Error , ForEach , ForEachKey , MiniscriptKey } ;
34
41
@@ -126,27 +133,137 @@ impl fmt::Display for PolicyError {
126
133
}
127
134
128
135
impl < Pk : MiniscriptKey > Policy < Pk > {
129
- /// Single-Node compilation
136
+ /// Create a Huffman Tree from compiled [Miniscript] nodes
130
137
#[ 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) ) )
138
+ fn with_huffman_tree < T > (
139
+ ms : Vec < ( OrdF64 , Miniscript < Pk , Tap > ) > ,
140
+ f : T ,
141
+ ) -> Result < TapTree < Pk > , Error >
142
+ where
143
+ T : Fn ( OrdF64 ) -> OrdF64 ,
144
+ {
145
+ // Pattern match terminal Or/ Terminal (with equal odds)
146
+ let mut node_weights = BinaryHeap :: < ( Reverse < OrdF64 > , TapTree < Pk > ) > :: new ( ) ;
147
+ for ( prob, script) in ms {
148
+ node_weights. push ( ( Reverse ( f ( prob) ) , TapTree :: Leaf ( Arc :: new ( script) ) ) ) ;
149
+ }
150
+ if node_weights. is_empty ( ) {
151
+ return Err ( errstr ( "Empty Miniscript compilation" ) ) ;
152
+ }
153
+ while node_weights. len ( ) > 1 {
154
+ let ( p1, s1) = node_weights. pop ( ) . expect ( "len must atleast be two" ) ;
155
+ let ( p2, s2) = node_weights. pop ( ) . expect ( "len must atleast be two" ) ;
156
+
157
+ let p = ( p1. 0 ) . 0 + ( p2. 0 ) . 0 ;
158
+ node_weights. push ( (
159
+ Reverse ( OrdF64 ( p) ) ,
160
+ TapTree :: Tree ( Arc :: from ( s1) , Arc :: from ( s2) ) ,
161
+ ) ) ;
162
+ }
163
+
164
+ debug_assert ! ( node_weights. len( ) == 1 ) ;
165
+ let node = node_weights
166
+ . pop ( )
167
+ . expect ( "huffman tree algorithm is broken" )
168
+ . 1 ;
169
+ Ok ( node)
134
170
}
135
171
136
- /// Extract the Taproot internal_key from policy tree.
172
+ /// Flatten the [`Policy`] tree structure into a Vector with corresponding leaf probability
173
+ // TODO: 1. Can try to push the maximum of scaling factors and accordingly update later for
174
+ // TODO: 1. integer metric. (Accordingly change metrics everywhere)
137
175
#[ 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" ) ) ,
176
+ fn to_tapleaf_prob_vec ( & self , prob : f64 ) -> Vec < ( f64 , Policy < Pk > ) > {
177
+ match * self {
178
+ Policy :: Or ( ref subs) => {
179
+ let total_odds: usize = subs. iter ( ) . map ( |( ref k, _) | k) . sum ( ) ;
180
+ subs. iter ( )
181
+ . map ( |( k, ref policy) | {
182
+ policy. to_tapleaf_prob_vec ( prob * * k as f64 / total_odds as f64 )
183
+ } )
184
+ . flatten ( )
185
+ . collect :: < Vec < _ > > ( )
186
+ }
187
+ Policy :: Threshold ( k, ref subs) if k == 1 => {
188
+ let total_odds = subs. len ( ) ;
189
+ subs. iter ( )
190
+ . map ( |policy| policy. to_tapleaf_prob_vec ( prob / total_odds as f64 ) )
191
+ . flatten ( )
192
+ . collect :: < Vec < _ > > ( )
193
+ }
194
+ ref x => vec ! [ ( prob, x. clone( ) ) ] ,
195
+ }
196
+ }
197
+
198
+ /// Compile [`Policy::Or`] and [`Policy::Threshold`] according to odds
199
+ #[ cfg( feature = "compiler" ) ]
200
+ fn compile_tr_policy ( & self ) -> Result < TapTree < Pk > , Error > {
201
+ let leaf_compilations: Vec < _ > = self
202
+ . to_tapleaf_prob_vec ( 1.0 )
203
+ . into_iter ( )
204
+ . filter ( |x| x. 1 != Policy :: Unsatisfiable )
205
+ . map ( |( prob, ref policy) | ( OrdF64 ( prob) , compiler:: best_compilation ( policy) . unwrap ( ) ) )
206
+ . collect ( ) ;
207
+ let taptree = Self :: with_huffman_tree ( leaf_compilations, |x| x) . unwrap ( ) ;
208
+ Ok ( taptree)
209
+ }
210
+
211
+ /// Extract the internal_key from policy tree.
212
+ #[ cfg( feature = "compiler" ) ]
213
+ fn extract_key ( self , unspendable_key : Option < Pk > ) -> Result < ( Pk , Policy < Pk > ) , Error > {
214
+ // Making sure the borrow ends before you move the value.
215
+ let mut internal_key: Option < Pk > = None ;
216
+ {
217
+ let mut prob = 0. ;
218
+ let semantic_policy = self . lift ( ) ?;
219
+ let concrete_keys = self . keys ( ) ;
220
+ let key_prob_map: HashMap < _ , _ > = self
221
+ . to_tapleaf_prob_vec ( 1.0 )
222
+ . into_iter ( )
223
+ . filter ( |( _, ref pol) | match * pol {
224
+ Concrete :: Key ( ..) => true ,
225
+ _ => false ,
226
+ } )
227
+ . map ( |( prob, key) | ( key, prob) )
228
+ . collect ( ) ;
229
+
230
+ for key in concrete_keys. into_iter ( ) {
231
+ if semantic_policy
232
+ . clone ( )
233
+ . satisfy_constraint ( & Semantic :: KeyHash ( key. to_pubkeyhash ( ) ) , true )
234
+ == Semantic :: Trivial
235
+ {
236
+ match key_prob_map. get ( & Concrete :: Key ( key. clone ( ) ) ) {
237
+ Some ( val) => {
238
+ if * val > prob {
239
+ prob = * val;
240
+ internal_key = Some ( key. clone ( ) ) ;
241
+ }
242
+ }
243
+ None => return Err ( errstr ( "Key should have existed in the HashMap!" ) ) ,
244
+ }
245
+ }
246
+ }
247
+ }
248
+ match ( internal_key, unspendable_key) {
249
+ ( Some ( ref key) , _) => Ok ( ( key. clone ( ) , self . translate_unsatisfiable_pk ( & key) ) ) ,
250
+ ( _, Some ( key) ) => Ok ( ( key, self ) ) ,
251
+ _ => Err ( errstr ( "No viable internal key found." ) ) ,
142
252
}
143
253
}
144
254
145
255
/// Compile the [`Tr`] descriptor into optimized [`TapTree`] implementation
256
+ // TODO: We might require other compile errors for Taproot. Will discuss and update.
146
257
#[ cfg( feature = "compiler" ) ]
147
258
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 ( ) ?) ) ?;
259
+ let ( internal_key, policy) = self . clone ( ) . extract_key ( unspendable_key) ?;
260
+ let tree = Descriptor :: new_tr (
261
+ internal_key,
262
+ match policy {
263
+ Policy :: Trivial => None ,
264
+ policy => Some ( policy. compile_tr_policy ( ) ?) ,
265
+ } ,
266
+ ) ?;
150
267
Ok ( tree)
151
268
}
152
269
@@ -250,6 +367,30 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
250
367
}
251
368
}
252
369
370
+ /// Translate `Semantic::Key(key)` to `Semantic::Unsatisfiable` when extracting TapKey
371
+ pub fn translate_unsatisfiable_pk ( self , key : & Pk ) -> Policy < Pk > {
372
+ match self {
373
+ Policy :: Key ( ref k) if k. clone ( ) == * key => Policy :: Unsatisfiable ,
374
+ Policy :: And ( subs) => Policy :: And (
375
+ subs. into_iter ( )
376
+ . map ( |sub| sub. translate_unsatisfiable_pk ( key) )
377
+ . collect :: < Vec < _ > > ( ) ,
378
+ ) ,
379
+ Policy :: Or ( subs) => Policy :: Or (
380
+ subs. into_iter ( )
381
+ . map ( |( k, sub) | ( k, sub. translate_unsatisfiable_pk ( key) ) )
382
+ . collect :: < Vec < _ > > ( ) ,
383
+ ) ,
384
+ Policy :: Threshold ( k, subs) => Policy :: Threshold (
385
+ k,
386
+ subs. into_iter ( )
387
+ . map ( |sub| sub. translate_unsatisfiable_pk ( key) )
388
+ . collect :: < Vec < _ > > ( ) ,
389
+ ) ,
390
+ x => x,
391
+ }
392
+ }
393
+
253
394
/// Get all keys in the policy
254
395
pub fn keys ( & self ) -> Vec < & Pk > {
255
396
match * self {
0 commit comments