Skip to content

Commit 43471f0

Browse files
tests: plan capabilities
Co-authored-by: Alekos Filini <[email protected]>
1 parent 2b5d678 commit 43471f0

File tree

1 file changed

+352
-0
lines changed

1 file changed

+352
-0
lines changed

src/plan.rs

Lines changed: 352 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)