@@ -583,20 +583,28 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
583
583
584
584
/// Count the minimum number of public keys for which signatures
585
585
/// 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 > {
587
588
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 ) ,
590
592
Policy :: After ( ..)
591
593
| Policy :: Older ( ..)
592
594
| Policy :: Sha256 ( ..)
593
595
| Policy :: Hash256 ( ..)
594
596
| Policy :: Ripemd160 ( ..)
595
- | Policy :: Hash160 ( ..) => 0 ,
597
+ | Policy :: Hash160 ( ..) => Some ( 0 ) ,
596
598
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
+ }
600
608
}
601
609
}
602
610
}
@@ -655,7 +663,7 @@ mod tests {
655
663
assert_eq ! ( policy. clone( ) . at_age( 0 ) , policy. clone( ) ) ;
656
664
assert_eq ! ( policy. clone( ) . at_age( 10000 ) , policy. clone( ) ) ;
657
665
assert_eq ! ( policy. n_keys( ) , 1 ) ;
658
- assert_eq ! ( policy. minimum_n_keys( ) , 1 ) ;
666
+ assert_eq ! ( policy. minimum_n_keys( ) , Some ( 1 ) ) ;
659
667
660
668
let policy = StringPolicy :: from_str ( "older(1000)" ) . unwrap ( ) ;
661
669
assert_eq ! ( policy, Policy :: Older ( 1000 ) ) ;
@@ -666,7 +674,7 @@ mod tests {
666
674
assert_eq ! ( policy. clone( ) . at_age( 1000 ) , policy. clone( ) ) ;
667
675
assert_eq ! ( policy. clone( ) . at_age( 10000 ) , policy. clone( ) ) ;
668
676
assert_eq ! ( policy. n_keys( ) , 0 ) ;
669
- assert_eq ! ( policy. minimum_n_keys( ) , 0 ) ;
677
+ assert_eq ! ( policy. minimum_n_keys( ) , Some ( 0 ) ) ;
670
678
671
679
let policy = StringPolicy :: from_str ( "or(pkh(),older(1000))" ) . unwrap ( ) ;
672
680
assert_eq ! (
@@ -683,7 +691,33 @@ mod tests {
683
691
assert_eq ! ( policy. clone( ) . at_age( 1000 ) , policy. clone( ) . normalized( ) ) ;
684
692
assert_eq ! ( policy. clone( ) . at_age( 10000 ) , policy. clone( ) . normalized( ) ) ;
685
693
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 ) ;
687
721
688
722
let policy = StringPolicy :: from_str (
689
723
"thresh(\
@@ -709,6 +743,32 @@ mod tests {
709
743
vec![ 1000 , 2000 , 10000 ] //sorted and dedup'd
710
744
) ;
711
745
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
+
712
772
let policy = StringPolicy :: from_str ( "after(1000)" ) . unwrap ( ) ;
713
773
assert_eq ! ( policy, Policy :: After ( 1000 ) ) ;
714
774
assert_eq ! ( policy. absolute_timelocks( ) , vec![ 1000 ] ) ;
@@ -718,7 +778,7 @@ mod tests {
718
778
assert_eq ! ( policy. clone( ) . at_height( 1000 ) , policy. clone( ) ) ;
719
779
assert_eq ! ( policy. clone( ) . at_height( 10000 ) , policy. clone( ) ) ;
720
780
assert_eq ! ( policy. n_keys( ) , 0 ) ;
721
- assert_eq ! ( policy. minimum_n_keys( ) , 0 ) ;
781
+ assert_eq ! ( policy. minimum_n_keys( ) , Some ( 0 ) ) ;
722
782
}
723
783
724
784
#[ test]
0 commit comments