@@ -28,8 +28,14 @@ use crate::miniscript::types::extra_props::TimeLockInfo;
28
28
use crate :: { Error , ForEach , ForEachKey , MiniscriptKey } ;
29
29
#[ cfg( feature = "compiler" ) ]
30
30
use {
31
- crate :: descriptor:: TapTree , crate :: miniscript:: ScriptContext , crate :: policy:: compiler,
32
- crate :: policy:: compiler:: CompilerError , crate :: Descriptor , crate :: Miniscript , crate :: Tap ,
31
+ crate :: descriptor:: TapTree ,
32
+ crate :: miniscript:: ScriptContext ,
33
+ crate :: policy:: compiler:: CompilerError ,
34
+ crate :: policy:: { compiler, Concrete , Liftable , Semantic } ,
35
+ crate :: Descriptor ,
36
+ crate :: Miniscript ,
37
+ crate :: Tap ,
38
+ std:: collections:: HashMap ,
33
39
std:: sync:: Arc ,
34
40
} ;
35
41
@@ -127,7 +133,46 @@ impl fmt::Display for PolicyError {
127
133
}
128
134
129
135
impl < Pk : MiniscriptKey > Policy < Pk > {
130
- /// Single-Node compilation
136
+ /// Flatten the [`Policy`] tree structure into a Vector of tuple `(leaf script, leaf probability)`
137
+ /// with leaf probabilities corresponding to odds for sub-branch in the policy.
138
+ /// We calculate the probability of selecting the sub-branch at every level and calculate the
139
+ /// leaf probabilities as the probability of traversing through required branches to reach the
140
+ /// leaf node, i.e. multiplication of the respective probabilities.
141
+ ///
142
+ /// For example, the policy tree: OR
143
+ /// / \
144
+ /// 2 1 odds
145
+ /// / \
146
+ /// A OR
147
+ /// / \
148
+ /// 3 1 odds
149
+ /// / \
150
+ /// B C
151
+ ///
152
+ /// gives the vector [(2/3, A), (1/3 * 3/4, B), (1/3 * 1/4, C)].
153
+ #[ cfg( feature = "compiler" ) ]
154
+ fn to_tapleaf_prob_vec ( & self , prob : f64 ) -> Vec < ( f64 , Policy < Pk > ) > {
155
+ match * self {
156
+ Policy :: Or ( ref subs) => {
157
+ let total_odds: usize = subs. iter ( ) . map ( |( ref k, _) | k) . sum ( ) ;
158
+ subs. iter ( )
159
+ . map ( |( k, ref policy) | {
160
+ policy. to_tapleaf_prob_vec ( prob * * k as f64 / total_odds as f64 )
161
+ } )
162
+ . flatten ( )
163
+ . collect :: < Vec < _ > > ( )
164
+ }
165
+ Policy :: Threshold ( k, ref subs) if k == 1 => {
166
+ let total_odds = subs. len ( ) ;
167
+ subs. iter ( )
168
+ . map ( |policy| policy. to_tapleaf_prob_vec ( prob / total_odds as f64 ) )
169
+ . flatten ( )
170
+ . collect :: < Vec < _ > > ( )
171
+ }
172
+ ref x => vec ! [ ( prob, x. clone( ) ) ] ,
173
+ }
174
+ }
175
+
131
176
#[ cfg( feature = "compiler" ) ]
132
177
fn compile_leaf_taptree ( & self ) -> Result < TapTree < Pk > , Error > {
133
178
let compilation = self . compile :: < Tap > ( ) . unwrap ( ) ;
@@ -136,17 +181,51 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
136
181
137
182
/// Extract the Taproot internal_key from policy tree.
138
183
#[ cfg( feature = "compiler" ) ]
139
- fn extract_key ( & self , unspendable_key : Option < Pk > ) -> Result < ( Pk , & Policy < Pk > ) , Error > {
140
- match unspendable_key {
141
- Some ( key) => Ok ( ( key, self ) ) ,
142
- None => Err ( errstr ( "No internal key found" ) ) ,
184
+ fn extract_key ( self , unspendable_key : Option < Pk > ) -> Result < ( Pk , Policy < Pk > ) , Error > {
185
+ let mut internal_key: Option < Pk > = None ;
186
+ {
187
+ let mut prob = 0. ;
188
+ let semantic_policy = self . lift ( ) ?;
189
+ let concrete_keys = self . keys ( ) ;
190
+ let key_prob_map: HashMap < _ , _ > = self
191
+ . to_tapleaf_prob_vec ( 1.0 )
192
+ . into_iter ( )
193
+ . filter ( |( _, ref pol) | match * pol {
194
+ Concrete :: Key ( ..) => true ,
195
+ _ => false ,
196
+ } )
197
+ . map ( |( prob, key) | ( key, prob) )
198
+ . collect ( ) ;
199
+
200
+ for key in concrete_keys. into_iter ( ) {
201
+ if semantic_policy
202
+ . clone ( )
203
+ . satisfy_constraint ( & Semantic :: KeyHash ( key. to_pubkeyhash ( ) ) , true )
204
+ == Semantic :: Trivial
205
+ {
206
+ match key_prob_map. get ( & Concrete :: Key ( key. clone ( ) ) ) {
207
+ Some ( val) => {
208
+ if * val > prob {
209
+ prob = * val;
210
+ internal_key = Some ( key. clone ( ) ) ;
211
+ }
212
+ }
213
+ None => return Err ( errstr ( "Key should have existed in the HashMap!" ) ) ,
214
+ }
215
+ }
216
+ }
217
+ }
218
+ match ( internal_key, unspendable_key) {
219
+ ( Some ( ref key) , _) => Ok ( ( key. clone ( ) , self . translate_unsatisfiable_pk ( & key) ) ) ,
220
+ ( _, Some ( key) ) => Ok ( ( key, self ) ) ,
221
+ _ => Err ( errstr ( "No viable internal key found." ) ) ,
143
222
}
144
223
}
145
224
146
225
/// Compile the [`Tr`] descriptor into optimized [`TapTree`] implementation
147
226
#[ cfg( feature = "compiler" ) ]
148
227
pub fn compile_tr ( & self , unspendable_key : Option < Pk > ) -> Result < Descriptor < Pk > , Error > {
149
- let ( internal_key, policy) = self . extract_key ( unspendable_key) ?;
228
+ let ( internal_key, policy) = self . clone ( ) . extract_key ( unspendable_key) ?;
150
229
let tree = Descriptor :: new_tr ( internal_key, Some ( policy. compile_leaf_taptree ( ) ?) ) ?;
151
230
Ok ( tree)
152
231
}
@@ -249,6 +328,30 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
249
328
}
250
329
}
251
330
331
+ /// Translate `Concrete::Key(key)` to `Concrete::Unsatisfiable` when extracting TapKey
332
+ pub fn translate_unsatisfiable_pk ( self , key : & Pk ) -> Policy < Pk > {
333
+ match self {
334
+ Policy :: Key ( ref k) if k. clone ( ) == * key => Policy :: Unsatisfiable ,
335
+ Policy :: And ( subs) => Policy :: And (
336
+ subs. into_iter ( )
337
+ . map ( |sub| sub. translate_unsatisfiable_pk ( key) )
338
+ . collect :: < Vec < _ > > ( ) ,
339
+ ) ,
340
+ Policy :: Or ( subs) => Policy :: Or (
341
+ subs. into_iter ( )
342
+ . map ( |( k, sub) | ( k, sub. translate_unsatisfiable_pk ( key) ) )
343
+ . collect :: < Vec < _ > > ( ) ,
344
+ ) ,
345
+ Policy :: Threshold ( k, subs) => Policy :: Threshold (
346
+ k,
347
+ subs. into_iter ( )
348
+ . map ( |sub| sub. translate_unsatisfiable_pk ( key) )
349
+ . collect :: < Vec < _ > > ( ) ,
350
+ ) ,
351
+ x => x,
352
+ }
353
+ }
354
+
252
355
/// Get all keys in the policy
253
356
pub fn keys ( & self ) -> Vec < & Pk > {
254
357
match * self {
0 commit comments