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