@@ -457,3 +457,355 @@ impl Assets {
457457 self . absolute_timelock = b. absolute_timelock . or ( self . absolute_timelock ) ;
458458 }
459459}
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