@@ -13,7 +13,7 @@ use sync::Arc;
1313
1414use crate :: miniscript:: context:: SigType ;
1515use crate :: miniscript:: limits:: { MAX_PUBKEYS_IN_CHECKSIGADD , MAX_PUBKEYS_PER_MULTISIG } ;
16- use crate :: miniscript:: types:: { self , ErrorKind , ExtData , Type } ;
16+ use crate :: miniscript:: types:: { self , ErrorKind , Type } ;
1717use crate :: miniscript:: ScriptContext ;
1818use crate :: policy:: Concrete ;
1919use crate :: prelude:: * ;
@@ -353,7 +353,7 @@ impl CompilerExtData {
353353 fn and_or ( a : Self , b : Self , c : Self ) -> Self {
354354 let aprob = a. branch_prob . expect ( "andor, a prob must be set" ) ;
355355 let bprob = b. branch_prob . expect ( "andor, b prob must be set" ) ;
356- let cprob = c. branch_prob . expect ( "andor, c prob must be set" ) ;
356+ let cprob = c. branch_prob . unwrap_or ( 0.0 ) ;
357357
358358 let adis = a
359359 . dissat_cost
@@ -562,6 +562,55 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> AstElemExt<Pk, Ctx> {
562562 }
563563 }
564564
565+ /// Helper functions to compose two Miniscript fragments, where we assume
566+ /// by construction that all validation parameters are upheld.
567+ fn compose_typeck_only (
568+ term : Terminal < Pk , Ctx > ,
569+ ) -> Result < Arc < Miniscript < Pk , Ctx > > , types:: Error > {
570+ let ty = types:: Type :: type_check ( & term) ?;
571+ let ext = types:: ExtData :: type_check ( & term) ;
572+ Ok ( Arc :: new ( Miniscript :: from_components_unchecked ( term, ty, ext) ) )
573+ }
574+
575+ fn and_b ( left : & Self , right : & Self ) -> Result < Self , types:: Error > {
576+ Ok ( Self {
577+ ms : Self :: compose_typeck_only ( Terminal :: AndB (
578+ Arc :: clone ( & left. ms ) ,
579+ Arc :: clone ( & right. ms ) ,
580+ ) ) ?,
581+ comp_ext_data : CompilerExtData :: and_b ( left. comp_ext_data , right. comp_ext_data ) ,
582+ } )
583+ }
584+
585+ fn and_v ( left : & Self , right : & Self ) -> Result < Self , types:: Error > {
586+ Ok ( Self {
587+ ms : Self :: compose_typeck_only ( Terminal :: AndV (
588+ Arc :: clone ( & left. ms ) ,
589+ Arc :: clone ( & right. ms ) ,
590+ ) ) ?,
591+ comp_ext_data : CompilerExtData :: and_v ( left. comp_ext_data , right. comp_ext_data ) ,
592+ } )
593+ }
594+
595+ /// andor(a,b,0) is a conjunction of a and b
596+ fn and_or_0 ( left : & Self , right : & Self ) -> Result < Self , types:: Error > {
597+ let left_ext_data = CompilerExtData { branch_prob : Some ( 1.0 ) , ..left. comp_ext_data } ;
598+ let right_ext_data = CompilerExtData { branch_prob : Some ( 1.0 ) , ..right. comp_ext_data } ;
599+
600+ Ok ( Self {
601+ ms : Self :: compose_typeck_only ( Terminal :: AndOr (
602+ Arc :: clone ( & left. ms ) ,
603+ Arc :: clone ( & right. ms ) ,
604+ Arc :: new ( Miniscript :: FALSE ) ,
605+ ) ) ?,
606+ comp_ext_data : CompilerExtData :: and_or (
607+ left_ext_data,
608+ right_ext_data,
609+ CompilerExtData :: FALSE ,
610+ ) ,
611+ } )
612+ }
613+
565614 fn binary ( ast : Terminal < Pk , Ctx > , l : & Self , r : & Self ) -> Result < Self , types:: Error > {
566615 let lookup_ext = |n| match n {
567616 0 => l. comp_ext_data ,
@@ -861,26 +910,92 @@ where
861910 Concrete :: Hash160 ( ref hash) => insert_wrap ! ( AstElemExt :: hash160( hash. clone( ) ) ) ,
862911 Concrete :: And ( ref subs) => {
863912 assert_eq ! ( subs. len( ) , 2 , "and takes 2 args" ) ;
864- let mut left =
865- best_compilations ( policy_cache, subs[ 0 ] . as_ref ( ) , sat_prob, dissat_prob) ?;
866- let mut right =
867- best_compilations ( policy_cache, subs[ 1 ] . as_ref ( ) , sat_prob, dissat_prob) ?;
868- let mut q_zero_right =
869- best_compilations ( policy_cache, subs[ 1 ] . as_ref ( ) , sat_prob, None ) ?;
870- let mut q_zero_left =
871- best_compilations ( policy_cache, subs[ 0 ] . as_ref ( ) , sat_prob, None ) ?;
872-
873- compile_binary ! ( & mut left, & mut right, [ 1.0 , 1.0 ] , Terminal :: AndB ) ;
874- compile_binary ! ( & mut right, & mut left, [ 1.0 , 1.0 ] , Terminal :: AndB ) ;
875- compile_binary ! ( & mut left, & mut right, [ 1.0 , 1.0 ] , Terminal :: AndV ) ;
876- compile_binary ! ( & mut right, & mut left, [ 1.0 , 1.0 ] , Terminal :: AndV ) ;
877- let mut zero_comp = BTreeMap :: new ( ) ;
878- zero_comp. insert (
879- CompilationKey :: from_type ( Type :: FALSE , ExtData :: FALSE . has_free_verify , dissat_prob) ,
880- AstElemExt :: unsatisfiable ( ) ,
881- ) ;
882- compile_tern ! ( & mut left, & mut q_zero_right, & mut zero_comp, [ 1.0 , 0.0 ] ) ;
883- compile_tern ! ( & mut right, & mut q_zero_left, & mut zero_comp, [ 1.0 , 0.0 ] ) ;
913+ let left = best_compilations ( policy_cache, subs[ 0 ] . as_ref ( ) , sat_prob, dissat_prob) ?;
914+ let right = best_compilations ( policy_cache, subs[ 1 ] . as_ref ( ) , sat_prob, dissat_prob) ?;
915+ let q_zero_right = best_compilations ( policy_cache, subs[ 1 ] . as_ref ( ) , sat_prob, None ) ?;
916+ let q_zero_left = best_compilations ( policy_cache, subs[ 0 ] . as_ref ( ) , sat_prob, None ) ?;
917+
918+ for l in left. values ( ) {
919+ for r in right. values ( ) {
920+ if let Ok ( new_ext) = AstElemExt :: and_b ( l, r) {
921+ insert_best_wrapped (
922+ policy_cache,
923+ policy,
924+ & mut ret,
925+ new_ext,
926+ sat_prob,
927+ dissat_prob,
928+ ) ?;
929+ }
930+ if let Ok ( new_ext) = AstElemExt :: and_v ( l, r) {
931+ insert_best_wrapped (
932+ policy_cache,
933+ policy,
934+ & mut ret,
935+ new_ext,
936+ sat_prob,
937+ dissat_prob,
938+ ) ?;
939+ }
940+ }
941+ }
942+ // Do a separate loop with 'l' and 'r' swapped; we could combine the loops,
943+ // but this would sometimes result in compiling e.g. and(pk(A),pk(B)) into
944+ // an and with A and B swapped, which is surprising to the user since the
945+ // cost is the same with or without the swap.
946+ for l in left. values ( ) {
947+ for r in right. values ( ) {
948+ if let Ok ( new_ext) = AstElemExt :: and_b ( r, l) {
949+ insert_best_wrapped (
950+ policy_cache,
951+ policy,
952+ & mut ret,
953+ new_ext,
954+ sat_prob,
955+ dissat_prob,
956+ ) ?;
957+ }
958+ if let Ok ( new_ext) = AstElemExt :: and_v ( r, l) {
959+ insert_best_wrapped (
960+ policy_cache,
961+ policy,
962+ & mut ret,
963+ new_ext,
964+ sat_prob,
965+ dissat_prob,
966+ ) ?;
967+ }
968+ }
969+ }
970+
971+ for l in left. values ( ) {
972+ for r in q_zero_right. values ( ) {
973+ if let Ok ( new_ext) = AstElemExt :: and_or_0 ( l, r) {
974+ insert_best_wrapped (
975+ policy_cache,
976+ policy,
977+ & mut ret,
978+ new_ext,
979+ sat_prob,
980+ dissat_prob,
981+ ) ?;
982+ }
983+ }
984+ }
985+ for l in right. values ( ) {
986+ for r in q_zero_left. values ( ) {
987+ if let Ok ( new_ext) = AstElemExt :: and_or_0 ( l, r) {
988+ insert_best_wrapped (
989+ policy_cache,
990+ policy,
991+ & mut ret,
992+ new_ext,
993+ sat_prob,
994+ dissat_prob,
995+ ) ?;
996+ }
997+ }
998+ }
884999 }
8851000 Concrete :: Or ( ref subs) => {
8861001 let total = u32:: from ( subs[ 0 ] . 0 ) as f64 + u32:: from ( subs[ 1 ] . 0 ) as f64 ;
0 commit comments