@@ -465,3 +465,355 @@ impl Assets {
465465 self . absolute_timelock = b. absolute_timelock . or ( self . absolute_timelock ) ;
466466 }
467467}
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