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