Skip to content

Commit 54b2fdf

Browse files
tests: plan capabilities
Co-authored-by: Alekos Filini <[email protected]>
1 parent cf3f2de commit 54b2fdf

File tree

1 file changed

+352
-0
lines changed

1 file changed

+352
-0
lines changed

src/plan.rs

+352
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)