From cac78151935e83a0cd0eb58da0cca175e8e4ba4e Mon Sep 17 00:00:00 2001 From: SarcasticNastik <aman.rojjha@research.iiit.ac.in> Date: Tue, 13 Jul 2021 19:10:04 +0530 Subject: [PATCH 1/2] Add absolute timelocks --- src/policy/semantic.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/policy/semantic.rs b/src/policy/semantic.rs index 740c493a7..b8a261622 100644 --- a/src/policy/semantic.rs +++ b/src/policy/semantic.rs @@ -499,6 +499,34 @@ impl<Pk: MiniscriptKey> Policy<Pk> { ret } + /// Helper function for recursion in `absolute timelocks` + pub fn real_absolute_timelocks(&self) -> Vec<u32> { + match *self { + Policy::Unsatisfiable + | Policy::Trivial + | Policy::KeyHash(..) + | Policy::Sha256(..) + | Policy::Hash256(..) + | Policy::Ripemd160(..) + | Policy::Hash160(..) => vec![], + Policy::Older(..) => vec![], + Policy::After(t) => vec![t], + Policy::Threshold(_, ref subs) => subs.iter().fold(vec![], |mut acc, x| { + acc.extend(x.real_absolute_timelocks()); + acc + }), + } + } + + /// Returns a list of all absolute timelocks, not including 0, + /// which appear in the policy + pub fn absolute_timelocks(&self) -> Vec<u32> { + let mut ret = self.real_absolute_timelocks(); + ret.sort(); + ret.dedup(); + ret + } + /// Filter a policy by eliminating relative timelock constraints /// that are not satisfied at the given age. pub fn at_age(mut self, time: u32) -> Policy<Pk> { @@ -604,6 +632,7 @@ mod tests { let policy = StringPolicy::from_str("pkh()").unwrap(); assert_eq!(policy, Policy::KeyHash("".to_owned())); assert_eq!(policy.relative_timelocks(), vec![]); + assert_eq!(policy.absolute_timelocks(), vec![]); assert_eq!(policy.clone().at_age(0), policy.clone()); assert_eq!(policy.clone().at_age(10000), policy.clone()); assert_eq!(policy.n_keys(), 1); @@ -611,6 +640,7 @@ mod tests { let policy = StringPolicy::from_str("older(1000)").unwrap(); assert_eq!(policy, Policy::Older(1000)); + assert_eq!(policy.absolute_timelocks(), vec![]); assert_eq!(policy.relative_timelocks(), vec![1000]); assert_eq!(policy.clone().at_age(0), Policy::Unsatisfiable); assert_eq!(policy.clone().at_age(999), Policy::Unsatisfiable); From 925ae345c51769c9ff0da7908f26f90866cf5c52 Mon Sep 17 00:00:00 2001 From: SarcasticNastik <aman.rojjha@research.iiit.ac.in> Date: Tue, 13 Jul 2021 19:31:22 +0530 Subject: [PATCH 2/2] Add `at_height` for policy analysis --- src/policy/semantic.rs | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/policy/semantic.rs b/src/policy/semantic.rs index b8a261622..6f18300a0 100644 --- a/src/policy/semantic.rs +++ b/src/policy/semantic.rs @@ -500,7 +500,7 @@ impl<Pk: MiniscriptKey> Policy<Pk> { } /// Helper function for recursion in `absolute timelocks` - pub fn real_absolute_timelocks(&self) -> Vec<u32> { + fn real_absolute_timelocks(&self) -> Vec<u32> { match *self { Policy::Unsatisfiable | Policy::Trivial @@ -546,6 +546,25 @@ impl<Pk: MiniscriptKey> Policy<Pk> { self.normalized() } + /// Filter a policy by eliminating absolute timelock constraints + /// that are not satisfied at the given age. + pub fn at_height(mut self, time: u32) -> Policy<Pk> { + self = match self { + Policy::After(t) => { + if t > time { + Policy::Unsatisfiable + } else { + Policy::After(t) + } + } + Policy::Threshold(k, subs) => { + Policy::Threshold(k, subs.into_iter().map(|sub| sub.at_height(time)).collect()) + } + x => x, + }; + self.normalized() + } + /// Count the number of public keys and keyhashes referenced in a policy. /// Duplicate keys will be double-counted. pub fn n_keys(&self) -> usize { @@ -658,6 +677,7 @@ mod tests { ) ); assert_eq!(policy.relative_timelocks(), vec![1000]); + assert_eq!(policy.absolute_timelocks(), vec![]); assert_eq!(policy.clone().at_age(0), Policy::KeyHash("".to_owned())); assert_eq!(policy.clone().at_age(999), Policy::KeyHash("".to_owned())); assert_eq!(policy.clone().at_age(1000), policy.clone().normalized()); @@ -688,6 +708,17 @@ mod tests { policy.relative_timelocks(), vec![1000, 2000, 10000] //sorted and dedup'd ); + + let policy = StringPolicy::from_str("after(1000)").unwrap(); + assert_eq!(policy, Policy::After(1000)); + assert_eq!(policy.absolute_timelocks(), vec![1000]); + assert_eq!(policy.relative_timelocks(), vec![]); + assert_eq!(policy.clone().at_height(0), Policy::Unsatisfiable); + assert_eq!(policy.clone().at_height(999), Policy::Unsatisfiable); + assert_eq!(policy.clone().at_height(1000), policy.clone()); + assert_eq!(policy.clone().at_height(10000), policy.clone()); + assert_eq!(policy.n_keys(), 0); + assert_eq!(policy.minimum_n_keys(), 0); } #[test]