@@ -583,20 +583,28 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
583583
584584 /// Count the minimum number of public keys for which signatures
585585 /// could be used to satisfy the policy.
586- pub fn minimum_n_keys ( & self ) -> usize {
586+ /// Returns `None` if the policy is not satisfiable.
587+ pub fn minimum_n_keys ( & self ) -> Option < usize > {
587588 match * self {
588- Policy :: Unsatisfiable | Policy :: Trivial => 0 ,
589- Policy :: KeyHash ( ..) => 1 ,
589+ Policy :: Unsatisfiable => None ,
590+ Policy :: Trivial => Some ( 0 ) ,
591+ Policy :: KeyHash ( ..) => Some ( 1 ) ,
590592 Policy :: After ( ..)
591593 | Policy :: Older ( ..)
592594 | Policy :: Sha256 ( ..)
593595 | Policy :: Hash256 ( ..)
594596 | Policy :: Ripemd160 ( ..)
595- | Policy :: Hash160 ( ..) => 0 ,
597+ | Policy :: Hash160 ( ..) => Some ( 0 ) ,
596598 Policy :: Threshold ( k, ref subs) => {
597- let mut sublens: Vec < usize > = subs. iter ( ) . map ( Policy :: minimum_n_keys) . collect ( ) ;
598- sublens. sort ( ) ;
599- sublens[ 0 ..k] . iter ( ) . cloned ( ) . sum :: < usize > ( )
599+ let mut sublens: Vec < usize > =
600+ subs. iter ( ) . filter_map ( Policy :: minimum_n_keys) . collect ( ) ;
601+ if sublens. len ( ) < k {
602+ // Not enough branches are satisfiable
603+ None
604+ } else {
605+ sublens. sort ( ) ;
606+ Some ( sublens[ 0 ..k] . iter ( ) . cloned ( ) . sum :: < usize > ( ) )
607+ }
600608 }
601609 }
602610 }
@@ -655,7 +663,7 @@ mod tests {
655663 assert_eq ! ( policy. clone( ) . at_age( 0 ) , policy. clone( ) ) ;
656664 assert_eq ! ( policy. clone( ) . at_age( 10000 ) , policy. clone( ) ) ;
657665 assert_eq ! ( policy. n_keys( ) , 1 ) ;
658- assert_eq ! ( policy. minimum_n_keys( ) , 1 ) ;
666+ assert_eq ! ( policy. minimum_n_keys( ) , Some ( 1 ) ) ;
659667
660668 let policy = StringPolicy :: from_str ( "older(1000)" ) . unwrap ( ) ;
661669 assert_eq ! ( policy, Policy :: Older ( 1000 ) ) ;
@@ -666,7 +674,7 @@ mod tests {
666674 assert_eq ! ( policy. clone( ) . at_age( 1000 ) , policy. clone( ) ) ;
667675 assert_eq ! ( policy. clone( ) . at_age( 10000 ) , policy. clone( ) ) ;
668676 assert_eq ! ( policy. n_keys( ) , 0 ) ;
669- assert_eq ! ( policy. minimum_n_keys( ) , 0 ) ;
677+ assert_eq ! ( policy. minimum_n_keys( ) , Some ( 0 ) ) ;
670678
671679 let policy = StringPolicy :: from_str ( "or(pkh(),older(1000))" ) . unwrap ( ) ;
672680 assert_eq ! (
@@ -683,7 +691,33 @@ mod tests {
683691 assert_eq ! ( policy. clone( ) . at_age( 1000 ) , policy. clone( ) . normalized( ) ) ;
684692 assert_eq ! ( policy. clone( ) . at_age( 10000 ) , policy. clone( ) . normalized( ) ) ;
685693 assert_eq ! ( policy. n_keys( ) , 1 ) ;
686- assert_eq ! ( policy. minimum_n_keys( ) , 0 ) ;
694+ assert_eq ! ( policy. minimum_n_keys( ) , Some ( 0 ) ) ;
695+
696+ let policy = StringPolicy :: from_str ( "or(pkh(),UNSATISFIABLE)" ) . unwrap ( ) ;
697+ assert_eq ! (
698+ policy,
699+ Policy :: Threshold (
700+ 1 ,
701+ vec![ Policy :: KeyHash ( "" . to_owned( ) ) , Policy :: Unsatisfiable , ]
702+ )
703+ ) ;
704+ assert_eq ! ( policy. relative_timelocks( ) , vec![ ] ) ;
705+ assert_eq ! ( policy. absolute_timelocks( ) , vec![ ] ) ;
706+ assert_eq ! ( policy. n_keys( ) , 1 ) ;
707+ assert_eq ! ( policy. minimum_n_keys( ) , Some ( 1 ) ) ;
708+
709+ let policy = StringPolicy :: from_str ( "and(pkh(),UNSATISFIABLE)" ) . unwrap ( ) ;
710+ assert_eq ! (
711+ policy,
712+ Policy :: Threshold (
713+ 2 ,
714+ vec![ Policy :: KeyHash ( "" . to_owned( ) ) , Policy :: Unsatisfiable , ]
715+ )
716+ ) ;
717+ assert_eq ! ( policy. relative_timelocks( ) , vec![ ] ) ;
718+ assert_eq ! ( policy. absolute_timelocks( ) , vec![ ] ) ;
719+ assert_eq ! ( policy. n_keys( ) , 1 ) ;
720+ assert_eq ! ( policy. minimum_n_keys( ) , None ) ;
687721
688722 let policy = StringPolicy :: from_str (
689723 "thresh(\
@@ -709,6 +743,32 @@ mod tests {
709743 vec![ 1000 , 2000 , 10000 ] //sorted and dedup'd
710744 ) ;
711745
746+ let policy = StringPolicy :: from_str (
747+ "thresh(\
748+ 2,older(1000),older(10000),older(1000),UNSATISFIABLE,UNSATISFIABLE\
749+ )",
750+ )
751+ . unwrap ( ) ;
752+ assert_eq ! (
753+ policy,
754+ Policy :: Threshold (
755+ 2 ,
756+ vec![
757+ Policy :: Older ( 1000 ) ,
758+ Policy :: Older ( 10000 ) ,
759+ Policy :: Older ( 1000 ) ,
760+ Policy :: Unsatisfiable ,
761+ Policy :: Unsatisfiable ,
762+ ]
763+ )
764+ ) ;
765+ assert_eq ! (
766+ policy. relative_timelocks( ) ,
767+ vec![ 1000 , 10000 ] //sorted and dedup'd
768+ ) ;
769+ assert_eq ! ( policy. n_keys( ) , 0 ) ;
770+ assert_eq ! ( policy. minimum_n_keys( ) , Some ( 0 ) ) ;
771+
712772 let policy = StringPolicy :: from_str ( "after(1000)" ) . unwrap ( ) ;
713773 assert_eq ! ( policy, Policy :: After ( 1000 ) ) ;
714774 assert_eq ! ( policy. absolute_timelocks( ) , vec![ 1000 ] ) ;
@@ -718,7 +778,7 @@ mod tests {
718778 assert_eq ! ( policy. clone( ) . at_height( 1000 ) , policy. clone( ) ) ;
719779 assert_eq ! ( policy. clone( ) . at_height( 10000 ) , policy. clone( ) ) ;
720780 assert_eq ! ( policy. n_keys( ) , 0 ) ;
721- assert_eq ! ( policy. minimum_n_keys( ) , 0 ) ;
781+ assert_eq ! ( policy. minimum_n_keys( ) , Some ( 0 ) ) ;
722782 }
723783
724784 #[ test]
0 commit comments