@@ -502,3 +502,355 @@ impl Assets {
502502 self . absolute_timelock = b. absolute_timelock . or ( self . absolute_timelock ) ;
503503 }
504504}
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