diff --git a/src/miniscript/mod.rs b/src/miniscript/mod.rs index e4c35b032..8488a07e6 100644 --- a/src/miniscript/mod.rs +++ b/src/miniscript/mod.rs @@ -1136,8 +1136,11 @@ mod tests { let schnorr_sig = secp256k1::schnorr::Signature::from_str("84526253c27c7aef56c7b71a5cd25bebb66dddda437826defc5b2568bde81f0784526253c27c7aef56c7b71a5cd25bebb66dddda437826defc5b2568bde81f07").unwrap(); let s = SimpleSatisfier(schnorr_sig); + let template = tap_ms.build_template(&s); + assert_eq!(template.absolute_timelock, None); + assert_eq!(template.relative_timelock, None); - let wit = tap_ms.satisfy(s).unwrap(); + let wit = tap_ms.satisfy(&s).unwrap(); assert_eq!(wit, vec![schnorr_sig.as_ref().to_vec(), vec![], vec![]]); } @@ -1171,4 +1174,113 @@ mod tests { SegwitMs::parse_insane(&script).unwrap_err(); SegwitMs::parse_with_ext(&script, &ExtParams::allow_all()).unwrap(); } + + #[test] + fn template_timelocks() { + let key_present = bitcoin::PublicKey::from_str( + "0327a6ed0e71b451c79327aa9e4a6bb26ffb1c0056abc02c25e783f6096b79bb4f", + ) + .unwrap(); + let key_missing = bitcoin::PublicKey::from_str( + "03e4d788718644a59030b1d234d8bb8fff28314720b9a1a237874b74b089c638da", + ) + .unwrap(); + + // ms, absolute_timelock, relative_timelock + let test_cases = vec![ + ( + format!("t:or_c(pk({}),v:pkh({}))", key_present, key_missing), + None, + None, + ), + ( + format!( + "thresh(2,pk({}),s:pk({}),snl:after(1))", + key_present, key_missing + ), + Some(bitcoin::PackedLockTime(1)), + None, + ), + ( + format!( + "or_d(pk({}),and_v(v:pk({}),older(12960)))", + key_present, key_missing + ), + None, + None, + ), + ( + format!( + "or_d(pk({}),and_v(v:pk({}),older(12960)))", + key_missing, key_present + ), + None, + Some(bitcoin::Sequence(12960)), + ), + ( + format!( + "thresh(3,pk({}),s:pk({}),snl:older(10),snl:after(11))", + key_present, key_missing + ), + Some(bitcoin::PackedLockTime(11)), + Some(bitcoin::Sequence(10)), + ), + ( + format!("and_v(v:and_v(v:pk({}),older(10)),older(20))", key_present), + None, + Some(bitcoin::Sequence(20)), + ), + ( + format!( + "andor(pk({}),older(10),and_v(v:pk({}),older(20)))", + key_present, key_missing + ), + None, + Some(bitcoin::Sequence(10)), + ), + ]; + + // Test satisfaction code + struct SimpleSatisfier(secp256k1::schnorr::Signature, bitcoin::PublicKey); + + // a simple satisfier that always outputs the same signature + impl Satisfier for SimpleSatisfier { + fn lookup_tap_leaf_script_sig( + &self, + pk: &bitcoin::PublicKey, + _h: &TapLeafHash, + ) -> Option { + if pk == &self.1 { + Some(bitcoin::SchnorrSig { + sig: self.0, + hash_ty: bitcoin::SchnorrSighashType::Default, + }) + } else { + None + } + } + + fn check_older(&self, _: bitcoin::Sequence) -> bool { + true + } + + fn check_after(&self, _: bitcoin::LockTime) -> bool { + true + } + } + + let schnorr_sig = secp256k1::schnorr::Signature::from_str("84526253c27c7aef56c7b71a5cd25bebb66dddda437826defc5b2568bde81f0784526253c27c7aef56c7b71a5cd25bebb66dddda437826defc5b2568bde81f07").unwrap(); + let s = SimpleSatisfier(schnorr_sig, key_present); + + for (ms_str, absolute_timelock, relative_timelock) in test_cases { + let ms = Miniscript::::from_str(&ms_str).unwrap(); + let template = ms.build_template(&s); + match template.stack { + crate::miniscript::satisfy::Witness::Stack(_) => {} + _ => panic!("Should be possible"), + } + assert_eq!(template.absolute_timelock, absolute_timelock, "{}", ms_str); + assert_eq!(template.relative_timelock, relative_timelock, "{}", ms_str); + } + } }