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