diff --git a/Cargo.toml b/Cargo.toml index ad6180db..a6f93ed4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ bitcoin = { version = "0.29.2", optional = true } bitcoin_hashes = "0.11" byteorder = "1.3" elements = { version = "0.21.1", optional = true } -elements-miniscript = { git = "https://github.com/ElementsProject/elements-miniscript", rev = "955f380" } +elements-miniscript = { git = "https://github.com/apoelstra/elements-miniscript", tag = "2023-07--rust-simplicity-patch" } simplicity-sys = { version = "0.1.0", path = "./simplicity-sys" } actual-serde = { package = "serde", version = "1.0.103", features = ["derive"], optional = true } diff --git a/src/policy/ast.rs b/src/policy/ast.rs index 2d754012..f46af16f 100644 --- a/src/policy/ast.rs +++ b/src/policy/ast.rs @@ -25,7 +25,7 @@ use std::sync::Arc; use std::{fmt, iter, mem}; use crate::jet::Elements; -use crate::miniscript::{MiniscriptKey, ToPublicKey, Translator}; +use crate::miniscript::{ForEachKey, MiniscriptKey, ToPublicKey, Translator}; use crate::node::{ConstructNode, NoWitness}; use crate::FailEntropy; @@ -217,6 +217,35 @@ impl Policy { } } +impl ForEachKey for Policy { + fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool + where + Pk: 'a, + { + let mut stack = vec![self]; + + while let Some(top) = stack.pop() { + match top { + Policy::Key(key) => { + if !pred(key) { + return false; + } + } + Policy::And { left, right } | Policy::Or { left, right } => { + stack.push(right); + stack.push(left); + } + Policy::Threshold(_, sub_policies) => { + stack.extend(sub_policies.iter()); + } + _ => {} + } + } + + true + } +} + impl fmt::Debug for Policy { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { diff --git a/src/policy/descriptor.rs b/src/policy/descriptor.rs index b4762c46..b5cd33a4 100644 --- a/src/policy/descriptor.rs +++ b/src/policy/descriptor.rs @@ -1,15 +1,21 @@ -use crate::policy::satisfy::PolicySatisfier; -use crate::{Cmr, Error, Policy}; -use bitcoin_hashes::Hash; +use crate::{miniscript, Error, Policy}; +use bitcoin_hashes::{hash160, ripemd160, sha256, Hash}; use elements::schnorr::{TapTweak, XOnlyPublicKey}; -use elements::secp256k1_zkp; use elements::taproot::{ ControlBlock, LeafVersion, TapBranchHash, TapLeafHash, TaprootBuilder, TaprootMerkleBranch, TaprootSpendInfo, }; -use elements_miniscript::{MiniscriptKey, ToPublicKey}; +use elements::{bitcoin, secp256k1_zkp}; +use miniscript::descriptor::{ConversionError, DescriptorSecretKey, KeyMap}; +use miniscript::Error as MSError; +use miniscript::{ + hash256, translate_hash_clone, DefiniteDescriptorKey, DescriptorPublicKey, ForEachKey, + MiniscriptKey, Satisfier, ToPublicKey, Translator, +}; +use std::collections::HashMap; use std::fmt; use std::str::FromStr; +use std::sync::{Arc, Mutex}; pub trait UnspendableKey: MiniscriptKey { fn unspendable() -> Self; @@ -21,6 +27,15 @@ impl UnspendableKey for XOnlyPublicKey { } } +impl UnspendableKey for DescriptorPublicKey { + fn unspendable() -> Self { + Self::Single(miniscript::descriptor::SinglePub { + origin: None, + key: miniscript::descriptor::SinglePubKey::XOnly(XOnlyPublicKey::unspendable()), + }) + } +} + /// Bytes of x-only public key whose discrete logarithm (secret key) is unknown /// /// Taken from BIP 341 @@ -49,43 +64,54 @@ pub fn leaf_version() -> LeafVersion { /// /// The internal key can be a normal public key (p2pk), a MuSig aggregate public key (multisig) /// or an unspendable public key in case this feature is undesirable. -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug)] pub struct Descriptor { internal_key: Pk, - spend_info: TaprootSpendInfo, policy: Policy, - cmr: Cmr, + spend_info: Mutex>>, } -impl Descriptor { - /// Create a new descriptor from the given internal key and - /// policy which will become a single tap leaf - pub fn new(internal_key: Pk, policy: Policy) -> Result { - let commit = policy.serialize_no_witness(); - let cmr = commit.cmr(); - let script = elements::Script::from(Vec::from(cmr.as_ref())); - let version = leaf_version(); +impl Clone for Descriptor { + fn clone(&self) -> Self { + Self { + internal_key: self.internal_key.clone(), + policy: self.policy.clone(), + // New mutex so clones don't block each other + // Cloning the contained spending info is cheap + spend_info: Mutex::new( + self.spend_info + .lock() + .expect("Lock poisoned") + .as_ref() + .map(Arc::clone), + ), + } + } +} - let builder = TaprootBuilder::new() - .add_leaf_with_ver(0, script, version) - .expect("constant leaf"); - let secp = secp256k1_zkp::Secp256k1::verification_only(); - let spend_info = builder - .finalize(&secp, internal_key.to_x_only_pubkey()) - .expect("constant tree"); +impl PartialEq for Descriptor { + fn eq(&self, other: &Self) -> bool { + self.internal_key == other.internal_key && self.policy == other.policy + } +} - Ok(Self { +impl Eq for Descriptor {} + +impl Descriptor { + /// Create a new descriptor from the given internal key and + /// policy which will become a single tap leaf + pub fn new(internal_key: Pk, policy: Policy) -> Self { + Self { internal_key, - spend_info, policy, - cmr, - }) + spend_info: Mutex::new(None), + } } /// Create a new descriptor from the given policy which will become a single tap leaf /// /// The internal key is set to a constant that is provably not spendable - pub fn single_leaf(policy: Policy) -> Result + pub fn single_leaf(policy: Policy) -> Self where Pk: UnspendableKey, { @@ -98,9 +124,41 @@ impl Descriptor { &self.internal_key } + fn translate_pk(&self, translator: &mut T) -> Result, E> + where + T: Translator, + Q: MiniscriptKey, + { + let internal_key = translator.pk(self.internal_key())?; + let policy = self.policy.translate(translator)?; + Ok(Descriptor::new(internal_key, policy)) + } +} + +impl Descriptor { /// Return the spend data - pub fn spend_info(&self) -> &TaprootSpendInfo { - &self.spend_info + pub fn spend_info(&self) -> Arc { + // Return the spending info if it is already cached + // Panic if lock is poisoned (another thread with the lock panicked) + let read_lock = self.spend_info.lock().expect("Lock poisoned"); + if let Some(ref spend_info) = *read_lock { + return Arc::clone(spend_info); + } + drop(read_lock); + + let (script, version) = self.leaf(); + let builder = TaprootBuilder::new() + .add_leaf_with_ver(0, script, version) + .expect("constant leaf"); + let secp = secp256k1_zkp::Secp256k1::verification_only(); + let data = builder + .finalize(&secp, self.internal_key.to_x_only_pubkey()) + .expect("constant tree"); + + // Cache spending info + let spend_info = Arc::new(data); + *self.spend_info.lock().expect("Lock poisoned") = Some(Arc::clone(&spend_info)); + spend_info } /// Return the script pubkey @@ -119,24 +177,21 @@ impl Descriptor { elements::Address::p2tr_tweaked(output_key, None, params) } - /// Return the CMR of the program inside the single tap leaf - pub fn cmr(&self) -> Cmr { - self.cmr - } - /// Return the single tap leaf pub fn leaf(&self) -> (elements::Script, LeafVersion) { - let script = elements::Script::from(Vec::from(self.cmr.as_ref())); + let commit = self.policy.serialize_no_witness(); + let script = elements::Script::from(commit.cmr().as_ref().to_vec()); let version = leaf_version(); + (script, version) } /// Return a satisfying non-malleable witness and script sig with minimum weight /// to spend an output controlled by the given descriptor if it is possible to satisfy /// given the `satisfier` - pub fn get_satisfaction( + pub fn get_satisfaction>( &self, - satisfier: &PolicySatisfier, + satisfier: S, ) -> Result<(Vec>, elements::Script), Error> { let program = self.policy.satisfy(satisfier)?; @@ -179,23 +234,269 @@ impl Descriptor { } } +impl ForEachKey for Descriptor { + fn for_each_key<'a, F: FnMut(&'a Pk) -> bool>(&'a self, mut pred: F) -> bool + where + Pk: 'a, + { + pred(&self.internal_key) && self.policy.for_each_key(pred) + } +} + +impl Descriptor { + /// Whether or not the descriptor has any wildcards i.e. `/*`. + pub fn has_wildcard(&self) -> bool { + self.for_any_key(|key| key.has_wildcard()) + } + + /// Replaces all wildcards (i.e. `/*`) in the descriptor with a particular derivation index, + /// turning it into a *definite* descriptor. + /// + /// # Errors + /// - If index ≥ 2^31 + pub fn at_derivation_index( + &self, + index: u32, + ) -> Result, ConversionError> { + struct Derivator(u32); + + impl Translator for Derivator { + fn pk( + &mut self, + pk: &DescriptorPublicKey, + ) -> Result { + pk.clone().at_derivation_index(self.0) + } + + translate_hash_clone!(DescriptorPublicKey, DescriptorPublicKey, ConversionError); + } + + self.translate_pk(&mut Derivator(index)) + } + + /// Parse a descriptor that may contain secret keys + /// + /// Internally turns every secret key found into the corresponding public key and then returns a + /// a descriptor that only contains public keys and a map to lookup the secret key given a public key. + pub fn parse_descriptor( + secp: &secp256k1_zkp::Secp256k1, + s: &str, + ) -> Result<(Descriptor, KeyMap), MSError> { + fn parse_key( + s: &str, + key_map: &mut KeyMap, + secp: &secp256k1_zkp::Secp256k1, + ) -> Result { + let (public_key, secret_key) = match DescriptorSecretKey::from_str(s) { + Ok(sk) => ( + sk.to_public(secp) + .map_err(|e| MSError::Unexpected(e.to_string()))?, + Some(sk), + ), + Err(_) => ( + DescriptorPublicKey::from_str(s) + .map_err(|e| MSError::Unexpected(e.to_string()))?, + None, + ), + }; + + if let Some(secret_key) = secret_key { + key_map.insert(public_key.clone(), secret_key); + } + + Ok(public_key) + } + + let mut keymap_pk = KeyMapWrapper(HashMap::new(), secp); + + struct KeyMapWrapper<'a, C: secp256k1_zkp::Signing>( + KeyMap, + &'a secp256k1_zkp::Secp256k1, + ); + + impl<'a, C: secp256k1_zkp::Signing> Translator + for KeyMapWrapper<'a, C> + { + fn pk(&mut self, pk: &String) -> Result { + parse_key(pk, &mut self.0, self.1) + } + + fn sha256(&mut self, sha256: &String) -> Result { + let hash = sha256::Hash::from_str(sha256) + .map_err(|e| MSError::Unexpected(e.to_string()))?; + Ok(hash) + } + + fn hash256(&mut self, hash256: &String) -> Result { + let hash = hash256::Hash::from_str(hash256) + .map_err(|e| MSError::Unexpected(e.to_string()))?; + Ok(hash) + } + + fn ripemd160(&mut self, ripemd160: &String) -> Result { + let hash = ripemd160::Hash::from_str(ripemd160) + .map_err(|e| MSError::Unexpected(e.to_string()))?; + Ok(hash) + } + + fn hash160(&mut self, hash160: &String) -> Result { + let hash = hash160::Hash::from_str(hash160) + .map_err(|e| MSError::Unexpected(e.to_string()))?; + Ok(hash) + } + } + + let descriptor = Descriptor::::from_str(s)?; + let descriptor = descriptor + .translate_pk(&mut keymap_pk) + .map_err(|e| MSError::Unexpected(e.to_string()))?; + + Ok((descriptor, keymap_pk.0)) + } + + /// Serialize a descriptor to string with its secret keys + pub fn to_string_with_secret(&self, key_map: &KeyMap) -> String { + struct KeyMapLookUp<'a>(&'a KeyMap); + + impl<'a> Translator for KeyMapLookUp<'a> { + fn pk(&mut self, pk: &DescriptorPublicKey) -> Result { + key_to_string(pk, self.0) + } + + fn sha256(&mut self, sha256: &sha256::Hash) -> Result { + Ok(sha256.to_string()) + } + + fn hash256(&mut self, hash256: &hash256::Hash) -> Result { + Ok(hash256.to_string()) + } + + fn ripemd160(&mut self, ripemd160: &ripemd160::Hash) -> Result { + Ok(ripemd160.to_string()) + } + + fn hash160(&mut self, hash160: &hash160::Hash) -> Result { + Ok(hash160.to_string()) + } + } + + fn key_to_string(pk: &DescriptorPublicKey, key_map: &KeyMap) -> Result { + Ok(match key_map.get(pk) { + Some(secret) => secret.to_string(), + None => pk.to_string(), + }) + } + + let descriptor = self + .translate_pk(&mut KeyMapLookUp(key_map)) + .expect("Translation to string cannot fail"); + + descriptor.to_string() + } +} + +impl Descriptor { + /// Convert all the public keys in the descriptor to [`bitcoin::PublicKey`] by deriving them or + /// otherwise converting them. All [`secp256k1_zkp::XOnlyPublicKey`]s are converted to by adding a + /// default(0x02) y-coordinate. + /// + /// # Errors + /// + /// This function will return an error if hardened derivation is attempted. + pub fn derived_descriptor( + &self, + secp: &secp256k1_zkp::Secp256k1, + ) -> Result, ConversionError> { + struct Derivator<'a, C: secp256k1_zkp::Verification>(&'a secp256k1_zkp::Secp256k1); + + impl<'a, C: secp256k1_zkp::Verification> + Translator + for Derivator<'a, C> + { + fn pk( + &mut self, + pk: &DefiniteDescriptorKey, + ) -> Result { + pk.derive_public_key(self.0) + } + + translate_hash_clone!(DefiniteDescriptorKey, bitcoin::PublicKey, ConversionError); + } + + let derived = self.translate_pk(&mut Derivator(secp))?; + Ok(derived) + } +} + impl fmt::Display for Descriptor { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self.policy, f) + write!(f, "sim({},{})", self.internal_key, self.policy) } } impl FromStr for Descriptor where - Pk: UnspendableKey + ToPublicKey + FromStr, + Pk: MiniscriptKey + FromStr, Pk::Sha256: FromStr, ::Err: ToString, ::Err: ToString, { - type Err = Error; + type Err = MSError; fn from_str(s: &str) -> Result { - let policy = Policy::from_str(s)?; - Self::single_leaf(policy) + let (internal_key, policy) = s + .strip_prefix("sim(") + .and_then(|s| s.strip_suffix(')')) + .and_then(|s| { + let mut split = s.splitn(2, ','); + let x = split.next()?; + let y = split.next()?; + Some((x, y)) + }) + .ok_or(MSError::BadDescriptor("bad taproot descriptor".to_string()))?; + let internal_key = ::from_str(internal_key) + .map_err(|e| MSError::BadDescriptor(e.to_string()))?; + let policy = Policy::from_str(policy)?; + + Ok(Self::new(internal_key, policy)) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn from_string_to_string() { + let original = "sim(d6889cb081036e0faefa3a35157ad71086b123b2b144b649798b494c300a961d,pk(e0dfe2300b0dd746a3f8674dfd4525623639042569d829c7f0eed9602d263e6f))"; + let descriptor = Descriptor::::from_str(original).expect("from_str"); + let display = descriptor.to_string(); + assert_eq!(original, display); + } + + #[test] + fn derived_descriptor() { + let key = "[78412e3a/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*"; + let parent_key = DescriptorPublicKey::from_str(key).expect("constant key"); + let policy = Policy::Key(parent_key.clone()); + // Use the same xpub for internal key and for policy + // Unrealistic, but sufficient for testing + let parent_descriptor = Descriptor::new(parent_key.clone(), policy); + + for index in 0..10 { + let child_descriptor = parent_descriptor + .at_derivation_index(index) + .expect("derive descriptor"); + let child_key = parent_key + .clone() + .at_derivation_index(index) + .expect("derive key"); + + assert_eq!(child_key, child_descriptor.internal_key); + + if let Policy::Key(key) = child_descriptor.policy { + assert_eq!(child_key, key); + } + } } } diff --git a/src/policy/embed.rs b/src/policy/embed.rs index c9e701d9..3563857c 100644 --- a/src/policy/embed.rs +++ b/src/policy/embed.rs @@ -3,8 +3,7 @@ use std::str::FromStr; use std::sync::Arc; use crate::miniscript::Error as msError; -use crate::miniscript::ToPublicKey; -use crate::miniscript::{expression, Miniscript, ScriptContext, Terminal}; +use crate::miniscript::{expression, Miniscript, MiniscriptKey, ScriptContext, Terminal}; use crate::{miniscript, policy}; use crate::policy::Policy; @@ -14,7 +13,7 @@ serde_string_impl_pk!(Policy, "a Simplicity policy"); impl FromStr for Policy where - Pk: ToPublicKey + FromStr, + Pk: MiniscriptKey + FromStr, Pk::Sha256: FromStr, ::Err: ToString, ::Err: ToString, @@ -35,7 +34,7 @@ where impl expression::FromTree for Policy where - Pk: ToPublicKey + FromStr, + Pk: MiniscriptKey + FromStr, Pk::Sha256: FromStr, ::Err: ToString, ::Err: ToString, @@ -100,7 +99,7 @@ where } } -impl<'a, Pk: ToPublicKey, Ctx: ScriptContext> TryFrom<&'a Miniscript> for Policy { +impl<'a, Pk: MiniscriptKey, Ctx: ScriptContext> TryFrom<&'a Miniscript> for Policy { type Error = Error; fn try_from(top: &Miniscript) -> Result { @@ -179,6 +178,7 @@ impl<'a, Pk: ToPublicKey, Ctx: ScriptContext> TryFrom<&'a Miniscript> f mod tests { use super::*; use crate::miniscript::bitcoin::XOnlyPublicKey; + use crate::miniscript::DescriptorPublicKey; #[test] fn parse_bad_thresh() { @@ -216,4 +216,18 @@ mod tests { Err(msError::Unexpected("3".to_string())), ); } + + #[test] + fn decode_xpub() { + let s = "[78412e3a/44'/0'/0']xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL/1/*"; + let decoded_key = DescriptorPublicKey::from_str(s).expect("constant key"); + let s = format!("pk({})", s); + let decoded_policy = Policy::::from_str(&s).expect("decode policy"); + + if let Policy::Key(key) = decoded_policy { + assert_eq!(decoded_key, key); + } else { + panic!("Decoded policy should be public key") + } + } } diff --git a/src/policy/satisfy.rs b/src/policy/satisfy.rs index a46b2099..1c3e7331 100644 --- a/src/policy/satisfy.rs +++ b/src/policy/satisfy.rs @@ -1,45 +1,17 @@ +use crate::analysis::Cost; use crate::jet::Elements; use crate::node::{RedeemNode, WitnessNode}; -use crate::{Error, Policy, Value}; +use crate::{miniscript, Error, Policy, Value}; use bitcoin_hashes::Hash; use elements::locktime::Height; use elements::taproot::TapLeafHash; use elements::{LockTime, Sequence}; -use elements_miniscript::{MiniscriptKey, Preimage32, Satisfier, ToPublicKey}; +use miniscript::{Satisfier, ToPublicKey}; -use crate::analysis::Cost; -use std::collections::HashMap; use std::convert::TryFrom; use std::sync::Arc; -pub struct PolicySatisfier<'a, Pk: MiniscriptKey> { - pub preimages: HashMap, - pub signatures: HashMap, - pub tx: &'a elements::Transaction, - pub index: usize, -} - -impl<'a, Pk: ToPublicKey> Satisfier for PolicySatisfier<'a, Pk> { - fn lookup_tap_leaf_script_sig(&self, pk: &Pk, _: &TapLeafHash) -> Option { - self.signatures.get(pk).copied() - } - - fn lookup_sha256(&self, hash: &Pk::Sha256) -> Option { - self.preimages.get(hash).copied() - } - - fn check_older(&self, sequence: Sequence) -> bool { - let self_sequence = self.tx.input[self.index].sequence; - >::check_older(&self_sequence, sequence) - } - - fn check_after(&self, locktime: LockTime) -> bool { - let self_locktime = LockTime::from(self.tx.lock_time); - >::check_after(&self_locktime, locktime) - } -} - impl Policy { pub fn satisfy_internal>( &self, @@ -160,9 +132,9 @@ impl Policy { pub fn satisfy>( &self, - satisfier: &S, + satisfier: S, ) -> Result>, Error> { - let witnode = self.satisfy_internal(satisfier)?; + let witnode = self.satisfy_internal(&satisfier)?; if witnode.must_prune() { Err(Error::IncompleteFinalization) } else { @@ -178,19 +150,42 @@ mod tests { use crate::jet::elements::ElementsEnv; use crate::node::SimpleFinalizer; use crate::{BitMachine, FailEntropy}; - use bitcoin_hashes::{sha256, Hash}; - use elements::{bitcoin, secp256k1_zkp, PackedLockTime, SchnorrSigHashType}; + use bitcoin_hashes::sha256; + use elements::{bitcoin, secp256k1_zkp, PackedLockTime, SchnorrSig, SchnorrSigHashType}; + use miniscript::{MiniscriptKey, Preimage32}; + use std::collections::HashMap; use std::sync::Arc; - fn get_satisfier(env: &ElementsEnv) -> PolicySatisfier { + struct HashSatisfier(HashMap); + + impl Satisfier for HashSatisfier { + fn lookup_sha256(&self, image: &Pk::Sha256) -> Option { + self.0.get(image).copied() + } + } + + fn get_hash_satisfier() -> HashSatisfier { let mut preimages = HashMap::new(); - let mut signatures = HashMap::new(); for i in 0..3 { let preimage = [i; 32]; preimages.insert(sha256::Hash::hash(&preimage), preimage); } + HashSatisfier(preimages) + } + + struct SigSatisfier(HashMap); + + impl Satisfier for SigSatisfier { + fn lookup_tap_leaf_script_sig(&self, key: &Pk, _: &TapLeafHash) -> Option { + self.0.get(key).copied() + } + } + + fn get_sig_satisfier(env: &ElementsEnv) -> SigSatisfier { + let mut signatures = HashMap::new(); + let secp = secp256k1_zkp::Secp256k1::new(); let mut rng = secp256k1_zkp::rand::rngs::ThreadRng::default(); @@ -208,12 +203,7 @@ mod tests { signatures.insert(xonly, sig); } - PolicySatisfier { - preimages, - signatures, - tx: env.tx(), - index: 0, - } + SigSatisfier(signatures) } fn execute_successful(program: Arc>, env: &ElementsEnv) { @@ -231,7 +221,7 @@ mod tests { #[test] fn satisfy_unsatisfiable() { let env = ElementsEnv::dummy(); - let satisfier = get_satisfier(&env); + let satisfier = get_sig_satisfier(&env); let policy = Policy::Unsatisfiable(FailEntropy::ZERO); assert!(policy.satisfy(&satisfier).is_err()); @@ -250,7 +240,7 @@ mod tests { #[test] fn satisfy_trivial() { let env = ElementsEnv::dummy(); - let satisfier = get_satisfier(&env); + let satisfier = get_sig_satisfier(&env); let policy = Policy::Trivial; let program = policy.satisfy(&satisfier).expect("satisfiable"); @@ -263,9 +253,8 @@ mod tests { #[test] fn satisfy_pk() { let env = ElementsEnv::dummy(); - let satisfier = get_satisfier(&env); - let mut it = satisfier.signatures.keys(); - let xonly = it.next().unwrap(); + let satisfier = get_sig_satisfier(&env); + let xonly = satisfier.0.keys().next().expect("satisfier has keys"); let policy = Policy::Key(*xonly); let program = policy.satisfy(&satisfier).expect("satisfiable"); @@ -285,9 +274,8 @@ mod tests { #[test] fn satisfy_sha256() { let env = ElementsEnv::dummy(); - let satisfier = get_satisfier(&env); - let mut it = satisfier.preimages.keys(); - let image = *it.next().unwrap(); + let satisfier = get_hash_satisfier(); + let image = *satisfier.0.keys().next().expect("satisfier has image"); let policy = Policy::Sha256(image); let program = policy.satisfy(&satisfier).expect("satisfiable"); @@ -296,7 +284,7 @@ mod tests { let witness_bytes = witness[0].try_to_bytes().expect("to bytes"); let witness_preimage = Preimage32::try_from(witness_bytes.as_slice()).expect("to array"); - let preimage = *satisfier.preimages.get(&image).unwrap(); + let preimage = *satisfier.0.get(&image).unwrap(); assert_eq!(preimage, witness_preimage); execute_successful(program, &env); @@ -304,55 +292,54 @@ mod tests { #[test] fn satisfy_after() { - let env = ElementsEnv::dummy_with(PackedLockTime(42), Sequence::ZERO); - let satisfier = get_satisfier(&env); + let locktime = 42; + let env = ElementsEnv::dummy_with(PackedLockTime(locktime), Sequence::ZERO); + let satisfier = LockTime::Blocks(Height::from_consensus(locktime).expect("valid height")); - let policy0 = Policy::After(41); + let policy0: Policy = Policy::After(41); let program = policy0.satisfy(&satisfier).expect("satisfiable"); let witness = to_witness(&program); assert!(witness.is_empty()); execute_successful(program, &env); - let policy1 = Policy::After(42); + let policy1: Policy = Policy::After(42); let program = policy1.satisfy(&satisfier).expect("satisfiable"); let witness = to_witness(&program); assert!(witness.is_empty()); execute_successful(program, &env); - let policy2 = Policy::After(43); + let policy2: Policy = Policy::After(43); assert!(policy2.satisfy(&satisfier).is_err(), "unsatisfiable"); } #[test] fn satisfy_older() { - let env = ElementsEnv::dummy_with(PackedLockTime::ZERO, Sequence::from_consensus(42)); - let satisfier = get_satisfier(&env); + let sequence = Sequence::from_consensus(42); + let env = ElementsEnv::dummy_with(PackedLockTime::ZERO, sequence); + let satisfier = sequence; - let policy0 = Policy::Older(41); + let policy0: Policy = Policy::Older(41); let program = policy0.satisfy(&satisfier).expect("satisfiable"); let witness = to_witness(&program); assert!(witness.is_empty()); execute_successful(program, &env); - let policy1 = Policy::Older(42); + let policy1: Policy = Policy::Older(42); let program = policy1.satisfy(&satisfier).expect("satisfiable"); let witness = to_witness(&program); assert!(witness.is_empty()); execute_successful(program, &env); - let policy2 = Policy::Older(43); + let policy2: Policy = Policy::Older(43); assert!(policy2.satisfy(&satisfier).is_err(), "unsatisfiable"); } #[test] fn satisfy_and() { let env = ElementsEnv::dummy(); - let satisfier = get_satisfier(&env); - let images: Vec<_> = satisfier.preimages.keys().copied().collect(); - let preimages: Vec<_> = images - .iter() - .map(|x| satisfier.preimages.get(x).unwrap()) - .collect(); + let satisfier = get_hash_satisfier(); + let images: Vec<_> = satisfier.0.keys().copied().collect(); + let preimages: Vec<_> = images.iter().map(|x| satisfier.0.get(x).unwrap()).collect(); // Policy 0 @@ -393,12 +380,9 @@ mod tests { #[test] fn satisfy_or() { let env = ElementsEnv::dummy(); - let satisfier = get_satisfier(&env); - let images: Vec<_> = satisfier.preimages.keys().copied().collect(); - let preimages: Vec<_> = images - .iter() - .map(|x| satisfier.preimages.get(x).unwrap()) - .collect(); + let satisfier = get_hash_satisfier(); + let images: Vec<_> = satisfier.0.keys().copied().collect(); + let preimages: Vec<_> = images.iter().map(|x| satisfier.0.get(x).unwrap()).collect(); let assert_branch = |policy: &Policy, bit: bool| { let program = policy.satisfy(&satisfier).expect("satisfiable"); @@ -450,12 +434,9 @@ mod tests { #[test] fn satisfy_thresh() { let env = ElementsEnv::dummy(); - let satisfier = get_satisfier(&env); - let images: Vec<_> = satisfier.preimages.keys().copied().collect(); - let preimages: Vec<_> = images - .iter() - .map(|x| satisfier.preimages.get(x).unwrap()) - .collect(); + let satisfier = get_hash_satisfier(); + let images: Vec<_> = satisfier.0.keys().copied().collect(); + let preimages: Vec<_> = images.iter().map(|x| satisfier.0.get(x).unwrap()).collect(); let assert_branches = |policy: &Policy, bits: &[bool]| { let program = policy.satisfy(&satisfier).expect("satisfiable"); @@ -477,6 +458,8 @@ mod tests { witidx += 1; } } + + execute_successful(program, &env); }; let image_from_bit = |bit: bool, j: u8| {