diff --git a/src/descriptor/sortedmulti.rs b/src/descriptor/sortedmulti.rs index 3bd5fa8e0..9c68db830 100644 --- a/src/descriptor/sortedmulti.rs +++ b/src/descriptor/sortedmulti.rs @@ -17,6 +17,7 @@ use crate::miniscript::limits::MAX_PUBKEYS_PER_MULTISIG; use crate::miniscript::satisfy::{Placeholder, Satisfaction}; use crate::plan::AssetProvider; use crate::prelude::*; +use crate::sync::Arc; use crate::{ errstr, expression, policy, script_num_size, Error, ForEachKey, Miniscript, MiniscriptKey, Satisfier, ToPublicKey, TranslateErr, Translator, @@ -201,7 +202,7 @@ impl policy::Liftable for SortedMulti self.k, self.pks .iter() - .map(|k| policy::semantic::Policy::Key(k.clone())) + .map(|k| Arc::new(policy::semantic::Policy::Key(k.clone()))) .collect(), ); Ok(ret) diff --git a/src/descriptor/tr.rs b/src/descriptor/tr.rs index 81cb5c65a..fd0dcec83 100644 --- a/src/descriptor/tr.rs +++ b/src/descriptor/tr.rs @@ -620,9 +620,10 @@ impl Liftable for TapTree { fn lift(&self) -> Result, Error> { fn lift_helper(s: &TapTree) -> Result, Error> { match *s { - TapTree::Tree { ref left, ref right, height: _ } => { - Ok(Policy::Threshold(1, vec![lift_helper(left)?, lift_helper(right)?])) - } + TapTree::Tree { ref left, ref right, height: _ } => Ok(Policy::Threshold( + 1, + vec![Arc::new(lift_helper(left)?), Arc::new(lift_helper(right)?)], + )), TapTree::Leaf(ref leaf) => leaf.lift(), } } @@ -635,9 +636,13 @@ impl Liftable for TapTree { impl Liftable for Tr { fn lift(&self) -> Result, Error> { match &self.tree { - Some(root) => { - Ok(Policy::Threshold(1, vec![Policy::Key(self.internal_key.clone()), root.lift()?])) - } + Some(root) => Ok(Policy::Threshold( + 1, + vec![ + Arc::new(Policy::Key(self.internal_key.clone())), + Arc::new(root.lift()?), + ], + )), None => Ok(Policy::Key(self.internal_key.clone())), } } diff --git a/src/iter/mod.rs b/src/iter/mod.rs index f8dbed939..02e59b6e2 100644 --- a/src/iter/mod.rs +++ b/src/iter/mod.rs @@ -15,7 +15,7 @@ pub use tree::{ }; use crate::sync::Arc; -use crate::{policy, Miniscript, MiniscriptKey, ScriptContext, Terminal}; +use crate::{Miniscript, MiniscriptKey, ScriptContext, Terminal}; impl<'a, Pk: MiniscriptKey, Ctx: ScriptContext> TreeLike for &'a Miniscript { fn as_node(&self) -> Tree { @@ -68,29 +68,3 @@ impl TreeLike for Arc } } } - -impl<'a, Pk: MiniscriptKey> TreeLike for &'a policy::Concrete { - fn as_node(&self) -> Tree { - use policy::Concrete::*; - match *self { - Unsatisfiable | Trivial | Key(_) | After(_) | Older(_) | Sha256(_) | Hash256(_) - | Ripemd160(_) | Hash160(_) => Tree::Nullary, - And(ref subs) => Tree::Nary(subs.iter().map(Arc::as_ref).collect()), - Or(ref v) => Tree::Nary(v.iter().map(|(_, p)| p.as_ref()).collect()), - Threshold(_, ref subs) => Tree::Nary(subs.iter().map(Arc::as_ref).collect()), - } - } -} - -impl<'a, Pk: MiniscriptKey> TreeLike for Arc> { - fn as_node(&self) -> Tree { - use policy::Concrete::*; - match self.as_ref() { - Unsatisfiable | Trivial | Key(_) | After(_) | Older(_) | Sha256(_) | Hash256(_) - | Ripemd160(_) | Hash160(_) => Tree::Nullary, - And(ref subs) => Tree::Nary(subs.iter().map(Arc::clone).collect()), - Or(ref v) => Tree::Nary(v.iter().map(|(_, p)| Arc::clone(p)).collect()), - Threshold(_, ref subs) => Tree::Nary(subs.iter().map(Arc::clone).collect()), - } - } -} diff --git a/src/policy/concrete.rs b/src/policy/concrete.rs index 19e7771b9..acd153f54 100644 --- a/src/policy/concrete.rs +++ b/src/policy/concrete.rs @@ -23,7 +23,7 @@ use { use super::ENTAILMENT_MAX_TERMINALS; use crate::expression::{self, FromTree}; -use crate::iter::TreeLike; +use crate::iter::{Tree, TreeLike}; use crate::miniscript::types::extra_props::TimelockInfo; use crate::prelude::*; use crate::sync::Arc; @@ -1114,6 +1114,34 @@ fn generate_combination( ret } +impl<'a, Pk: MiniscriptKey> TreeLike for &'a Policy { + fn as_node(&self) -> Tree { + use Policy::*; + + match *self { + Unsatisfiable | Trivial | Key(_) | After(_) | Older(_) | Sha256(_) | Hash256(_) + | Ripemd160(_) | Hash160(_) => Tree::Nullary, + And(ref subs) => Tree::Nary(subs.iter().map(Arc::as_ref).collect()), + Or(ref v) => Tree::Nary(v.iter().map(|(_, p)| p.as_ref()).collect()), + Threshold(_, ref subs) => Tree::Nary(subs.iter().map(Arc::as_ref).collect()), + } + } +} + +impl<'a, Pk: MiniscriptKey> TreeLike for Arc> { + fn as_node(&self) -> Tree { + use Policy::*; + + match self.as_ref() { + Unsatisfiable | Trivial | Key(_) | After(_) | Older(_) | Sha256(_) | Hash256(_) + | Ripemd160(_) | Hash160(_) => Tree::Nullary, + And(ref subs) => Tree::Nary(subs.iter().map(Arc::clone).collect()), + Or(ref v) => Tree::Nary(v.iter().map(|(_, p)| Arc::clone(p)).collect()), + Threshold(_, ref subs) => Tree::Nary(subs.iter().map(Arc::clone).collect()), + } + } +} + #[cfg(all(test, feature = "compiler"))] mod compiler_tests { use core::str::FromStr; diff --git a/src/policy/mod.rs b/src/policy/mod.rs index 138ec45b7..4798e3564 100644 --- a/src/policy/mod.rs +++ b/src/policy/mod.rs @@ -23,7 +23,7 @@ pub use self::semantic::Policy as Semantic; use crate::descriptor::Descriptor; use crate::miniscript::{Miniscript, ScriptContext}; use crate::sync::Arc; -use crate::{Error, MiniscriptKey, Terminal}; +use crate::{Error, MiniscriptKey, Terminal, Vec}; /// Policy entailment algorithm maximum number of terminals allowed. const ENTAILMENT_MAX_TERMINALS: usize = 20; @@ -136,28 +136,40 @@ impl Liftable for Terminal { | Terminal::NonZero(ref sub) | Terminal::ZeroNotEqual(ref sub) => sub.node.lift()?, Terminal::AndV(ref left, ref right) | Terminal::AndB(ref left, ref right) => { - Semantic::Threshold(2, vec![left.node.lift()?, right.node.lift()?]) + Semantic::Threshold( + 2, + vec![Arc::new(left.node.lift()?), Arc::new(right.node.lift()?)], + ) } Terminal::AndOr(ref a, ref b, ref c) => Semantic::Threshold( 1, vec![ - Semantic::Threshold(2, vec![a.node.lift()?, b.node.lift()?]), - c.node.lift()?, + Arc::new(Semantic::Threshold( + 2, + vec![Arc::new(a.node.lift()?), Arc::new(b.node.lift()?)], + )), + Arc::new(c.node.lift()?), ], ), Terminal::OrB(ref left, ref right) | Terminal::OrD(ref left, ref right) | Terminal::OrC(ref left, ref right) - | Terminal::OrI(ref left, ref right) => { - Semantic::Threshold(1, vec![left.node.lift()?, right.node.lift()?]) - } + | Terminal::OrI(ref left, ref right) => Semantic::Threshold( + 1, + vec![Arc::new(left.node.lift()?), Arc::new(right.node.lift()?)], + ), Terminal::Thresh(k, ref subs) => { - let semantic_subs: Result<_, Error> = subs.iter().map(|s| s.node.lift()).collect(); - Semantic::Threshold(k, semantic_subs?) - } - Terminal::Multi(k, ref keys) | Terminal::MultiA(k, ref keys) => { - Semantic::Threshold(k, keys.iter().map(|k| Semantic::Key(k.clone())).collect()) + let semantic_subs: Result>, Error> = + subs.iter().map(|s| s.node.lift()).collect(); + let semantic_subs = semantic_subs?.into_iter().map(Arc::new).collect(); + Semantic::Threshold(k, semantic_subs) } + Terminal::Multi(k, ref keys) | Terminal::MultiA(k, ref keys) => Semantic::Threshold( + k, + keys.iter() + .map(|k| Arc::new(Semantic::Key(k.clone()))) + .collect(), + ), } .normalized(); Ok(ret) @@ -197,17 +209,22 @@ impl Liftable for Concrete { Concrete::Ripemd160(ref h) => Semantic::Ripemd160(h.clone()), Concrete::Hash160(ref h) => Semantic::Hash160(h.clone()), Concrete::And(ref subs) => { - let semantic_subs: Result<_, Error> = subs.iter().map(Liftable::lift).collect(); - Semantic::Threshold(2, semantic_subs?) + let semantic_subs: Result>, Error> = + subs.iter().map(Liftable::lift).collect(); + let semantic_subs = semantic_subs?.into_iter().map(Arc::new).collect(); + Semantic::Threshold(2, semantic_subs) } Concrete::Or(ref subs) => { - let semantic_subs: Result<_, Error> = + let semantic_subs: Result>, Error> = subs.iter().map(|(_p, sub)| sub.lift()).collect(); - Semantic::Threshold(1, semantic_subs?) + let semantic_subs = semantic_subs?.into_iter().map(Arc::new).collect(); + Semantic::Threshold(1, semantic_subs) } Concrete::Threshold(k, ref subs) => { - let semantic_subs: Result<_, Error> = subs.iter().map(Liftable::lift).collect(); - Semantic::Threshold(k, semantic_subs?) + let semantic_subs: Result>, Error> = + subs.iter().map(Liftable::lift).collect(); + let semantic_subs = semantic_subs?.into_iter().map(Arc::new).collect(); + Semantic::Threshold(k, semantic_subs) } } .normalized(); @@ -223,14 +240,12 @@ mod tests { use core::str::FromStr; use bitcoin::Sequence; - #[cfg(feature = "compiler")] - use sync::Arc; - use super::super::miniscript::context::Segwitv0; - use super::super::miniscript::Miniscript; - use super::{Concrete, Liftable, Semantic}; + use super::*; #[cfg(feature = "compiler")] use crate::descriptor::Tr; + use crate::miniscript::context::Segwitv0; + use crate::miniscript::Miniscript; use crate::prelude::*; #[cfg(feature = "compiler")] use crate::{descriptor::TapTree, Descriptor, Tap}; @@ -348,14 +363,14 @@ mod tests { Semantic::Threshold( 1, vec![ - Semantic::Threshold( + Arc::new(Semantic::Threshold( 2, vec![ - Semantic::Key(key_a), - Semantic::Older(Sequence::from_height(42)) + Arc::new(Semantic::Key(key_a)), + Arc::new(Semantic::Older(Sequence::from_height(42))) ] - ), - Semantic::Key(key_b) + )), + Arc::new(Semantic::Key(key_b)) ] ), ms_str.lift().unwrap() diff --git a/src/policy/semantic.rs b/src/policy/semantic.rs index dc84a9439..ec66afe35 100644 --- a/src/policy/semantic.rs +++ b/src/policy/semantic.rs @@ -12,7 +12,9 @@ use bitcoin::{absolute, Sequence}; use super::concrete::PolicyError; use super::ENTAILMENT_MAX_TERMINALS; +use crate::iter::{Tree, TreeLike}; use crate::prelude::*; +use crate::sync::Arc; use crate::{errstr, expression, AbsLockTime, Error, ForEachKey, MiniscriptKey, Translator}; /// Abstract policy which corresponds to the semantics of a miniscript and @@ -42,7 +44,7 @@ pub enum Policy { /// A HASH160 whose preimage must be provided to satisfy the descriptor. Hash160(Pk::Hash160), /// A set of descriptors, satisfactions must be provided for `k` of them. - Threshold(usize, Vec>), + Threshold(usize, Vec>>), } impl Policy @@ -64,27 +66,14 @@ where impl ForEachKey for Policy { fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool { - self.real_for_each_key(&mut pred) + self.pre_order_iter().all(|policy| match policy { + Policy::Key(ref pk) => pred(pk), + _ => true, + }) } } impl Policy { - fn real_for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, pred: &mut F) -> bool { - match *self { - Policy::Unsatisfiable | Policy::Trivial => true, - Policy::Key(ref pk) => pred(pk), - Policy::Sha256(..) - | Policy::Hash256(..) - | Policy::Ripemd160(..) - | Policy::Hash160(..) - | Policy::After(..) - | Policy::Older(..) => true, - Policy::Threshold(_, ref subs) => { - subs.iter().all(|sub| sub.real_for_each_key(&mut *pred)) - } - } - } - /// Converts a policy using one kind of public key to another type of public key. /// /// # Examples @@ -131,22 +120,30 @@ impl Policy { T: Translator, Q: MiniscriptKey, { - match *self { - Policy::Unsatisfiable => Ok(Policy::Unsatisfiable), - Policy::Trivial => Ok(Policy::Trivial), - Policy::Key(ref pk) => t.pk(pk).map(Policy::Key), - Policy::Sha256(ref h) => t.sha256(h).map(Policy::Sha256), - Policy::Hash256(ref h) => t.hash256(h).map(Policy::Hash256), - Policy::Ripemd160(ref h) => t.ripemd160(h).map(Policy::Ripemd160), - Policy::Hash160(ref h) => t.hash160(h).map(Policy::Hash160), - Policy::After(n) => Ok(Policy::After(n)), - Policy::Older(n) => Ok(Policy::Older(n)), - Policy::Threshold(k, ref subs) => { - let new_subs: Result>, _> = - subs.iter().map(|sub| sub.translate_pk(t)).collect(); - new_subs.map(|ok| Policy::Threshold(k, ok)) - } + use Policy::*; + + let mut translated = vec![]; + for data in self.post_order_iter() { + let child_n = |n| Arc::clone(&translated[data.child_indices[n]]); + + let new_policy = match data.node { + Unsatisfiable => Unsatisfiable, + Trivial => Trivial, + Key(ref pk) => t.pk(pk).map(Key)?, + Sha256(ref h) => t.sha256(h).map(Sha256)?, + Hash256(ref h) => t.hash256(h).map(Hash256)?, + Ripemd160(ref h) => t.ripemd160(h).map(Ripemd160)?, + Hash160(ref h) => t.hash160(h).map(Hash160)?, + Older(ref n) => Older(*n), + After(ref n) => After(*n), + Threshold(ref k, ref subs) => Threshold(*k, (0..subs.len()).map(child_n).collect()), + }; + translated.push(Arc::new(new_policy)); } + // Unwrap is ok because we know we processed at least one node. + let root_node = translated.pop().unwrap(); + // Unwrap is ok because we know `root_node` is the only strong reference. + Ok(Arc::try_unwrap(root_node).unwrap()) } /// Computes whether the current policy entails the second one. @@ -184,11 +181,21 @@ impl Policy { // Helper function to compute the number of constraints in policy. fn n_terminals(&self) -> usize { - match self { - &Policy::Threshold(_k, ref subs) => subs.iter().map(|sub| sub.n_terminals()).sum(), - &Policy::Trivial | &Policy::Unsatisfiable => 0, - _leaf => 1, + use Policy::*; + + let mut n_terminals = vec![]; + for data in self.post_order_iter() { + let n_terminals_for_child_n = |n| n_terminals[data.child_indices[n]]; + + let num = match data.node { + Threshold(_k, subs) => (0..subs.len()).map(n_terminals_for_child_n).sum(), + Trivial | Unsatisfiable => 0, + _leaf => 1, + }; + n_terminals.push(num); } + // Ok to unwrap because we know we processed at least one node. + n_terminals.pop().unwrap() } // Helper function to get the first constraint in the policy. @@ -217,8 +224,9 @@ impl Policy { Policy::Threshold(k, subs) => { let mut ret_subs = vec![]; for sub in subs { - ret_subs.push(sub.satisfy_constraint(witness, available)); + ret_subs.push(sub.as_ref().clone().satisfy_constraint(witness, available)); } + let ret_subs = ret_subs.into_iter().map(Arc::new).collect(); Policy::Threshold(k, ret_subs) } ref leaf if leaf == witness => { @@ -344,7 +352,7 @@ impl_from_tree!( } let mut subs = Vec::with_capacity(nsubs); for arg in &top.args { - subs.push(Policy::from_tree(arg)?); + subs.push(Arc::new(Policy::from_tree(arg)?)); } Ok(Policy::Threshold(nsubs, subs)) } @@ -354,7 +362,7 @@ impl_from_tree!( } let mut subs = Vec::with_capacity(nsubs); for arg in &top.args { - subs.push(Policy::from_tree(arg)?); + subs.push(Arc::new(Policy::from_tree(arg)?)); } Ok(Policy::Threshold(1, subs)) } @@ -372,7 +380,7 @@ impl_from_tree!( // thresh(1) and thresh(n) are disallowed in semantic policies if thresh <= 1 || thresh >= (nsubs as u32 - 1) { return Err(errstr( - "Semantic Policy thresh cannot have k = 1 or k =n, use `and`/`or` instead", + "Semantic Policy thresh cannot have k = 1 or k = n, use `and`/`or` instead", )); } if thresh >= (nsubs as u32) { @@ -381,7 +389,7 @@ impl_from_tree!( let mut subs = Vec::with_capacity(top.args.len() - 1); for arg in &top.args[1..] { - subs.push(Policy::from_tree(arg)?); + subs.push(Arc::new(Policy::from_tree(arg)?)); } Ok(Policy::Threshold(thresh as usize, subs)) } @@ -394,56 +402,90 @@ impl Policy { /// Flattens out trees of `And`s and `Or`s; eliminate `Trivial` and /// `Unsatisfiable`s. Does not reorder any branches; use `.sort`. pub fn normalized(self) -> Policy { - match self { - Policy::Threshold(k, subs) => { - let mut ret_subs = Vec::with_capacity(subs.len()); - - let subs: Vec<_> = subs.into_iter().map(|sub| sub.normalized()).collect(); - let trivial_count = subs.iter().filter(|&pol| *pol == Policy::Trivial).count(); - let unsatisfied_count = subs - .iter() - .filter(|&pol| *pol == Policy::Unsatisfiable) - .count(); - - let n = subs.len() - unsatisfied_count - trivial_count; // remove all true/false - let m = k.checked_sub(trivial_count).map_or(0, |x| x); // satisfy all trivial - // m == n denotes `and` and m == 1 denotes `or` - let is_and = m == n; - let is_or = m == 1; - for sub in subs { - match sub { - Policy::Trivial | Policy::Unsatisfiable => {} - Policy::Threshold(k, subs) => { - match (is_and, is_or) { - (true, true) => { - // means m = n = 1, thresh(1,X) type thing. - ret_subs.push(Policy::Threshold(k, subs)); + // Returns (m, n)-thresh values for the normalized (k, subs.len())-thresh. + fn normalized_threshold_values( + k: usize, + subs: &[Arc>], + ) -> (usize, usize) { + let trivial_count = subs + .iter() + .filter(|&pol| *pol.as_ref() == Policy::Trivial) + .count(); + let unsatisfied_count = subs + .iter() + .filter(|&pol| *pol.as_ref() == Policy::Unsatisfiable) + .count(); + + let n = subs.len() - unsatisfied_count - trivial_count; // remove all true/false + let m = k.checked_sub(trivial_count).unwrap_or(0); // satisfy all trivial + + (m, n) + } + + use Policy::*; + + let mut normalized: Vec>> = vec![]; + for data in Arc::new(self).post_order_iter() { + let child_n = |n| Arc::clone(&normalized[data.child_indices[n]]); + + let new_policy = match data.node.as_ref() { + Threshold(k, ref subs) => { + let mut ret_subs = Vec::with_capacity(subs.len()); + let (m, n) = normalized_threshold_values(*k, &subs); + + let parent_is_and = m == n; // (n, n)-thresh is an AND + let parent_is_or = m == 1; // (1, n)-thresh is an OR + + for sub in (0..subs.len()).map(child_n) { + match sub.as_ref() { + Trivial | Unsatisfiable => {} + Threshold(ref k, ref subs) => { + let child_is_and = *k == subs.len(); + let child_is_or = *k == 1; + + if parent_is_and && parent_is_or { + // m = n = 1, child must be the non-trivial, non-unsatisfiable node. + ret_subs.push(Arc::clone(&sub)); + } else if parent_is_and && child_is_and { + // If both parent and child are ANDs we can flatten them. + subs.iter().for_each(|sub| ret_subs.push(Arc::clone(sub))); + } else if parent_is_or && child_is_or { + // If both parent and child are ORs we can flatten them. + subs.iter().for_each(|sub| ret_subs.push(Arc::clone(sub))); + } else { + ret_subs.push(Arc::clone(&sub)); } - (true, false) if k == subs.len() => ret_subs.extend(subs), // and case - (false, true) if k == 1 => ret_subs.extend(subs), // or case - _ => ret_subs.push(Policy::Threshold(k, subs)), } + _ => ret_subs.push(Arc::clone(&sub)), } - x => ret_subs.push(x), + } + // Now reason about m of n threshold + if m == 0 { + Some(Trivial) + } else if m > ret_subs.len() { + Some(Unsatisfiable) + } else if ret_subs.len() == 1 { + let policy = ret_subs.pop().unwrap(); + Some((*policy).clone()) // I'm lost now, can we try_unwrap still? + } else if parent_is_and { + Some(Threshold(ret_subs.len(), ret_subs)) + } else if parent_is_or { + Some(Threshold(1, ret_subs)) + } else { + Some(Threshold(m, ret_subs)) } } - // Now reason about m of n threshold - if m == 0 { - Policy::Trivial - } else if m > ret_subs.len() { - Policy::Unsatisfiable - } else if ret_subs.len() == 1 { - ret_subs.pop().unwrap() - } else if is_and { - Policy::Threshold(ret_subs.len(), ret_subs) - } else if is_or { - Policy::Threshold(1, ret_subs) - } else { - Policy::Threshold(m, ret_subs) - } + _ => None, + }; + match new_policy { + Some(new_policy) => normalized.push(Arc::new(new_policy)), + None => normalized.push(Arc::clone(&data.node)), } - x => x, } + // Unwrap is ok because we know we processed at least one node. + let root_node = normalized.pop().unwrap(); + // Unwrap is ok because we know `root_node` is the only strong reference. + Arc::try_unwrap(root_node).unwrap() } /// Detects a true/trivial policy. @@ -462,21 +504,12 @@ impl Policy { /// Helper function to do the recursion in `timelocks`. fn real_relative_timelocks(&self) -> Vec { - match *self { - Policy::Unsatisfiable - | Policy::Trivial - | Policy::Key(..) - | Policy::Sha256(..) - | Policy::Hash256(..) - | Policy::Ripemd160(..) - | Policy::Hash160(..) => vec![], - Policy::After(..) => vec![], - Policy::Older(t) => vec![t.to_consensus_u32()], - Policy::Threshold(_, ref subs) => subs.iter().fold(vec![], |mut acc, x| { - acc.extend(x.real_relative_timelocks()); - acc - }), - } + self.pre_order_iter() + .filter_map(|policy| match policy { + Policy::Older(t) => Some(t.to_consensus_u32()), + _ => None, + }) + .collect() } /// Returns a list of all relative timelocks, not including 0, which appear @@ -490,21 +523,12 @@ impl Policy { /// Helper function for recursion in `absolute timelocks` fn real_absolute_timelocks(&self) -> Vec { - match *self { - Policy::Unsatisfiable - | Policy::Trivial - | Policy::Key(..) - | Policy::Sha256(..) - | Policy::Hash256(..) - | Policy::Ripemd160(..) - | Policy::Hash160(..) => vec![], - Policy::Older(..) => vec![], - Policy::After(t) => vec![t.to_u32()], - Policy::Threshold(_, ref subs) => subs.iter().fold(vec![], |mut acc, x| { - acc.extend(x.real_absolute_timelocks()); - acc - }), - } + self.pre_order_iter() + .filter_map(|policy| match policy { + Policy::After(t) => Some(t.to_u32()), + _ => None, + }) + .collect() } /// Returns a list of all absolute timelocks, not including 0, which appear @@ -518,67 +542,91 @@ impl Policy { /// Filters a policy by eliminating relative timelock constraints /// that are not satisfied at the given `age`. - pub fn at_age(mut self, age: Sequence) -> Policy { - self = match self { - Policy::Older(t) => { - if t.is_height_locked() && age.is_time_locked() - || t.is_time_locked() && age.is_height_locked() - || t.to_consensus_u32() > age.to_consensus_u32() - { - Policy::Unsatisfiable - } else { - Policy::Older(t) + pub fn at_age(self, age: Sequence) -> Policy { + use Policy::*; + + let mut at_age = vec![]; + for data in Arc::new(self).post_order_iter() { + let child_n = |n| Arc::clone(&at_age[data.child_indices[n]]); + + let new_policy = match data.node.as_ref() { + Older(ref t) => { + if t.is_height_locked() && age.is_time_locked() + || t.is_time_locked() && age.is_height_locked() + || t.to_consensus_u32() > age.to_consensus_u32() + { + Some(Policy::Unsatisfiable) + } else { + Some(Policy::Older(*t)) + } } + Threshold(k, ref subs) => { + Some(Threshold(*k, (0..subs.len()).map(child_n).collect())) + } + _ => None, + }; + match new_policy { + Some(new_policy) => at_age.push(Arc::new(new_policy)), + None => at_age.push(Arc::clone(&data.node)), } - Policy::Threshold(k, subs) => { - Policy::Threshold(k, subs.into_iter().map(|sub| sub.at_age(age)).collect()) - } - x => x, - }; - self.normalized() + } + // Unwrap is ok because we know we processed at least one node. + let root_node = at_age.pop().unwrap(); + // Unwrap is ok because we know `root_node` is the only strong reference. + let policy = Arc::try_unwrap(root_node).unwrap(); + policy.normalized() } /// Filters a policy by eliminating absolute timelock constraints /// that are not satisfied at the given `n` (`n OP_CHECKLOCKTIMEVERIFY`). - pub fn at_lock_time(mut self, n: absolute::LockTime) -> Policy { + pub fn at_lock_time(self, n: absolute::LockTime) -> Policy { use absolute::LockTime::*; - - self = match self { - Policy::After(t) => { - let t = absolute::LockTime::from(t); - let is_satisfied_by = match (t, n) { - (Blocks(t), Blocks(n)) => t <= n, - (Seconds(t), Seconds(n)) => t <= n, - _ => false, - }; - if !is_satisfied_by { - Policy::Unsatisfiable - } else { - Policy::After(t.into()) + use Policy::*; + + let mut at_age = vec![]; + for data in Arc::new(self).post_order_iter() { + let child_n = |n| Arc::clone(&at_age[data.child_indices[n]]); + + let new_policy = match data.node.as_ref() { + After(t) => { + let t = absolute::LockTime::from(*t); + let is_satisfied_by = match (t, n) { + (Blocks(t), Blocks(n)) => t <= n, + (Seconds(t), Seconds(n)) => t <= n, + _ => false, + }; + if !is_satisfied_by { + Some(Unsatisfiable) + } else { + Some(After(t.into())) + } } + Threshold(k, ref subs) => { + Some(Threshold(*k, (0..subs.len()).map(child_n).collect())) + } + _ => None, + }; + match new_policy { + Some(new_policy) => at_age.push(Arc::new(new_policy)), + None => at_age.push(Arc::clone(&data.node)), } - Policy::Threshold(k, subs) => { - Policy::Threshold(k, subs.into_iter().map(|sub| sub.at_lock_time(n)).collect()) - } - x => x, - }; - self.normalized() + } + // Unwrap is ok because we know we processed at least one node. + let root_node = at_age.pop().unwrap(); + // Unwrap is ok because we know `root_node` is the only strong reference. + let policy = Arc::try_unwrap(root_node).unwrap(); + policy.normalized() } /// Counts the number of public keys and keyhashes referenced in a policy. /// Duplicate keys will be double-counted. pub fn n_keys(&self) -> usize { - match *self { - Policy::Unsatisfiable | Policy::Trivial => 0, - Policy::Key(..) => 1, - Policy::After(..) - | Policy::Older(..) - | Policy::Sha256(..) - | Policy::Hash256(..) - | Policy::Ripemd160(..) - | Policy::Hash160(..) => 0, - Policy::Threshold(_, ref subs) => subs.iter().map(|sub| sub.n_keys()).sum::(), - } + self.pre_order_iter() + .filter(|policy| match policy { + Policy::Key(..) => true, + _ => false, + }) + .count() } /// Counts the minimum number of public keys for which signatures could be @@ -588,28 +636,34 @@ impl Policy { /// /// Returns `None` if the policy is not satisfiable. pub fn minimum_n_keys(&self) -> Option { - match *self { - Policy::Unsatisfiable => None, - Policy::Trivial => Some(0), - Policy::Key(..) => Some(1), - Policy::After(..) - | Policy::Older(..) - | Policy::Sha256(..) - | Policy::Hash256(..) - | Policy::Ripemd160(..) - | Policy::Hash160(..) => Some(0), - Policy::Threshold(k, ref subs) => { - let mut sublens: Vec = - subs.iter().filter_map(Policy::minimum_n_keys).collect(); - if sublens.len() < k { - // Not enough branches are satisfiable - None - } else { - sublens.sort_unstable(); - Some(sublens[0..k].iter().cloned().sum::()) + use Policy::*; + + let mut minimum_n_keys = vec![]; + for data in Arc::new(self).post_order_iter() { + let minimum_n_keys_for_child_n = |n| minimum_n_keys[data.child_indices[n]]; + + let minimum_n_key = match data.node { + Unsatisfiable => None, + Trivial | After(..) | Older(..) | Sha256(..) | Hash256(..) | Ripemd160(..) + | Hash160(..) => Some(0), + Key(..) => Some(1), + Threshold(k, ref subs) => { + let mut sublens = (0..subs.len()) + .filter_map(minimum_n_keys_for_child_n) + .collect::>(); + if sublens.len() < *k { + // Not enough branches are satisfiable + None + } else { + sublens.sort_unstable(); + Some(sublens[0..*k].iter().cloned().sum::()) + } } - } + }; + minimum_n_keys.push(minimum_n_key); } + // Ok to unwrap because we know we processed at least one node. + minimum_n_keys.pop().unwrap() } } @@ -620,13 +674,52 @@ impl Policy { /// in general this appears to require Gröbner basis techniques that are not /// implemented. pub fn sorted(self) -> Policy { - match self { - Policy::Threshold(k, subs) => { - let mut new_subs: Vec<_> = subs.into_iter().map(Policy::sorted).collect(); - new_subs.sort(); - Policy::Threshold(k, new_subs) + use Policy::*; + + let mut sorted = vec![]; + for data in Arc::new(self).post_order_iter() { + let child_n = |n| Arc::clone(&sorted[data.child_indices[n]]); + + let new_policy = match data.node.as_ref() { + Threshold(k, ref subs) => { + let mut subs = (0..subs.len()).map(child_n).collect::>(); + subs.sort(); + Some(Threshold(*k, subs)) + } + _ => None, + }; + match new_policy { + Some(new_policy) => sorted.push(Arc::new(new_policy)), + None => sorted.push(Arc::clone(&data.node)), } - x => x, + } + // Unwrap is ok because we know we processed at least one node. + let root_node = sorted.pop().unwrap(); + // Unwrap is ok because we know `root_node` is the only strong reference. + Arc::try_unwrap(root_node).unwrap() + } +} + +impl<'a, Pk: MiniscriptKey> TreeLike for &'a Policy { + fn as_node(&self) -> Tree { + use Policy::*; + + match *self { + Unsatisfiable | Trivial | Key(_) | After(_) | Older(_) | Sha256(_) | Hash256(_) + | Ripemd160(_) | Hash160(_) => Tree::Nullary, + Threshold(_, ref subs) => Tree::Nary(subs.iter().map(Arc::as_ref).collect()), + } + } +} + +impl<'a, Pk: MiniscriptKey> TreeLike for Arc> { + fn as_node(&self) -> Tree { + use Policy::*; + + match self.as_ref() { + Unsatisfiable | Trivial | Key(_) | After(_) | Older(_) | Sha256(_) | Hash256(_) + | Ripemd160(_) | Hash160(_) => Tree::Nullary, + Threshold(_, ref subs) => Tree::Nary(subs.iter().map(Arc::clone).collect()), } } } @@ -693,8 +786,8 @@ mod tests { Policy::Threshold( 1, vec![ - Policy::Key("".to_owned()), - Policy::Older(Sequence::from_height(1000)), + Policy::Key("".to_owned()).into(), + Policy::Older(Sequence::from_height(1000)).into(), ] ) ); @@ -713,7 +806,13 @@ mod tests { let policy = StringPolicy::from_str("or(pk(),UNSATISFIABLE)").unwrap(); assert_eq!( policy, - Policy::Threshold(1, vec![Policy::Key("".to_owned()), Policy::Unsatisfiable,]) + Policy::Threshold( + 1, + vec![ + Policy::Key("".to_owned()).into(), + Policy::Unsatisfiable.into() + ] + ) ); assert_eq!(policy.relative_timelocks(), vec![]); assert_eq!(policy.absolute_timelocks(), vec![]); @@ -723,7 +822,13 @@ mod tests { let policy = StringPolicy::from_str("and(pk(),UNSATISFIABLE)").unwrap(); assert_eq!( policy, - Policy::Threshold(2, vec![Policy::Key("".to_owned()), Policy::Unsatisfiable,]) + Policy::Threshold( + 2, + vec![ + Policy::Key("".to_owned()).into(), + Policy::Unsatisfiable.into() + ] + ) ); assert_eq!(policy.relative_timelocks(), vec![]); assert_eq!(policy.absolute_timelocks(), vec![]); @@ -741,11 +846,11 @@ mod tests { Policy::Threshold( 2, vec![ - Policy::Older(Sequence::from_height(1000)), - Policy::Older(Sequence::from_height(10000)), - Policy::Older(Sequence::from_height(1000)), - Policy::Older(Sequence::from_height(2000)), - Policy::Older(Sequence::from_height(2000)), + Policy::Older(Sequence::from_height(1000)).into(), + Policy::Older(Sequence::from_height(10000)).into(), + Policy::Older(Sequence::from_height(1000)).into(), + Policy::Older(Sequence::from_height(2000)).into(), + Policy::Older(Sequence::from_height(2000)).into(), ] ) ); @@ -765,11 +870,11 @@ mod tests { Policy::Threshold( 2, vec![ - Policy::Older(Sequence::from_height(1000)), - Policy::Older(Sequence::from_height(10000)), - Policy::Older(Sequence::from_height(1000)), - Policy::Unsatisfiable, - Policy::Unsatisfiable, + Policy::Older(Sequence::from_height(1000)).into(), + Policy::Older(Sequence::from_height(10000)).into(), + Policy::Older(Sequence::from_height(1000)).into(), + Policy::Unsatisfiable.into(), + Policy::Unsatisfiable.into(), ] ) ); @@ -875,7 +980,8 @@ mod tests { "or(and(older(4096),thresh(2,pk(A),pk(B),pk(C))),thresh(11,pk(F1),pk(F2),pk(F3),pk(F4),pk(F5),pk(F6),pk(F7),pk(F8),pk(F9),pk(F10),pk(F11),pk(F12),pk(F13),pk(F14)))").unwrap(); // Very bad idea to add master key,pk but let's have it have 50M blocks let master_key = StringPolicy::from_str("and(older(50000000),pk(master))").unwrap(); - let new_liquid_pol = Policy::Threshold(1, vec![liquid_pol.clone(), master_key]); + let new_liquid_pol = + Policy::Threshold(1, vec![liquid_pol.clone().into(), master_key.into()]); assert!(liquid_pol.clone().entails(new_liquid_pol.clone()).unwrap()); assert!(!new_liquid_pol.entails(liquid_pol.clone()).unwrap()); @@ -952,4 +1058,86 @@ mod tests { })); assert_eq!(count, 17); } + + fn four_arbitrary_keys( + ) -> (Arc, Arc, Arc, Arc) { + let a = Arc::new(StringPolicy::from_str("pk(A)").unwrap()); + let b = Arc::new(StringPolicy::from_str("pk(B)").unwrap()); + let c = Arc::new(StringPolicy::from_str("pk(C)").unwrap()); + let d = Arc::new(StringPolicy::from_str("pk(D)").unwrap()); + + (a, b, c, d) + } + + #[test] + fn normalize_nested_and() { + let (a, b, c, d) = four_arbitrary_keys(); + + let thresh0 = StringPolicy::Threshold(2, vec![a.clone(), b.clone()]); + let thresh1 = StringPolicy::Threshold(2, vec![c.clone(), d.clone()]); + + let policy = StringPolicy::Threshold(2, vec![thresh0.into(), thresh1.into()]); + let got = policy.normalized(); + + let want = StringPolicy::Threshold(4, vec![a, b, c, d]); + + assert_eq!(got, want) + } + + #[test] + fn normalize_nested_or() { + let (a, b, c, d) = four_arbitrary_keys(); + + let thresh0 = StringPolicy::Threshold(1, vec![a.clone(), b.clone()]); + let thresh1 = StringPolicy::Threshold(1, vec![c.clone(), d.clone()]); + + let policy = StringPolicy::Threshold(1, vec![thresh0.into(), thresh1.into()]); + let got = policy.normalized(); + + let want = StringPolicy::Threshold(1, vec![a, b, c, d]); + + assert_eq!(got, want) + } + + #[test] + fn normalize_2_of_5_containing_2_unsatisfiable_1_trivial() { + let (a, b, _, _) = four_arbitrary_keys(); + let u = Arc::new(StringPolicy::Unsatisfiable); + let t = Arc::new(StringPolicy::Trivial); + + // (2,5)-thresh with only 2 satisfiable, 1 trivial + let policy = + StringPolicy::Threshold(2, vec![a.clone(), b.clone(), u.clone(), u.clone(), t]); + let got = policy.normalized(); + let want = StringPolicy::Threshold(1, vec![a, b]); + + assert_eq!(got, want) + } + + #[test] + fn normalize_2_of_5_containing_3_unsatisfiable() { + let (a, b, _, _) = four_arbitrary_keys(); + let u = Arc::new(StringPolicy::Unsatisfiable); + + // (2,5)-thresh with only 2 satisfiable + let policy = + StringPolicy::Threshold(2, vec![a.clone(), b.clone(), u.clone(), u.clone(), u.clone()]); + let got = policy.normalized(); + let want = StringPolicy::Threshold(2, vec![a, b]); + + assert_eq!(got, want) + } + + #[test] + fn normalize_2_of_3_containing_2_unsatisfiable() { + let (a, _, _, _) = four_arbitrary_keys(); + let u = Arc::new(StringPolicy::Unsatisfiable); + + // (2,3)-thresh with only 2 satisfiable + let policy = StringPolicy::Threshold(2, vec![a.clone(), u.clone(), u.clone()]); + let got = policy.normalized(); + let want = StringPolicy::Unsatisfiable; + + assert_eq!(got, want) + } }