@@ -502,3 +502,355 @@ impl Assets {
502
502
self . absolute_timelock = b. absolute_timelock . or ( self . absolute_timelock ) ;
503
503
}
504
504
}
505
+
506
+ #[ cfg( test) ]
507
+ mod test {
508
+ use std:: str:: FromStr ;
509
+
510
+ use bitcoin:: { LockTime , Sequence } ;
511
+
512
+ use super :: * ;
513
+ use crate :: * ;
514
+
515
+ fn test_inner (
516
+ desc : & str ,
517
+ keys : Vec < DescriptorPublicKey > ,
518
+ hashes : Vec < hash160:: Hash > ,
519
+ // [ (key_indexes, hash_indexes, older, after, expected) ]
520
+ tests : Vec < (
521
+ Vec < usize > ,
522
+ Vec < usize > ,
523
+ Option < Sequence > ,
524
+ Option < LockTime > ,
525
+ Option < usize > ,
526
+ ) > ,
527
+ ) {
528
+ let desc = Descriptor :: < DefiniteDescriptorKey > :: from_str ( & desc) . unwrap ( ) ;
529
+
530
+ for ( key_indexes, hash_indexes, older, after, expected) in tests {
531
+ let mut assets = Assets :: new ( ) ;
532
+ if let Some ( seq) = older {
533
+ assets = assets. older ( seq) ;
534
+ }
535
+ if let Some ( locktime) = after {
536
+ assets = assets. after ( locktime) ;
537
+ }
538
+ for ki in key_indexes {
539
+ assets = assets. add ( keys[ ki] . clone ( ) ) ;
540
+ }
541
+ for hi in hash_indexes {
542
+ assets = assets. add ( hashes[ hi] . clone ( ) ) ;
543
+ }
544
+
545
+ let result = desc. get_plan ( & assets) ;
546
+ assert_eq ! (
547
+ result. as_ref( ) . map( |plan| plan. satisfaction_weight( ) ) ,
548
+ expected,
549
+ "{:#?}" ,
550
+ result
551
+ ) ;
552
+ }
553
+ }
554
+
555
+ #[ test]
556
+ fn test_or ( ) {
557
+ let keys = vec ! [
558
+ DescriptorPublicKey :: from_str(
559
+ "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c" ,
560
+ )
561
+ . unwrap( ) ,
562
+ DescriptorPublicKey :: from_str(
563
+ "0257f4a2816338436cccabc43aa724cf6e69e43e84c3c8a305212761389dd73a8a" ,
564
+ )
565
+ . unwrap( ) ,
566
+ ] ;
567
+ let hashes = vec ! [ ] ;
568
+ let desc = format ! ( "wsh(t:or_c(pk({}),v:pkh({})))" , keys[ 0 ] , keys[ 1 ] ) ;
569
+
570
+ // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig)
571
+ let tests = vec ! [
572
+ ( vec![ ] , vec![ ] , None , None , None ) ,
573
+ ( vec![ 0 ] , vec![ ] , None , None , Some ( 4 + 1 + 73 ) ) ,
574
+ ( vec![ 0 , 1 ] , vec![ ] , None , None , Some ( 4 + 1 + 73 ) ) ,
575
+ ] ;
576
+
577
+ test_inner ( & desc, keys, hashes, tests) ;
578
+ }
579
+
580
+ #[ test]
581
+ fn test_and ( ) {
582
+ let keys = vec ! [
583
+ DescriptorPublicKey :: from_str(
584
+ "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c" ,
585
+ )
586
+ . unwrap( ) ,
587
+ DescriptorPublicKey :: from_str(
588
+ "0257f4a2816338436cccabc43aa724cf6e69e43e84c3c8a305212761389dd73a8a" ,
589
+ )
590
+ . unwrap( ) ,
591
+ ] ;
592
+ let hashes = vec ! [ ] ;
593
+ let desc = format ! ( "wsh(and_v(v:pk({}),pk({})))" , keys[ 0 ] , keys[ 1 ] ) ;
594
+
595
+ // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig) * 2
596
+ let tests = vec ! [
597
+ ( vec![ ] , vec![ ] , None , None , None ) ,
598
+ ( vec![ 0 ] , vec![ ] , None , None , None ) ,
599
+ ( vec![ 0 , 1 ] , vec![ ] , None , None , Some ( 4 + 1 + 73 * 2 ) ) ,
600
+ ] ;
601
+
602
+ test_inner ( & desc, keys, hashes, tests) ;
603
+ }
604
+
605
+ #[ test]
606
+ fn test_multi ( ) {
607
+ let keys = vec ! [
608
+ DescriptorPublicKey :: from_str(
609
+ "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c" ,
610
+ )
611
+ . unwrap( ) ,
612
+ DescriptorPublicKey :: from_str(
613
+ "0257f4a2816338436cccabc43aa724cf6e69e43e84c3c8a305212761389dd73a8a" ,
614
+ )
615
+ . unwrap( ) ,
616
+ DescriptorPublicKey :: from_str(
617
+ "03500a2b48b0f66c8183cc0d6645ab21cc19c7fad8a33ff04d41c3ece54b0bc1c5" ,
618
+ )
619
+ . unwrap( ) ,
620
+ DescriptorPublicKey :: from_str(
621
+ "033ad2d191da4f39512adbaac320cae1f12f298386a4e9d43fd98dec7cf5db2ac9" ,
622
+ )
623
+ . unwrap( ) ,
624
+ ] ;
625
+ let hashes = vec ! [ ] ;
626
+ let desc = format ! (
627
+ "wsh(multi(3,{},{},{},{}))" ,
628
+ keys[ 0 ] , keys[ 1 ] , keys[ 2 ] , keys[ 3 ]
629
+ ) ;
630
+
631
+ let tests = vec ! [
632
+ ( vec![ ] , vec![ ] , None , None , None ) ,
633
+ ( vec![ 0 , 1 ] , vec![ ] , None , None , None ) ,
634
+ // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig) * 3 + 1 (dummy push)
635
+ ( vec![ 0 , 1 , 3 ] , vec![ ] , None , None , Some ( 4 + 1 + 73 * 3 + 1 ) ) ,
636
+ ] ;
637
+
638
+ test_inner ( & desc, keys, hashes, tests) ;
639
+ }
640
+
641
+ #[ test]
642
+ fn test_thresh ( ) {
643
+ let keys = vec ! [
644
+ DescriptorPublicKey :: from_str(
645
+ "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c" ,
646
+ )
647
+ . unwrap( ) ,
648
+ DescriptorPublicKey :: from_str(
649
+ "0257f4a2816338436cccabc43aa724cf6e69e43e84c3c8a305212761389dd73a8a" ,
650
+ )
651
+ . unwrap( ) ,
652
+ ] ;
653
+ let hashes = vec ! [ ] ;
654
+ let desc = format ! (
655
+ "wsh(thresh(2,pk({}),s:pk({}),snl:older(144)))" ,
656
+ keys[ 0 ] , keys[ 1 ]
657
+ ) ;
658
+
659
+ let tests = vec ! [
660
+ ( vec![ ] , vec![ ] , None , None , None ) ,
661
+ ( vec![ ] , vec![ ] , Some ( Sequence ( 1000 ) ) , None , None ) ,
662
+ ( vec![ 0 ] , vec![ ] , None , None , None ) ,
663
+ // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig) + 1 (OP_0) + 1 (OP_ZERO)
664
+ ( vec![ 0 ] , vec![ ] , Some ( Sequence ( 1000 ) ) , None , Some ( 80 ) ) ,
665
+ // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig) * 2 + 2 (OP_PUSHBYTE_1 0x01)
666
+ ( vec![ 0 , 1 ] , vec![ ] , None , None , Some ( 153 ) ) ,
667
+ // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig) + 1 (OP_0) + 1 (OP_ZERO)
668
+ ( vec![ 0 , 1 ] , vec![ ] , Some ( Sequence ( 1000 ) ) , None , Some ( 80 ) ) ,
669
+ // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig) * 2 + 2 (OP_PUSHBYTE_1 0x01)
670
+ (
671
+ vec![ 0 , 1 ] ,
672
+ vec![ ] ,
673
+ Some ( Sequence :: from_512_second_intervals( 10 ) ) ,
674
+ None ,
675
+ Some ( 153 ) ,
676
+ ) , // incompatible timelock
677
+ ] ;
678
+
679
+ test_inner ( & desc, keys. clone ( ) , hashes. clone ( ) , tests) ;
680
+
681
+ let desc = format ! (
682
+ "wsh(thresh(2,pk({}),s:pk({}),snl:after(144)))" ,
683
+ keys[ 0 ] , keys[ 1 ]
684
+ ) ;
685
+
686
+ let tests = vec ! [
687
+ // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig) + 1 (OP_0) + 1 (OP_ZERO)
688
+ (
689
+ vec![ 0 ] ,
690
+ vec![ ] ,
691
+ None ,
692
+ Some ( LockTime :: from_height( 1000 ) . unwrap( ) ) ,
693
+ Some ( 80 ) ,
694
+ ) ,
695
+ // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig) * 2 + 2 (OP_PUSHBYTE_1 0x01)
696
+ (
697
+ vec![ 0 , 1 ] ,
698
+ vec![ ] ,
699
+ None ,
700
+ Some ( LockTime :: from_time( 500_001_000 ) . unwrap( ) ) ,
701
+ Some ( 153 ) ,
702
+ ) , // incompatible timelock
703
+ ] ;
704
+
705
+ test_inner ( & desc, keys, hashes, tests) ;
706
+ }
707
+
708
+ #[ test]
709
+ fn test_taproot ( ) {
710
+ let keys = vec ! [
711
+ DescriptorPublicKey :: from_str(
712
+ "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c" ,
713
+ )
714
+ . unwrap( ) ,
715
+ DescriptorPublicKey :: from_str(
716
+ "0257f4a2816338436cccabc43aa724cf6e69e43e84c3c8a305212761389dd73a8a" ,
717
+ )
718
+ . unwrap( ) ,
719
+ DescriptorPublicKey :: from_str(
720
+ "03500a2b48b0f66c8183cc0d6645ab21cc19c7fad8a33ff04d41c3ece54b0bc1c5" ,
721
+ )
722
+ . unwrap( ) ,
723
+ DescriptorPublicKey :: from_str(
724
+ "033ad2d191da4f39512adbaac320cae1f12f298386a4e9d43fd98dec7cf5db2ac9" ,
725
+ )
726
+ . unwrap( ) ,
727
+ DescriptorPublicKey :: from_str(
728
+ "023fc33527afab09fa97135f2180bcd22ce637b1d2fbcb2db748b1f2c33f45b2b4" ,
729
+ )
730
+ . unwrap( ) ,
731
+ ] ;
732
+ let hashes = vec ! [ ] ;
733
+ // .
734
+ // / \
735
+ // . .
736
+ // A / \
737
+ // . .
738
+ // B C
739
+ // where A = pk(key1)
740
+ // B = multi(1, key2, key3)
741
+ // C = and(key4, after(10))
742
+ let desc = format ! (
743
+ "tr({},{{pk({}),{{multi_a(1,{},{}),and_v(v:pk({}),after(10))}}}})" ,
744
+ keys[ 0 ] , keys[ 1 ] , keys[ 2 ] , keys[ 3 ] , keys[ 4 ]
745
+ ) ;
746
+
747
+ // expected weight: 4 (scriptSig len) + 1 (witness len) + 1 (OP_PUSH) + 65 (sig)
748
+ let internal_key_sat_weight = Some ( 71 ) ;
749
+ // expected weight: 4 (scriptSig len) + 1 (witness len) + 1 (OP_PUSH) + 65 (sig)
750
+ // + 34 [script: 1 (OP_PUSHBYTES_32) + 32 (key) + 1 (OP_CHECKSIG)]
751
+ // + 65 [control block: 1 (control byte) + 32 (internal key) + 32 (hash BC)]
752
+ let first_leaf_sat_weight = Some ( 170 ) ;
753
+ // expected weight: 4 (scriptSig len) + 1 (witness len) + 1 (OP_PUSH) + 65 (sig)
754
+ // + 1 (OP_ZERO)
755
+ // + 70 [script: 1 (OP_PUSHBYTES_32) + 32 (key) + 1 (OP_CHECKSIG)
756
+ // + 1 (OP_PUSHBYTES_32) + 32 (key) + 1 (OP_CHECKSIGADD)
757
+ // + 1 (OP_PUSHNUM1) + 1 (OP_NUMEQUAL)]
758
+ // + 97 [control block: 1 (control byte) + 32 (internal key) + 32 (hash C) + 32 (hash
759
+ // A)]
760
+ let second_leaf_sat_weight = Some ( 239 ) ;
761
+ // expected weight: 4 (scriptSig len) + 1 (witness len) + 1 (OP_PUSH) + 65 (sig)
762
+ // + 36 [script: 1 (OP_PUSHBYTES_32) + 32 (key) + 1 (OP_CHECKSIGVERIFY)
763
+ // + 1 (OP_PUSHNUM_10) + 1 (OP_CLTV)]
764
+ // + 97 [control block: 1 (control byte) + 32 (internal key) + 32 (hash B) + 32 (hash
765
+ // A)]
766
+ let third_leaf_sat_weight = Some ( 204 ) ;
767
+
768
+ let tests = vec ! [
769
+ // Don't give assets
770
+ ( vec![ ] , vec![ ] , None , None , None ) ,
771
+ // Spend with internal key
772
+ ( vec![ 0 ] , vec![ ] , None , None , internal_key_sat_weight) ,
773
+ // Spend with first leaf (single pk)
774
+ ( vec![ 1 ] , vec![ ] , None , None , first_leaf_sat_weight) ,
775
+ // Spend with second leaf (1of2)
776
+ ( vec![ 2 ] , vec![ ] , None , None , second_leaf_sat_weight) ,
777
+ // Spend with second leaf (1of2)
778
+ ( vec![ 2 , 3 ] , vec![ ] , None , None , second_leaf_sat_weight) ,
779
+ // Spend with third leaf (key + timelock)
780
+ (
781
+ vec![ 4 ] ,
782
+ vec![ ] ,
783
+ None ,
784
+ Some ( LockTime :: from_height( 10 ) . unwrap( ) ) ,
785
+ third_leaf_sat_weight,
786
+ ) ,
787
+ // Spend with third leaf (key + timelock),
788
+ // but timelock is too low (=impossible)
789
+ (
790
+ vec![ 4 ] ,
791
+ vec![ ] ,
792
+ None ,
793
+ Some ( LockTime :: from_height( 9 ) . unwrap( ) ) ,
794
+ None ,
795
+ ) ,
796
+ // Spend with third leaf (key + timelock),
797
+ // but timelock is in the wrong unit (=impossible)
798
+ (
799
+ vec![ 4 ] ,
800
+ vec![ ] ,
801
+ None ,
802
+ Some ( LockTime :: from_time( 1296000000 ) . unwrap( ) ) ,
803
+ None ,
804
+ ) ,
805
+ // Spend with third leaf (key + timelock),
806
+ // but don't give the timelock (=impossible)
807
+ ( vec![ 4 ] , vec![ ] , None , None , None ) ,
808
+ // Give all the keys (internal key will be used, as it's cheaper)
809
+ (
810
+ vec![ 0 , 1 , 2 , 3 , 4 ] ,
811
+ vec![ ] ,
812
+ None ,
813
+ None ,
814
+ internal_key_sat_weight,
815
+ ) ,
816
+ // Give all the leaf keys (uses 1st leaf)
817
+ ( vec![ 1 , 2 , 3 , 4 ] , vec![ ] , None , None , first_leaf_sat_weight) ,
818
+ // Give 2nd+3rd leaf without timelock (uses 2nd leaf)
819
+ ( vec![ 2 , 3 , 4 ] , vec![ ] , None , None , second_leaf_sat_weight) ,
820
+ // Give 2nd+3rd leaf with timelock (uses 3rd leaf)
821
+ (
822
+ vec![ 2 , 3 , 4 ] ,
823
+ vec![ ] ,
824
+ None ,
825
+ Some ( LockTime :: from_consensus( 11 ) ) ,
826
+ third_leaf_sat_weight,
827
+ ) ,
828
+ ] ;
829
+
830
+ test_inner ( & desc, keys, hashes, tests) ;
831
+ }
832
+
833
+ #[ test]
834
+ fn test_hash ( ) {
835
+ let keys = vec ! [ DescriptorPublicKey :: from_str(
836
+ "02c2fd50ceae468857bb7eb32ae9cd4083e6c7e42fbbec179d81134b3e3830586c" ,
837
+ )
838
+ . unwrap( ) ] ;
839
+ let hashes = vec ! [ hash160:: Hash :: from_slice( & vec![ 0 ; 20 ] ) . unwrap( ) ] ;
840
+ let desc = format ! ( "wsh(and_v(v:pk({}),hash160({})))" , keys[ 0 ] , hashes[ 0 ] ) ;
841
+
842
+ let tests = vec ! [
843
+ // No assets, impossible
844
+ ( vec![ ] , vec![ ] , None , None , None ) ,
845
+ // Only key, impossible
846
+ ( vec![ 0 ] , vec![ ] , None , None , None ) ,
847
+ // Only hash, impossible
848
+ ( vec![ ] , vec![ 0 ] , None , None , None ) ,
849
+ // Key + hash
850
+ // expected weight: 4 (scriptSig len) + 1 (witness len) + 73 (sig) + 1 (OP_PUSH) + 32 (preimage)
851
+ ( vec![ 0 ] , vec![ 0 ] , None , None , Some ( 111 ) ) ,
852
+ ] ;
853
+
854
+ test_inner ( & desc, keys, hashes, tests) ;
855
+ }
856
+ }
0 commit comments