@@ -251,7 +251,7 @@ impl<'a> ParsedPolicy<'a> {
251
251
/// - At least one of the keys is ours
252
252
/// - There are no duplicate or missing xpubs
253
253
/// - No duplicate keys in the policy
254
- pub fn validate ( & self , coin : BtcCoin ) -> Result < ( ) , Error > {
254
+ fn validate ( & self , coin : BtcCoin ) -> Result < ( ) , Error > {
255
255
check_enabled ( coin) ?;
256
256
257
257
let policy = self . policy ;
@@ -367,22 +367,24 @@ impl<'a> ParsedPolicy<'a> {
367
367
///
368
368
/// The parsed output keeps the key strings as is (e.g. "@0/**"). They will be processed and
369
369
/// replaced with actual pubkeys in a later step.
370
- pub fn parse ( policy : & Policy ) -> Result < ParsedPolicy , Error > {
370
+ pub fn parse ( policy : & Policy , coin : BtcCoin ) -> Result < ParsedPolicy , Error > {
371
371
let desc = policy. policy . as_str ( ) ;
372
- match desc. as_bytes ( ) {
372
+ let parsed = match desc. as_bytes ( ) {
373
373
// Match wsh(...).
374
374
[ b'w' , b's' , b'h' , b'(' , .., b')' ] => {
375
375
let miniscript_expr: miniscript:: Miniscript < String , miniscript:: Segwitv0 > =
376
376
miniscript:: Miniscript :: from_str ( & desc[ 4 ..desc. len ( ) - 1 ] )
377
377
. or ( Err ( Error :: InvalidInput ) ) ?;
378
378
379
- Ok ( ParsedPolicy {
379
+ ParsedPolicy {
380
380
policy,
381
381
descriptor : Descriptor :: Wsh ( Wsh { miniscript_expr } ) ,
382
- } )
382
+ }
383
383
}
384
- _ => Err ( Error :: InvalidInput ) ,
385
- }
384
+ _ => return Err ( Error :: InvalidInput ) ,
385
+ } ;
386
+ parsed. validate ( coin) ?;
387
+ Ok ( parsed)
386
388
}
387
389
388
390
/// Confirmation mode.
@@ -605,9 +607,11 @@ mod tests {
605
607
606
608
#[ test]
607
609
fn test_parse_wsh_miniscript ( ) {
610
+ let coin = BtcCoin :: Tbtc ;
611
+ let our_key = make_our_key ( KEYPATH_ACCOUNT ) ;
608
612
// Parse a valid example and check that the keys are collected as is as strings.
609
- let policy = make_policy ( "wsh(pk(@0/**))" , & [ ] ) ;
610
- match & parse ( & policy) . unwrap ( ) . descriptor {
613
+ let policy = make_policy ( "wsh(pk(@0/**))" , & [ our_key . clone ( ) ] ) ;
614
+ match & parse ( & policy, coin ) . unwrap ( ) . descriptor {
611
615
Descriptor :: Wsh ( Wsh {
612
616
miniscript_expr, ..
613
617
} ) => {
@@ -619,8 +623,11 @@ mod tests {
619
623
}
620
624
621
625
// Parse another valid example and check that the keys are collected as is as strings.
622
- let policy = make_policy ( "wsh(or_b(pk(@0/**),s:pk(@1/**)))" , & [ ] ) ;
623
- match & parse ( & policy) . unwrap ( ) . descriptor {
626
+ let policy = make_policy (
627
+ "wsh(or_b(pk(@0/**),s:pk(@1/**)))" ,
628
+ & [ our_key. clone ( ) , make_key ( SOME_XPUB_1 ) ] ,
629
+ ) ;
630
+ match & parse ( & policy, coin) . unwrap ( ) . descriptor {
624
631
Descriptor :: Wsh ( Wsh {
625
632
miniscript_expr, ..
626
633
} ) => {
@@ -633,125 +640,127 @@ mod tests {
633
640
634
641
// Unknown top-level fragment.
635
642
assert_eq ! (
636
- parse( & make_policy( "unknown(pk(@0/**))" , & [ ] ) ) . unwrap_err( ) ,
643
+ parse( & make_policy( "unknown(pk(@0/**))" , & [ our_key . clone ( ) ] ) , coin ) . unwrap_err( ) ,
637
644
Error :: InvalidInput ,
638
645
) ;
639
646
640
647
// Unknown script fragment.
641
648
assert_eq ! (
642
- parse( & make_policy( "wsh(unknown(@0/**))" , & [ ] ) ) . unwrap_err( ) ,
649
+ parse(
650
+ & make_policy( "wsh(unknown(@0/**))" , & [ our_key. clone( ) ] ) ,
651
+ coin
652
+ )
653
+ . unwrap_err( ) ,
643
654
Error :: InvalidInput ,
644
655
) ;
645
656
646
657
// Miniscript type-check fails (should be `or_b(pk(@0/**),s:pk(@1/**))`).
647
658
assert_eq ! (
648
- parse( & make_policy( "wsh(or_b(pk(@0/**),pk(@1/**)))" , & [ ] ) ) . unwrap_err( ) ,
659
+ parse(
660
+ & make_policy(
661
+ "wsh(or_b(pk(@0/**),pk(@1/**)))" ,
662
+ & [ our_key. clone( ) , make_key( SOME_XPUB_1 ) ]
663
+ ) ,
664
+ coin
665
+ )
666
+ . unwrap_err( ) ,
649
667
Error :: InvalidInput ,
650
668
) ;
651
669
}
652
670
653
671
#[ test]
654
- fn test_parse_validate ( ) {
672
+ fn test_parse ( ) {
655
673
mock_unlocked ( ) ;
656
674
657
675
let our_key = make_our_key ( KEYPATH_ACCOUNT ) ;
676
+ let coin = BtcCoin :: Tbtc ;
658
677
659
678
// All good.
660
- assert ! ( parse( & make_policy( "wsh(pk(@0/**))" , & [ our_key. clone( ) ] ) )
661
- . unwrap( )
662
- . validate( BtcCoin :: Tbtc )
663
- . is_ok( ) ) ;
679
+ assert ! ( parse( & make_policy( "wsh(pk(@0/**))" , & [ our_key. clone( ) ] ) , coin) . is_ok( ) ) ;
664
680
665
681
// Unsupported coins
666
682
for coin in [ BtcCoin :: Ltc , BtcCoin :: Tltc ] {
667
- assert_eq ! (
668
- parse( & make_policy( "wsh(pk(@0/**))" , & [ our_key. clone( ) ] ) )
669
- . unwrap( )
670
- . validate( coin) ,
683
+ assert ! ( matches!(
684
+ parse( & make_policy( "wsh(pk(@0/**))" , & [ our_key. clone( ) ] ) , coin) ,
671
685
Err ( Error :: InvalidInput )
672
- ) ;
686
+ ) ) ;
673
687
}
674
688
675
689
// Too many keys.
676
690
let many_keys: Vec < pb:: KeyOriginInfo > = ( 0 ..=20 )
677
691
. map ( |i| make_our_key ( & [ 48 + HARDENED , 1 + HARDENED , i + HARDENED , 3 + HARDENED ] ) )
678
692
. collect ( ) ;
679
- assert_eq ! (
680
- parse( & make_policy( "wsh(pk(@0/**))" , & many_keys) )
681
- . unwrap( )
682
- . validate( BtcCoin :: Tbtc ) ,
693
+ assert ! ( matches!(
694
+ parse( & make_policy( "wsh(pk(@0/**))" , & many_keys) , coin) ,
683
695
Err ( Error :: InvalidInput )
684
- ) ;
696
+ ) ) ;
685
697
686
698
// Our key is not present - fingerprint missing.
687
- assert_eq ! (
688
- parse( & make_policy( "wsh(pk(@0/**))" , & [ make_key( SOME_XPUB_1 ) ] ) )
689
- . unwrap( )
690
- . validate( BtcCoin :: Tbtc ) ,
699
+ assert ! ( matches!(
700
+ parse(
701
+ & make_policy( "wsh(pk(@0/**))" , & [ make_key( SOME_XPUB_1 ) ] ) ,
702
+ coin
703
+ ) ,
691
704
Err ( Error :: InvalidInput )
692
- ) ;
705
+ ) ) ;
693
706
694
707
// Our key is not present - fingerprint and keypath exit but xpub does not match.
695
708
let mut wrong_key = our_key. clone ( ) ;
696
709
wrong_key. xpub = Some ( parse_xpub ( SOME_XPUB_1 ) . unwrap ( ) ) ;
697
- assert_eq ! (
698
- parse( & make_policy( "wsh(pk(@0/**))" , & [ wrong_key] ) )
699
- . unwrap( )
700
- . validate( BtcCoin :: Tbtc ) ,
710
+ assert ! ( matches!(
711
+ parse( & make_policy( "wsh(pk(@0/**))" , & [ wrong_key] ) , coin) ,
701
712
Err ( Error :: InvalidInput )
702
- ) ;
713
+ ) ) ;
703
714
704
715
// Contains duplicate keys.
705
- assert_eq ! (
706
- parse( & make_policy(
707
- "wsh(multi(2,@0/**,@1/**,@2/**))" ,
708
- & [
709
- make_key( SOME_XPUB_1 ) ,
710
- our_key. clone( ) ,
711
- make_key( SOME_XPUB_1 )
712
- ]
713
- ) )
714
- . unwrap( )
715
- . validate( BtcCoin :: Tbtc ) ,
716
+ assert ! ( matches!(
717
+ parse(
718
+ & make_policy(
719
+ "wsh(multi(2,@0/**,@1/**,@2/**))" ,
720
+ & [
721
+ make_key( SOME_XPUB_1 ) ,
722
+ our_key. clone( ) ,
723
+ make_key( SOME_XPUB_1 )
724
+ ]
725
+ ) ,
726
+ coin
727
+ ) ,
716
728
Err ( Error :: InvalidInput )
717
- ) ;
729
+ ) ) ;
718
730
719
731
// Contains a key with missing xpub.
720
- assert_eq ! (
721
- parse( & make_policy(
722
- "wsh(multi(2,@0/**,@1/**))" ,
723
- & [
724
- our_key. clone( ) ,
725
- pb:: KeyOriginInfo {
726
- root_fingerprint: vec![ ] ,
727
- keypath: vec![ ] ,
728
- xpub: None // missing
729
- }
730
- ]
731
- ) )
732
- . unwrap( )
733
- . validate( BtcCoin :: Tbtc ) ,
732
+ assert ! ( matches!(
733
+ parse(
734
+ & make_policy(
735
+ "wsh(multi(2,@0/**,@1/**))" ,
736
+ & [
737
+ our_key. clone( ) ,
738
+ pb:: KeyOriginInfo {
739
+ root_fingerprint: vec![ ] ,
740
+ keypath: vec![ ] ,
741
+ xpub: None // missing
742
+ }
743
+ ]
744
+ ) ,
745
+ coin
746
+ ) ,
734
747
Err ( Error :: InvalidInput )
735
- ) ;
748
+ ) ) ;
736
749
737
750
// Not all keys are used.
738
- assert_eq ! (
739
- parse( & make_policy(
740
- "wsh(pk(@0/**))" ,
741
- & [ our_key. clone( ) , make_key( SOME_XPUB_1 ) ]
742
- ) )
743
- . unwrap( )
744
- . validate( BtcCoin :: Tbtc ) ,
751
+ assert ! ( matches!(
752
+ parse(
753
+ & make_policy( "wsh(pk(@0/**))" , & [ our_key. clone( ) , make_key( SOME_XPUB_1 ) ] ) ,
754
+ coin
755
+ ) ,
745
756
Err ( Error :: InvalidInput )
746
- ) ;
757
+ ) ) ;
747
758
748
759
// Referenced key does not exist
749
- assert_eq ! (
750
- parse( & make_policy( "wsh(pk(@1/**))" , & [ our_key. clone( ) ] ) )
751
- . unwrap( )
752
- . validate( BtcCoin :: Tbtc ) ,
760
+ assert ! ( matches!(
761
+ parse( & make_policy( "wsh(pk(@1/**))" , & [ our_key. clone( ) ] ) , coin) ,
753
762
Err ( Error :: InvalidInput )
754
- ) ;
763
+ ) ) ;
755
764
}
756
765
757
766
#[ test]
@@ -763,21 +772,21 @@ mod tests {
763
772
764
773
// Ok, one key.
765
774
let pol = make_policy ( "wsh(pk(@0/**))" , & [ our_key. clone ( ) ] ) ;
766
- assert ! ( parse( & pol) . unwrap ( ) . validate ( coin) . is_ok( ) ) ;
775
+ assert ! ( parse( & pol, coin) . is_ok( ) ) ;
767
776
768
777
// Ok, two keys.
769
778
let pol = make_policy (
770
779
"wsh(or_b(pk(@0/**),s:pk(@1/**)))" ,
771
780
& [ our_key. clone ( ) , make_key ( SOME_XPUB_1 ) ] ,
772
781
) ;
773
- assert ! ( parse( & pol) . unwrap ( ) . validate ( coin) . is_ok( ) ) ;
782
+ assert ! ( parse( & pol, coin) . is_ok( ) ) ;
774
783
775
784
// Ok, one key with different derivations
776
785
let pol = make_policy (
777
786
"wsh(or_b(pk(@0/<0;1>/*),s:pk(@0/<2;3>/*)))" ,
778
787
& [ our_key. clone ( ) ] ,
779
788
) ;
780
- assert ! ( parse( & pol) . unwrap ( ) . validate ( coin) . is_ok( ) ) ;
789
+ assert ! ( parse( & pol, coin) . is_ok( ) ) ;
781
790
782
791
// Duplicate path, one time in change, one time in receive. While the keys technically are
783
792
// never duplicate in the final miniscript with the pubkeys inserted, we still prohibit it,
@@ -787,33 +796,33 @@ mod tests {
787
796
"wsh(or_b(pk(@0/<0;1>/*),s:pk(@0/<1;2>/*)))" ,
788
797
& [ our_key. clone ( ) ] ,
789
798
) ;
790
- assert ! ( parse( & pol) . unwrap ( ) . validate ( coin) . is_err( ) ) ;
799
+ assert ! ( parse( & pol, coin) . is_err( ) ) ;
791
800
792
801
// Duplicate key inside policy.
793
802
let pol = make_policy ( "wsh(or_b(pk(@0/**),s:pk(@0/**)))" , & [ our_key. clone ( ) ] ) ;
794
- assert ! ( parse( & pol) . is_err( ) ) ;
803
+ assert ! ( parse( & pol, coin ) . is_err( ) ) ;
795
804
796
805
// Duplicate key inside policy (same change and receive).
797
806
let pol = make_policy ( "wsh(pk(@0/<0;0>/*))" , & [ our_key. clone ( ) ] ) ;
798
- assert ! ( parse( & pol) . unwrap ( ) . validate ( coin) . is_err( ) ) ;
807
+ assert ! ( parse( & pol, coin) . is_err( ) ) ;
799
808
800
809
// Duplicate key inside policy, using different notations for the same thing.
801
810
let pol = make_policy ( "wsh(or_b(pk(@0/**),s:pk(@0/<0;1>/*)))" , & [ our_key. clone ( ) ] ) ;
802
- assert ! ( parse( & pol) . unwrap ( ) . validate ( coin) . is_err( ) ) ;
811
+ assert ! ( parse( & pol, coin) . is_err( ) ) ;
803
812
804
813
// Duplicate key inside policy, using same receive but different change.
805
814
let pol = make_policy (
806
815
"wsh(or_b(pk(@0/<0;1>/*),s:pk(@0/<0;2>/*)))" ,
807
816
& [ our_key. clone ( ) ] ,
808
817
) ;
809
- assert ! ( parse( & pol) . unwrap ( ) . validate ( coin) . is_err( ) ) ;
818
+ assert ! ( parse( & pol, coin) . is_err( ) ) ;
810
819
811
820
// Duplicate key inside policy, using same change but different receive.
812
821
let pol = make_policy (
813
822
"wsh(or_b(pk(@0/<0;1>/*),s:pk(@0/<2;1>/*)))" ,
814
823
& [ our_key. clone ( ) ] ,
815
824
) ;
816
- assert ! ( parse( & pol) . unwrap ( ) . validate ( coin) . is_err( ) ) ;
825
+ assert ! ( parse( & pol, coin) . is_err( ) ) ;
817
826
}
818
827
819
828
#[ test]
@@ -922,9 +931,10 @@ mod tests {
922
931
let some_key = make_key ( SOME_XPUB_1 ) ;
923
932
let some_xpub = bip32:: Xpub :: from ( some_key. xpub . as_ref ( ) . unwrap ( ) ) ;
924
933
let address_index = 5 ;
934
+ let coin = BtcCoin :: Tbtc ;
925
935
926
936
let witness_script = |pol : & str , keys : & [ pb:: KeyOriginInfo ] , is_change : bool | {
927
- let derived = parse ( & make_policy ( pol, keys) )
937
+ let derived = parse ( & make_policy ( pol, keys) , coin )
928
938
. unwrap ( )
929
939
. derive ( is_change, address_index)
930
940
. unwrap ( ) ;
@@ -933,7 +943,7 @@ mod tests {
933
943
}
934
944
} ;
935
945
let witness_script_at_keypath = |pol : & str , keys : & [ pb:: KeyOriginInfo ] , keypath : & [ u32 ] | {
936
- let derived = parse ( & make_policy ( pol, keys) )
946
+ let derived = parse ( & make_policy ( pol, keys) , coin )
937
947
. unwrap ( )
938
948
. derive_at_keypath ( keypath)
939
949
. unwrap ( ) ;
0 commit comments