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