Skip to content

Commit 473932b

Browse files
tests: plan capabilities
Co-authored-by: Alekos Filini <[email protected]>
1 parent e1a6c3d commit 473932b

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
@@ -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

Comments
 (0)