diff --git a/src/policy/compiler.rs b/src/policy/compiler.rs index 9b29ee6ba..3d90a9f24 100644 --- a/src/policy/compiler.rs +++ b/src/policy/compiler.rs @@ -24,7 +24,7 @@ use crate::{policy, Miniscript, MiniscriptKey, Terminal}; type PolicyCache = BTreeMap<(Concrete, OrdF64, Option), BTreeMap>>; -///Ordered f64 for comparison +/// Ordered f64 for comparison. #[derive(Copy, Clone, PartialEq, PartialOrd, Debug)] pub(crate) struct OrdF64(pub f64); @@ -36,7 +36,7 @@ impl Ord for OrdF64 { } } -/// Detailed Error type for Compiler +/// Detailed error type for compiler. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum CompilerError { /// Compiler has non-safe input policy. diff --git a/src/policy/concrete.rs b/src/policy/concrete.rs index 8a080200e..9cb184738 100644 --- a/src/policy/concrete.rs +++ b/src/policy/concrete.rs @@ -35,35 +35,35 @@ use crate::{errstr, AbsLockTime, Error, ForEachKey, MiniscriptKey, Translator}; #[cfg(feature = "compiler")] const MAX_COMPILATION_LEAVES: usize = 1024; -/// Concrete policy which corresponds directly to a Miniscript structure, +/// Concrete policy which corresponds directly to a miniscript structure, /// and whose disjunctions are annotated with satisfaction probabilities -/// to assist the compiler +/// to assist the compiler. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Policy { - /// Unsatisfiable + /// Unsatisfiable. Unsatisfiable, - /// Trivially satisfiable + /// Trivially satisfiable. Trivial, - /// A public key which must sign to satisfy the descriptor + /// A public key which must sign to satisfy the descriptor. Key(Pk), - /// An absolute locktime restriction + /// An absolute locktime restriction. After(AbsLockTime), - /// A relative locktime restriction + /// A relative locktime restriction. Older(Sequence), - /// A SHA256 whose preimage must be provided to satisfy the descriptor + /// A SHA256 whose preimage must be provided to satisfy the descriptor. Sha256(Pk::Sha256), - /// A SHA256d whose preimage must be provided to satisfy the descriptor + /// A SHA256d whose preimage must be provided to satisfy the descriptor. Hash256(Pk::Hash256), - /// A RIPEMD160 whose preimage must be provided to satisfy the descriptor + /// A RIPEMD160 whose preimage must be provided to satisfy the descriptor. Ripemd160(Pk::Ripemd160), - /// A HASH160 whose preimage must be provided to satisfy the descriptor + /// A HASH160 whose preimage must be provided to satisfy the descriptor. Hash160(Pk::Hash160), - /// A list of sub-policies, all of which must be satisfied + /// A list of sub-policies, all of which must be satisfied. And(Vec>), /// A list of sub-policies, one of which must be satisfied, along with - /// relative probabilities for each one + /// relative probabilities for each one. Or(Vec<(usize, Policy)>), - /// A set of descriptors, satisfactions must be provided for `k` of them + /// A set of descriptors, satisfactions must be provided for `k` of them. Threshold(usize, Vec>), } @@ -183,29 +183,28 @@ impl From> for PolicyArc { } } -/// Detailed Error type for Policies +/// Detailed error type for concrete policies. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum PolicyError { - /// `And` fragments only support two args + /// `And` fragments only support two args. NonBinaryArgAnd, - /// `Or` fragments only support two args + /// `Or` fragments only support two args. NonBinaryArgOr, - /// `Thresh` fragment can only have `1<=k<=n` + /// `Thresh` fragment can only have `1<=k<=n`. IncorrectThresh, - /// `older` or `after` fragment can only have `n = 0` + /// `older` or `after` fragment can only have `n = 0`. ZeroTime, - /// `after` fragment can only have ` n < 2^31` + /// `after` fragment can only have `n < 2^31`. TimeTooFar, - /// Semantic Policy Error: `And` `Or` fragments must take args: k > 1 + /// Semantic Policy Error: `And` `Or` fragments must take args: `k > 1`. InsufficientArgsforAnd, - /// Semantic Policy Error: `And` `Or` fragments must take args: k > 1 + /// Semantic policy error: `And` `Or` fragments must take args: `k > 1`. InsufficientArgsforOr, - /// Entailment max terminals exceeded + /// Entailment max terminals exceeded. EntailmentMaxTerminals, - /// lifting error: Cannot lift policies that have - /// a combination of height and timelocks. + /// Cannot lift policies that have a combination of height and timelocks. HeightTimelockCombination, - /// Duplicate Public Keys + /// Duplicate Public Keys. DuplicatePubKeys, } @@ -278,8 +277,8 @@ impl error::Error for PolicyError { } impl Policy { - /// Flatten the [`Policy`] tree structure into a Vector of tuple `(leaf script, leaf probability)` - /// with leaf probabilities corresponding to odds for sub-branch in the policy. + /// Flattens the [`Policy`] tree structure into a vector of tuples `(leaf script, leaf probability)` + /// with leaf probabilities corresponding to odds for each sub-branch in the policy. /// We calculate the probability of selecting the sub-branch at every level and calculate the /// leaf probabilities as the probability of traversing through required branches to reach the /// leaf node, i.e. multiplication of the respective probabilities. @@ -298,7 +297,7 @@ impl Policy { /// /// ## Constraints /// - /// Since this splitting might lead to exponential blow-up, we constraint the number of + /// Since this splitting might lead to exponential blow-up, we constrain the number of /// leaf-nodes to [`MAX_COMPILATION_LEAVES`]. #[cfg(feature = "compiler")] fn to_tapleaf_prob_vec(&self, prob: f64) -> Vec<(f64, Policy)> { @@ -323,7 +322,7 @@ impl Policy { } } - /// Extract the internal_key from policy tree. + /// Extracts the internal_key from this policy tree. #[cfg(feature = "compiler")] fn extract_key(self, unspendable_key: Option) -> Result<(Pk, Policy), Error> { let mut internal_key: Option = None; @@ -366,13 +365,14 @@ impl Policy { } } - /// Compile the [`Policy`] into a [`Descriptor::Tr`]. + /// Compiles the [`Policy`] into a [`Descriptor::Tr`]. /// /// ### TapTree compilation /// - /// The policy tree constructed by root-level disjunctions over [`Or`][`Policy::Or`] and - /// [`Thresh`][`Policy::Threshold`](1, ..) which is flattened into a vector (with respective + /// The policy tree constructed by root-level disjunctions over [`Policy::Or`] and + /// [`Policy::Threshold`](1, ..) which is flattened into a vector (with respective /// probabilities derived from odds) of policies. + /// /// For example, the policy `thresh(1,or(pk(A),pk(B)),and(or(pk(C),pk(D)),pk(E)))` gives the /// vector `[pk(A),pk(B),and(or(pk(C),pk(D)),pk(E)))]`. Each policy in the vector is compiled /// into the respective miniscripts. A Huffman Tree is created from this vector which optimizes @@ -424,7 +424,7 @@ impl Policy { /// ### TapTree compilation /// /// The policy tree constructed by root-level disjunctions over [`Policy::Or`] and - /// [`Policy::Threshold`] (k, ..n..) which is flattened into a vector (with respective + /// [`Policy::Threshold`](k, ..n..) which is flattened into a vector (with respective /// probabilities derived from odds) of policies. For example, the policy /// `thresh(1,or(pk(A),pk(B)),and(or(pk(C),pk(D)),pk(E)))` gives the vector /// `[pk(A),pk(B),and(or(pk(C),pk(D)),pk(E)))]`. @@ -437,8 +437,6 @@ impl Policy { /// enumeration or limits exceed. For a given [`Policy`], we maintain an [ordered /// set](`BTreeSet`) of `(prob, policy)` (ordered by probability) to maintain the list of /// enumerated sub-policies whose disjunction is isomorphic to initial policy (*invariant*). - /// - /// [`Policy`]: crate::policy::concrete::Policy #[cfg(feature = "compiler")] pub fn compile_tr_private_experimental( &self, @@ -480,16 +478,16 @@ impl Policy { } } - /// Compile the [`Policy`] into desc_ctx [`Descriptor`] + /// Compiles the [`Policy`] into `desc_ctx` [`Descriptor`] /// - /// In case of [Tr][`DescriptorCtx::Tr`], `internal_key` is used for the Taproot comilation when + /// In case of [`DescriptorCtx::Tr`], `internal_key` is used for the taproot compilation when /// no public key can be inferred from the given policy. /// /// # NOTE: /// - /// It is **not recommended** to use policy as a stable identifier for a miniscript. - /// You should use the policy compiler once, and then use the miniscript output as a stable identifier. - /// See the compiler document in doc/compiler.md for more details. + /// It is **not recommended** to use policy as a stable identifier for a miniscript. You should + /// use the policy compiler once, and then use the miniscript output as a stable identifier. See + /// the compiler document in [`doc/compiler.md`] for more details. #[cfg(feature = "compiler")] pub fn compile_to_descriptor( &self, @@ -511,13 +509,13 @@ impl Policy { } } - /// Compile the descriptor into an optimized `Miniscript` representation + /// Compiles the descriptor into an optimized `Miniscript` representation. /// /// # NOTE: /// - /// It is **not recommended** to use policy as a stable identifier for a miniscript. - /// You should use the policy compiler once, and then use the miniscript output as a stable identifier. - /// See the compiler document in doc/compiler.md for more details. + /// It is **not recommended** to use policy as a stable identifier for a miniscript. You should + /// use the policy compiler once, and then use the miniscript output as a stable identifier. See + /// the compiler document in doc/compiler.md for more details. #[cfg(feature = "compiler")] pub fn compile(&self) -> Result, CompilerError> { self.is_valid()?; @@ -531,10 +529,11 @@ impl Policy { #[cfg(feature = "compiler")] impl PolicyArc { - /// Given a [`Policy`], return a vector of policies whose disjunction is isomorphic to the initial one. - /// This function is supposed to incrementally expand i.e. represent the policy as disjunction over - /// sub-policies output by it. The probability calculations are similar as - /// [to_tapleaf_prob_vec][`Policy::to_tapleaf_prob_vec`] + /// Returns a vector of policies whose disjunction is isomorphic to the initial one. + /// + /// This function is supposed to incrementally expand i.e. represent the policy as + /// disjunction over sub-policies output by it. The probability calculations are similar + /// to [`Policy::to_tapleaf_prob_vec`]. #[cfg(feature = "compiler")] fn enumerate_pol(&self, prob: f64) -> Vec<(f64, Arc)> { match self { @@ -563,8 +562,6 @@ impl PolicyArc { /// enumeration or limits exceed. For a given [`Policy`], we maintain an [ordered /// set](`BTreeSet`) of `(prob, policy)` (ordered by probability) to maintain the list of /// enumerated sub-policies whose disjunction is isomorphic to initial policy (*invariant*). - /// - /// [`Policy`]: crate::policy::concrete::Policy #[cfg(feature = "compiler")] fn enumerate_policy_tree(self, prob: f64) -> Vec<(f64, Arc)> { let mut tapleaf_prob_vec = BTreeSet::<(Reverse, Arc)>::new(); @@ -689,49 +686,9 @@ impl Policy { } } - /// Convert a policy using one kind of public key to another - /// type of public key - /// - /// # Example - /// - /// ``` - /// use miniscript::{bitcoin::PublicKey, policy::concrete::Policy, Translator, hash256}; - /// use std::str::FromStr; - /// use miniscript::translate_hash_fail; - /// use std::collections::HashMap; - /// use miniscript::bitcoin::hashes::{sha256, hash160, ripemd160}; - /// let alice_key = "0270cf3c71f65a3d93d285d9149fddeeb638f87a2d4d8cf16c525f71c417439777"; - /// let bob_key = "02f43b15c50a436f5335dbea8a64dd3b4e63e34c3b50c42598acb5f4f336b5d2fb"; - /// let placeholder_policy = Policy::::from_str("and(pk(alice_key),pk(bob_key))").unwrap(); - /// - /// // Information to translator abstract String type keys to concrete bitcoin::PublicKey. - /// // In practice, wallets would map from String key names to BIP32 keys - /// struct StrPkTranslator { - /// pk_map: HashMap - /// } - /// - /// // If we also wanted to provide mapping of other associated types(sha256, older etc), - /// // we would use the general Translator Trait. - /// impl Translator for StrPkTranslator { - /// // Provides the translation public keys P -> Q - /// fn pk(&mut self, pk: &String) -> Result { - /// self.pk_map.get(pk).copied().ok_or(()) // Dummy Err - /// } - /// - /// // Fail for hash types - /// translate_hash_fail!(String, bitcoin::PublicKey, ()); - /// } + /// Converts a policy using one kind of public key to another type of public key. /// - /// let mut pk_map = HashMap::new(); - /// pk_map.insert(String::from("alice_key"), bitcoin::PublicKey::from_str(alice_key).unwrap()); - /// pk_map.insert(String::from("bob_key"), bitcoin::PublicKey::from_str(bob_key).unwrap()); - /// let mut t = StrPkTranslator { pk_map: pk_map }; - /// - /// let real_policy = placeholder_policy.translate_pk(&mut t).unwrap(); - /// - /// let expected_policy = Policy::from_str(&format!("and(pk({}),pk({}))", alice_key, bob_key)).unwrap(); - /// assert_eq!(real_policy, expected_policy); - /// ``` + /// For example usage please see [`crate::policy::semantic::Policy::translate_pk`]. pub fn translate_pk(&self, t: &mut T) -> Result, E> where T: Translator, @@ -773,7 +730,7 @@ impl Policy { } } - /// Translate `Concrete::Key(key)` to `Concrete::Unsatisfiable` when extracting TapKey + /// Translates `Concrete::Key(key)` to `Concrete::Unsatisfiable` when extracting `TapKey`. pub fn translate_unsatisfiable_pk(self, key: &Pk) -> Policy { match self { Policy::Key(ref k) if k.clone() == *key => Policy::Unsatisfiable, @@ -797,7 +754,7 @@ impl Policy { } } - /// Get all keys in the policy + /// Gets all keys in the policy. pub fn keys(&self) -> Vec<&Pk> { match *self { Policy::Key(ref pk) => vec![pk], @@ -814,8 +771,8 @@ impl Policy { } } - /// Get the number of [TapLeaf][`TapTree::Leaf`] considering exhaustive root-level [OR][`Policy::Or`] - /// and [Thresh][`Policy::Threshold`] disjunctions for the TapTree. + /// Gets the number of [TapLeaf](`TapTree::Leaf`)s considering exhaustive root-level [`Policy::Or`] + /// and [`Policy::Threshold`] disjunctions for the `TapTree`. #[cfg(feature = "compiler")] fn num_tap_leaves(&self) -> usize { match self { @@ -827,7 +784,7 @@ impl Policy { } } - /// Check on the number of TapLeaves + /// Does checks on the number of `TapLeaf`s. #[cfg(feature = "compiler")] fn check_num_tapleaves(&self) -> Result<(), Error> { if self.num_tap_leaves() > MAX_COMPILATION_LEAVES { @@ -836,7 +793,7 @@ impl Policy { Ok(()) } - /// Check whether the policy contains duplicate public keys + /// Checks whether the policy contains duplicate public keys. pub fn check_duplicate_keys(&self) -> Result<(), PolicyError> { let pks = self.keys(); let pks_len = pks.len(); @@ -851,8 +808,11 @@ impl Policy { /// Checks whether the given concrete policy contains a combination of /// timelocks and heightlocks. + /// + /// # Returns + /// /// Returns an error if there is at least one satisfaction that contains - /// a combination of hieghtlock and timelock. + /// a combination of heightlock and timelock. pub fn check_timelocks(&self) -> Result<(), PolicyError> { let timelocks = self.check_timelocks_helper(); if timelocks.contains_combination { @@ -962,11 +922,14 @@ impl Policy { _ => Ok(()), } } - /// This returns whether any possible compilation of the policy could be - /// compiled as non-malleable and safe. Note that this returns a tuple - /// (safe, non-malleable) to avoid because the non-malleability depends on - /// safety and we would like to cache results. + + /// Checks if any possible compilation of the policy could be compiled + /// as non-malleable and safe. + /// + /// # Returns /// + /// Returns a tuple `(safe, non-malleable)` to avoid the fact that + /// non-malleability depends on safety and we would like to cache results. pub fn is_safe_nonmalleable(&self) -> (bool, bool) { match *self { Policy::Unsatisfiable | Policy::Trivial => (true, true), @@ -1232,7 +1195,7 @@ impl_from_tree!( } ); -/// Create a Huffman Tree from compiled [Miniscript] nodes +/// Creates a Huffman Tree from compiled [`Miniscript`] nodes. #[cfg(feature = "compiler")] fn with_huffman_tree( ms: Vec<(OrdF64, Miniscript)>, @@ -1263,7 +1226,7 @@ fn with_huffman_tree( Ok(node) } -/// Enumerate a [Thresh][`Policy::Threshold`](k, ..n..) into `n` different thresh. +/// Enumerates a [`Policy::Threshold(k, ..n..)`] into `n` different thresh's. /// /// ## Strategy /// diff --git a/src/policy/mod.rs b/src/policy/mod.rs index 83348333d..857ae0207 100644 --- a/src/policy/mod.rs +++ b/src/policy/mod.rs @@ -20,42 +20,43 @@ pub mod concrete; pub mod semantic; pub use self::concrete::Policy as Concrete; -/// Semantic policies are "abstract" policies elsewhere; but we -/// avoid this word because it is a reserved keyword in Rust pub use self::semantic::Policy as Semantic; use crate::descriptor::Descriptor; use crate::miniscript::{Miniscript, ScriptContext}; use crate::{Error, MiniscriptKey, Terminal}; -/// Policy entailment algorithm maximum number of terminals allowed +/// Policy entailment algorithm maximum number of terminals allowed. const ENTAILMENT_MAX_TERMINALS: usize = 20; + /// Trait describing script representations which can be lifted into /// an abstract policy, by discarding information. +/// /// After Lifting all policies are converted into `KeyHash(Pk::HasH)` to /// maintain the following invariant(modulo resource limits): /// `Lift(Concrete) == Concrete -> Miniscript -> Script -> Miniscript -> Semantic` -/// Lifting from [Miniscript], [Descriptor] can fail -/// if the miniscript contains a timelock combination or if it contains a -/// branch that exceeds resource limits. -/// Lifting from Concrete policies can fail if it contains a timelock -/// combination. It is possible that concrete policy has some branches that -/// exceed resource limits for any compilation, but cannot detect such -/// policies while lifting. Note that our compiler would not succeed for any -/// such policies. +/// +/// Lifting from [`Miniscript`] or [`Descriptor`] can fail if the miniscript +/// contains a timelock combination or if it contains a branch that exceeds +/// resource limits. +/// +/// Lifting from concrete policies can fail if the policy contains a timelock +/// combination. It is possible that a concrete policy has some branches that +/// exceed resource limits for any compilation but cannot detect such policies +/// while lifting. Note that our compiler would not succeed for any such +/// policies. pub trait Liftable { - /// Convert the object into an abstract policy + /// Converts this object into an abstract policy. fn lift(&self) -> Result, Error>; } -/// Detailed Error type for Policies +/// Error occurring during lifting. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum LiftError { - /// Cannot lift policies that have - /// a combination of height and timelocks. + /// Cannot lift policies that have a combination of height and timelocks. HeightTimelockCombination, - /// Duplicate Public Keys + /// Duplicate public keys. BranchExceedResourceLimits, - /// Cannot lift raw descriptors + /// Cannot lift raw descriptors. RawDescriptorLift, } @@ -85,14 +86,13 @@ impl error::Error for LiftError { } impl Miniscript { - /// Lifting corresponds conversion of miniscript into Policy - /// [policy.semantic.Policy] for human readable or machine analysis. - /// However, naively lifting miniscripts can result in incorrect - /// interpretations that don't correspond underlying semantics when - /// we try to spend them on bitcoin network. - /// This can occur if the miniscript contains a - /// 1. Timelock combination - /// 2. Contains a spend that exceeds resource limits + /// Lifting corresponds to conversion of a miniscript into a [`Semantic`] + /// policy for human readable or machine analysis. However, naively lifting + /// miniscripts can result in incorrect interpretations that don't + /// correspond to the underlying semantics when we try to spend them on + /// bitcoin network. This can occur if the miniscript contains: + /// 1. A combination of timelocks + /// 2. A spend that exceeds resource limits pub fn lift_check(&self) -> Result<(), LiftError> { if !self.within_resource_limits() { Err(LiftError::BranchExceedResourceLimits) diff --git a/src/policy/semantic.rs b/src/policy/semantic.rs index b188492bb..38dbbfd70 100644 --- a/src/policy/semantic.rs +++ b/src/policy/semantic.rs @@ -2,6 +2,9 @@ // SPDX-License-Identifier: CC0-1.0 //! Abstract Policies +//! +//! We use the terms "semantic" and "abstract" interchangeably because +//! "abstract" is a reserved keyword in Rust. use core::str::FromStr; use core::{fmt, str}; @@ -13,33 +16,33 @@ use super::ENTAILMENT_MAX_TERMINALS; use crate::prelude::*; use crate::{errstr, expression, AbsLockTime, Error, ForEachKey, MiniscriptKey, Translator}; -/// Abstract policy which corresponds to the semantics of a Miniscript -/// and which allows complex forms of analysis, e.g. filtering and -/// normalization. +/// Abstract policy which corresponds to the semantics of a miniscript and +/// which allows complex forms of analysis, e.g. filtering and normalization. +/// /// Semantic policies store only hashes of keys to ensure that objects -/// representing the same policy are lifted to the same `Semantic`, +/// representing the same policy are lifted to the same abstract `Policy`, /// regardless of their choice of `pk` or `pk_h` nodes. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] pub enum Policy { - /// Unsatisfiable + /// Unsatisfiable. Unsatisfiable, - /// Trivially satisfiable + /// Trivially satisfiable. Trivial, - /// Signature and public key matching a given hash is required + /// Signature and public key matching a given hash is required. Key(Pk), - /// An absolute locktime restriction + /// An absolute locktime restriction. After(AbsLockTime), - /// A relative locktime restriction + /// A relative locktime restriction. Older(Sequence), - /// A SHA256 whose preimage must be provided to satisfy the descriptor + /// A SHA256 whose preimage must be provided to satisfy the descriptor. Sha256(Pk::Sha256), - /// A SHA256d whose preimage must be provided to satisfy the descriptor + /// A SHA256d whose preimage must be provided to satisfy the descriptor. Hash256(Pk::Hash256), - /// A RIPEMD160 whose preimage must be provided to satisfy the descriptor + /// A RIPEMD160 whose preimage must be provided to satisfy the descriptor. Ripemd160(Pk::Ripemd160), - /// A HASH160 whose preimage must be provided to satisfy the descriptor + /// 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 + /// A set of descriptors, satisfactions must be provided for `k` of them. Threshold(usize, Vec>), } @@ -47,14 +50,16 @@ impl Policy where Pk: MiniscriptKey, { - /// Construct a `Policy::After` from `n`. Helper function equivalent to - /// `Policy::After(absolute::LockTime::from_consensus(n))`. + /// Constructs a `Policy::After` from `n`. + /// + /// Helper function equivalent to `Policy::After(absolute::LockTime::from_consensus(n))`. pub fn after(n: u32) -> Policy { Policy::After(AbsLockTime::from(absolute::LockTime::from_consensus(n))) } - /// Construct a `Policy::Older` from `n`. Helper function equivalent to - /// `Policy::Older(Sequence::from_consensus(n))`. + /// Construct a `Policy::Older` from `n`. + /// + /// Helper function equivalent to `Policy::Older(Sequence::from_consensus(n))`. pub fn older(n: u32) -> Policy { Policy::Older(Sequence::from_consensus(n)) } @@ -83,42 +88,41 @@ impl Policy { } } - /// Convert a policy using one kind of public key to another - /// type of public key + /// Converts a policy using one kind of public key to another type of public key. /// - /// # Example + /// # Examples /// /// ``` - /// use miniscript::{bitcoin::{hashes::hash160, PublicKey}, policy::semantic::Policy, Translator}; - /// use miniscript::translate_hash_fail; - /// use std::str::FromStr; /// use std::collections::HashMap; + /// use std::str::FromStr; + /// use miniscript::bitcoin::{hashes::hash160, PublicKey}; + /// use miniscript::{translate_hash_fail, policy::semantic::Policy, Translator}; /// let alice_pk = "02c79ef3ede6d14f72a00d0e49b4becfb152197b64c0707425c4f231df29500ee7"; /// let bob_pk = "03d008a849fbf474bd17e9d2c1a827077a468150e58221582ec3410ab309f5afe4"; /// let placeholder_policy = Policy::::from_str("and(pk(alice_pk),pk(bob_pk))").unwrap(); /// - /// // Information to translator abstract String type keys to concrete bitcoin::PublicKey. - /// // In practice, wallets would map from String key names to BIP32 keys + /// // Information to translate abstract string type keys to concrete `bitcoin::PublicKey`s. + /// // In practice, wallets would map from string key names to BIP32 keys. /// struct StrPkTranslator { /// pk_map: HashMap /// } /// - /// // If we also wanted to provide mapping of other associated types(sha256, older etc), - /// // we would use the general Translator Trait. + /// // If we also wanted to provide mapping of other associated types (sha256, older etc), + /// // we would use the general [`Translator`] trait. /// impl Translator for StrPkTranslator { /// fn pk(&mut self, pk: &String) -> Result { /// self.pk_map.get(pk).copied().ok_or(()) // Dummy Err /// } /// - /// // Handy macro for failing if we encounter any other fragment. - /// // also see translate_hash_clone! for cloning instead of failing + /// // Handy macro for failing if we encounter any other fragment. + /// // See also [`translate_hash_clone!`] for cloning instead of failing. /// translate_hash_fail!(String, bitcoin::PublicKey, ()); /// } /// /// let mut pk_map = HashMap::new(); /// pk_map.insert(String::from("alice_pk"), bitcoin::PublicKey::from_str(alice_pk).unwrap()); /// pk_map.insert(String::from("bob_pk"), bitcoin::PublicKey::from_str(bob_pk).unwrap()); - /// let mut t = StrPkTranslator { pk_map: pk_map }; + /// let mut t = StrPkTranslator { pk_map }; /// /// let real_policy = placeholder_policy.translate_pk(&mut t).unwrap(); /// @@ -156,11 +160,12 @@ impl Policy { } } - /// This function computes whether the current policy entails the second one. + /// Computes whether the current policy entails the second one. + /// /// A |- B means every satisfaction of A is also a satisfaction of B. - /// This implementation will run slow for larger policies but should be sufficient for - /// most practical policies. - + /// + /// This implementation will run slowly for larger policies but should be + /// sufficient for most practical policies. // This algorithm has a naive implementation. It is possible to optimize this // by memoizing and maintaining a hashmap. pub fn entails(self, other: Policy) -> Result { @@ -208,11 +213,10 @@ impl Policy { } } - // Helper function that takes in witness and its availability, - // changing it to true or false and returning the resultant normalized - // policy. - // Witness is currently encoded as policy. Only accepts leaf fragment and - // a normalized policy + // Helper function that takes in witness and its availability, changing it + // to true or false and returning the resultant normalized policy. Witness + // is currently encoded as policy. Only accepts leaf fragment and a + // normalized policy pub(crate) fn satisfy_constraint(self, witness: &Policy, available: bool) -> Policy { debug_assert!(self.clone().normalized() == self); if let Policy::Threshold { .. } = *witness { @@ -402,7 +406,7 @@ impl_from_tree!( ); impl Policy { - /// Flatten out trees of `And`s and `Or`s; eliminate `Trivial` and + /// 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 { @@ -457,10 +461,11 @@ impl Policy { } } - /// Helper function to detect a true/trivial policy - /// This function only checks whether the policy is Policy::Trivial - /// For checking if the normalized form is trivial, the caller - /// is expected to normalize the policy first. + /// Detects a true/trivial policy. + /// + /// Only checks whether the policy is `Policy::Trivial`, to check if the + /// normalized form is trivial, the caller is expected to normalize the + /// policy first. pub fn is_trivial(&self) -> bool { match *self { Policy::Trivial => true, @@ -468,10 +473,11 @@ impl Policy { } } - /// Helper function to detect a false/unsatisfiable policy - /// This function only checks whether the policy is Policy::Unsatisfiable - /// For checking if the normalized form is unsatisfiable, the caller - /// is expected to normalize the policy first. + /// Detects a false/unsatisfiable policy. + /// + /// Only checks whether the policy is `Policy::Unsatisfiable`, to check if + /// the normalized form is unsatisfiable, the caller is expected to + /// normalize the policy first. pub fn is_unsatisfiable(&self) -> bool { match *self { Policy::Unsatisfiable => true, @@ -498,8 +504,8 @@ impl Policy { } } - /// Returns a list of all relative timelocks, not including 0, - /// which appear in the policy + /// Returns a list of all relative timelocks, not including 0, which appear + /// in the policy. pub fn relative_timelocks(&self) -> Vec { let mut ret = self.real_relative_timelocks(); ret.sort_unstable(); @@ -526,8 +532,8 @@ impl Policy { } } - /// Returns a list of all absolute timelocks, not including 0, - /// which appear in the policy + /// Returns a list of all absolute timelocks, not including 0, which appear + /// in the policy. pub fn absolute_timelocks(&self) -> Vec { let mut ret = self.real_absolute_timelocks(); ret.sort_unstable(); @@ -535,7 +541,7 @@ impl Policy { ret } - /// Filter a policy by eliminating relative timelock constraints + /// 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 { @@ -557,7 +563,7 @@ impl Policy { self.normalized() } - /// Filter a policy by eliminating absolute timelock constraints + /// 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 { use absolute::LockTime::*; @@ -584,7 +590,7 @@ impl Policy { self.normalized() } - /// Count the number of public keys and keyhashes referenced in a policy. + /// 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 { @@ -600,8 +606,11 @@ impl Policy { } } - /// Count the minimum number of public keys for which signatures - /// could be used to satisfy the policy. + /// Counts the minimum number of public keys for which signatures could be + /// used to satisfy the policy. + /// + /// # Returns + /// /// Returns `None` if the policy is not satisfiable. pub fn minimum_n_keys(&self) -> Option { match *self { @@ -630,7 +639,8 @@ impl Policy { } impl Policy { - /// "Sort" a policy to bring it into a canonical form to allow comparisons. + /// "Sorts" a policy to bring it into a canonical form to allow comparisons. + /// /// Does **not** allow policies to be compared for functional equivalence; /// in general this appears to require Gröbner basis techniques that are not /// implemented.