@@ -20,20 +20,27 @@ use std::{error, fmt, str};
20
20
21
21
use bitcoin:: hashes:: hex:: FromHex ;
22
22
use bitcoin:: hashes:: { hash160, ripemd160, sha256, sha256d} ;
23
+ #[ cfg( feature = "compiler" ) ]
24
+ use {
25
+ crate :: descriptor:: TapTree ,
26
+ crate :: miniscript:: ScriptContext ,
27
+ crate :: policy:: compiler:: CompilerError ,
28
+ crate :: policy:: compiler:: OrdF64 ,
29
+ crate :: policy:: { compiler, Concrete , Liftable , Semantic } ,
30
+ crate :: Descriptor ,
31
+ crate :: Miniscript ,
32
+ crate :: Tap ,
33
+ std:: cmp:: Reverse ,
34
+ std:: collections:: { BinaryHeap , HashMap } ,
35
+ std:: sync:: Arc ,
36
+ } ;
23
37
24
38
use super :: ENTAILMENT_MAX_TERMINALS ;
25
39
use crate :: expression:: { self , FromTree } ;
26
40
use crate :: miniscript:: limits:: { HEIGHT_TIME_THRESHOLD , SEQUENCE_LOCKTIME_TYPE_FLAG } ;
27
41
use crate :: miniscript:: types:: extra_props:: TimeLockInfo ;
28
- #[ cfg( feature = "compiler" ) ]
29
- use crate :: miniscript:: ScriptContext ;
30
- #[ cfg( feature = "compiler" ) ]
31
- use crate :: policy:: compiler;
32
- #[ cfg( feature = "compiler" ) ]
33
- use crate :: policy:: compiler:: CompilerError ;
34
- #[ cfg( feature = "compiler" ) ]
35
- use crate :: Miniscript ;
36
42
use crate :: { errstr, Error , ForEach , ForEachKey , MiniscriptKey } ;
43
+
37
44
/// Concrete policy which corresponds directly to a Miniscript structure,
38
45
/// and whose disjunctions are annotated with satisfaction probabilities
39
46
/// to assist the compiler
@@ -128,6 +135,136 @@ impl fmt::Display for PolicyError {
128
135
}
129
136
130
137
impl < Pk : MiniscriptKey > Policy < Pk > {
138
+ /// Flatten the [`Policy`] tree structure into a Vector of tuple `(leaf script, leaf probability)`
139
+ /// with leaf probabilities corresponding to odds for sub-branch in the policy.
140
+ /// We calculate the probability of selecting the sub-branch at every level and calculate the
141
+ /// leaf probabilities as the probability of traversing through required branches to reach the
142
+ /// leaf node, i.e. multiplication of the respective probabilities.
143
+ ///
144
+ /// For example, the policy tree: OR
145
+ /// / \
146
+ /// 2 1 odds
147
+ /// / \
148
+ /// A OR
149
+ /// / \
150
+ /// 3 1 odds
151
+ /// / \
152
+ /// B C
153
+ ///
154
+ /// gives the vector [(2/3, A), (1/3 * 3/4, B), (1/3 * 1/4, C)].
155
+ #[ cfg( feature = "compiler" ) ]
156
+ fn to_tapleaf_prob_vec ( & self , prob : f64 ) -> Vec < ( f64 , Policy < Pk > ) > {
157
+ match * self {
158
+ Policy :: Or ( ref subs) => {
159
+ let total_odds: usize = subs. iter ( ) . map ( |( ref k, _) | k) . sum ( ) ;
160
+ subs. iter ( )
161
+ . map ( |( k, ref policy) | {
162
+ policy. to_tapleaf_prob_vec ( prob * * k as f64 / total_odds as f64 )
163
+ } )
164
+ . flatten ( )
165
+ . collect :: < Vec < _ > > ( )
166
+ }
167
+ Policy :: Threshold ( k, ref subs) if k == 1 => {
168
+ let total_odds = subs. len ( ) ;
169
+ subs. iter ( )
170
+ . map ( |policy| policy. to_tapleaf_prob_vec ( prob / total_odds as f64 ) )
171
+ . flatten ( )
172
+ . collect :: < Vec < _ > > ( )
173
+ }
174
+ ref x => vec ! [ ( prob, x. clone( ) ) ] ,
175
+ }
176
+ }
177
+
178
+ /// Compile [`Policy::Or`] and [`Policy::Threshold`] according to odds
179
+ #[ cfg( feature = "compiler" ) ]
180
+ fn compile_tr_policy ( & self ) -> Result < TapTree < Pk > , Error > {
181
+ let leaf_compilations: Vec < _ > = self
182
+ . to_tapleaf_prob_vec ( 1.0 )
183
+ . into_iter ( )
184
+ . filter ( |x| x. 1 != Policy :: Unsatisfiable )
185
+ . map ( |( prob, ref policy) | ( OrdF64 ( prob) , compiler:: best_compilation ( policy) . unwrap ( ) ) )
186
+ . collect ( ) ;
187
+ let taptree = with_huffman_tree :: < Pk > ( leaf_compilations) . unwrap ( ) ;
188
+ Ok ( taptree)
189
+ }
190
+
191
+ /// Extract the internal_key from policy tree.
192
+ #[ cfg( feature = "compiler" ) ]
193
+ fn extract_key ( self , unspendable_key : Option < Pk > ) -> Result < ( Pk , Policy < Pk > ) , Error > {
194
+ let mut internal_key: Option < Pk > = None ;
195
+ {
196
+ let mut prob = 0. ;
197
+ let semantic_policy = self . lift ( ) ?;
198
+ let concrete_keys = self . keys ( ) ;
199
+ let key_prob_map: HashMap < _ , _ > = self
200
+ . to_tapleaf_prob_vec ( 1.0 )
201
+ . into_iter ( )
202
+ . filter ( |( _, ref pol) | match * pol {
203
+ Concrete :: Key ( ..) => true ,
204
+ _ => false ,
205
+ } )
206
+ . map ( |( prob, key) | ( key, prob) )
207
+ . collect ( ) ;
208
+
209
+ for key in concrete_keys. into_iter ( ) {
210
+ if semantic_policy
211
+ . clone ( )
212
+ . satisfy_constraint ( & Semantic :: KeyHash ( key. to_pubkeyhash ( ) ) , true )
213
+ == Semantic :: Trivial
214
+ {
215
+ match key_prob_map. get ( & Concrete :: Key ( key. clone ( ) ) ) {
216
+ Some ( val) => {
217
+ if * val > prob {
218
+ prob = * val;
219
+ internal_key = Some ( key. clone ( ) ) ;
220
+ }
221
+ }
222
+ None => return Err ( errstr ( "Key should have existed in the HashMap!" ) ) ,
223
+ }
224
+ }
225
+ }
226
+ }
227
+ match ( internal_key, unspendable_key) {
228
+ ( Some ( ref key) , _) => Ok ( ( key. clone ( ) , self . translate_unsatisfiable_pk ( & key) ) ) ,
229
+ ( _, Some ( key) ) => Ok ( ( key, self ) ) ,
230
+ _ => Err ( errstr ( "No viable internal key found." ) ) ,
231
+ }
232
+ }
233
+
234
+ /// Compile the [`Policy`] into a [`Tr`][`Descriptor::Tr`] Descriptor.
235
+ ///
236
+ /// ### TapTree compilation
237
+ ///
238
+ /// The policy tree constructed by root-level disjunctions over [`Or`][`Policy::Or`] and
239
+ /// [`Thresh`][`Policy::Threshold`](1, ..) which is flattened into a vector (with respective
240
+ /// probabilities derived from odds) of policies.
241
+ /// For example, the policy `thresh(1,or(pk(A),pk(B)),and(or(pk(C),pk(D)),pk(E)))` gives the vector
242
+ /// `[pk(A),pk(B),and(or(pk(C),pk(D)),pk(E)))]`. Each policy in the vector is compiled into
243
+ /// the respective miniscripts. A Huffman Tree is created from this vector which optimizes over
244
+ /// the probabilitity of satisfaction for the respective branch in the TapTree.
245
+ // TODO: We might require other compile errors for Taproot.
246
+ #[ cfg( feature = "compiler" ) ]
247
+ pub fn compile_tr ( & self , unspendable_key : Option < Pk > ) -> Result < Descriptor < Pk > , Error > {
248
+ self . is_valid ( ) ?; // Check for validity
249
+ match self . is_safe_nonmalleable ( ) {
250
+ ( false , _) => Err ( Error :: from ( CompilerError :: TopLevelNonSafe ) ) ,
251
+ ( _, false ) => Err ( Error :: from (
252
+ CompilerError :: ImpossibleNonMalleableCompilation ,
253
+ ) ) ,
254
+ _ => {
255
+ let ( internal_key, policy) = self . clone ( ) . extract_key ( unspendable_key) ?;
256
+ let tree = Descriptor :: new_tr (
257
+ internal_key,
258
+ match policy {
259
+ Policy :: Trivial => None ,
260
+ policy => Some ( policy. compile_tr_policy ( ) ?) ,
261
+ } ,
262
+ ) ?;
263
+ Ok ( tree)
264
+ }
265
+ }
266
+ }
267
+
131
268
/// Compile the descriptor into an optimized `Miniscript` representation
132
269
#[ cfg( feature = "compiler" ) ]
133
270
pub fn compile < Ctx : ScriptContext > ( & self ) -> Result < Miniscript < Pk , Ctx > , CompilerError > {
@@ -226,6 +363,30 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
226
363
}
227
364
}
228
365
366
+ /// Translate `Concrete::Key(key)` to `Concrete::Unsatisfiable` when extracting TapKey
367
+ pub fn translate_unsatisfiable_pk ( self , key : & Pk ) -> Policy < Pk > {
368
+ match self {
369
+ Policy :: Key ( ref k) if k. clone ( ) == * key => Policy :: Unsatisfiable ,
370
+ Policy :: And ( subs) => Policy :: And (
371
+ subs. into_iter ( )
372
+ . map ( |sub| sub. translate_unsatisfiable_pk ( key) )
373
+ . collect :: < Vec < _ > > ( ) ,
374
+ ) ,
375
+ Policy :: Or ( subs) => Policy :: Or (
376
+ subs. into_iter ( )
377
+ . map ( |( k, sub) | ( k, sub. translate_unsatisfiable_pk ( key) ) )
378
+ . collect :: < Vec < _ > > ( ) ,
379
+ ) ,
380
+ Policy :: Threshold ( k, subs) => Policy :: Threshold (
381
+ k,
382
+ subs. into_iter ( )
383
+ . map ( |sub| sub. translate_unsatisfiable_pk ( key) )
384
+ . collect :: < Vec < _ > > ( ) ,
385
+ ) ,
386
+ x => x,
387
+ }
388
+ }
389
+
229
390
/// Get all keys in the policy
230
391
pub fn keys ( & self ) -> Vec < & Pk > {
231
392
match * self {
@@ -645,3 +806,34 @@ where
645
806
Policy :: from_tree_prob ( top, false ) . map ( |( _, result) | result)
646
807
}
647
808
}
809
+
810
+ /// Create a Huffman Tree from compiled [Miniscript] nodes
811
+ #[ cfg( feature = "compiler" ) ]
812
+ fn with_huffman_tree < Pk : MiniscriptKey > (
813
+ ms : Vec < ( OrdF64 , Miniscript < Pk , Tap > ) > ,
814
+ ) -> Result < TapTree < Pk > , Error > {
815
+ let mut node_weights = BinaryHeap :: < ( Reverse < OrdF64 > , TapTree < Pk > ) > :: new ( ) ;
816
+ for ( prob, script) in ms {
817
+ node_weights. push ( ( Reverse ( prob) , TapTree :: Leaf ( Arc :: new ( script) ) ) ) ;
818
+ }
819
+ if node_weights. is_empty ( ) {
820
+ return Err ( errstr ( "Empty Miniscript compilation" ) ) ;
821
+ }
822
+ while node_weights. len ( ) > 1 {
823
+ let ( p1, s1) = node_weights. pop ( ) . expect ( "len must atleast be two" ) ;
824
+ let ( p2, s2) = node_weights. pop ( ) . expect ( "len must atleast be two" ) ;
825
+
826
+ let p = ( p1. 0 ) . 0 + ( p2. 0 ) . 0 ;
827
+ node_weights. push ( (
828
+ Reverse ( OrdF64 ( p) ) ,
829
+ TapTree :: Tree ( Arc :: from ( s1) , Arc :: from ( s2) ) ,
830
+ ) ) ;
831
+ }
832
+
833
+ debug_assert ! ( node_weights. len( ) == 1 ) ;
834
+ let node = node_weights
835
+ . pop ( )
836
+ . expect ( "huffman tree algorithm is broken" )
837
+ . 1 ;
838
+ Ok ( node)
839
+ }
0 commit comments