Skip to content

Commit 2f5436f

Browse files
tests: plan capabilities
Co-authored-by: Alekos Filini <[email protected]>
1 parent 344a53e commit 2f5436f

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

Comments
 (0)