Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/descriptor/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ impl DescriptorXKey<bip32::ExtendedPrivKey> {
Some((fingerprint, path)) => Some((
*fingerprint,
path.into_iter()
.chain(hardened_path.into_iter())
.chain(hardened_path.iter())
.cloned()
.collect(),
)),
Expand Down Expand Up @@ -456,7 +456,7 @@ impl DescriptorPublicKey {
DescriptorPublicKey::XPub(DescriptorXKey {
origin: xpub.origin,
xkey: xpub.xkey,
derivation_path: derivation_path,
derivation_path,
wildcard: Wildcard::None,
})
}
Expand Down
1 change: 1 addition & 0 deletions src/expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ impl<'a> Tree<'a> {
}

/// Parses a tree from a string
#[allow(clippy::should_implement_trait)] // Cannot use std::str::FromStr because of lifetimes.
pub fn from_str(s: &'a str) -> Result<Tree<'a>, Error> {
// Filter out non-ASCII because we byte-index strings all over the
// place and Rust gets very upset when you splinch a string.
Expand Down
24 changes: 12 additions & 12 deletions src/interpreter/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,9 +228,9 @@ impl<'txin> Stack<'txin> {
/// The reason we don't need to copy the Script semantics is that
/// Miniscript never evaluates integers and it is safe to treat them as
/// booleans
pub(super) fn evaluate_after<'intp>(
pub(super) fn evaluate_after(
&mut self,
n: &'intp u32,
n: &u32,
age: u32,
) -> Option<Result<SatisfiedConstraint, Error>> {
if age >= *n {
Expand All @@ -247,9 +247,9 @@ impl<'txin> Stack<'txin> {
/// The reason we don't need to copy the Script semantics is that
/// Miniscript never evaluates integers and it is safe to treat them as
/// booleans
pub(super) fn evaluate_older<'intp>(
pub(super) fn evaluate_older(
&mut self,
n: &'intp u32,
n: &u32,
height: u32,
) -> Option<Result<SatisfiedConstraint, Error>> {
if height >= *n {
Expand All @@ -262,9 +262,9 @@ impl<'txin> Stack<'txin> {

/// Helper function to evaluate a Sha256 Node.
/// `SIZE 32 EQUALVERIFY SHA256 h EQUAL`
pub(super) fn evaluate_sha256<'intp>(
pub(super) fn evaluate_sha256(
&mut self,
hash: &'intp sha256::Hash,
hash: &sha256::Hash,
) -> Option<Result<SatisfiedConstraint, Error>> {
if let Some(Element::Push(preimage)) = self.pop() {
if preimage.len() != 32 {
Expand All @@ -287,9 +287,9 @@ impl<'txin> Stack<'txin> {

/// Helper function to evaluate a Hash256 Node.
/// `SIZE 32 EQUALVERIFY HASH256 h EQUAL`
pub(super) fn evaluate_hash256<'intp>(
pub(super) fn evaluate_hash256(
&mut self,
hash: &'intp sha256d::Hash,
hash: &sha256d::Hash,
) -> Option<Result<SatisfiedConstraint, Error>> {
if let Some(Element::Push(preimage)) = self.pop() {
if preimage.len() != 32 {
Expand All @@ -312,9 +312,9 @@ impl<'txin> Stack<'txin> {

/// Helper function to evaluate a Hash160 Node.
/// `SIZE 32 EQUALVERIFY HASH160 h EQUAL`
pub(super) fn evaluate_hash160<'intp>(
pub(super) fn evaluate_hash160(
&mut self,
hash: &'intp hash160::Hash,
hash: &hash160::Hash,
) -> Option<Result<SatisfiedConstraint, Error>> {
if let Some(Element::Push(preimage)) = self.pop() {
if preimage.len() != 32 {
Expand All @@ -337,9 +337,9 @@ impl<'txin> Stack<'txin> {

/// Helper function to evaluate a RipeMd160 Node.
/// `SIZE 32 EQUALVERIFY RIPEMD160 h EQUAL`
pub(super) fn evaluate_ripemd160<'intp>(
pub(super) fn evaluate_ripemd160(
&mut self,
hash: &'intp ripemd160::Hash,
hash: &ripemd160::Hash,
) -> Option<Result<SatisfiedConstraint, Error>> {
if let Some(Element::Push(preimage)) = self.pop() {
if preimage.len() != 32 {
Expand Down
41 changes: 18 additions & 23 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,36 +54,31 @@
//!
//! ```rust
//! use std::str::FromStr;
//! use miniscript::{DescriptorTrait};
//! use miniscript::DescriptorTrait;
//!
//! fn main() {
//! let desc = miniscript::Descriptor::<
//! bitcoin::PublicKey,
//! >::from_str("\
//! sh(wsh(or_d(\
//! c:pk_k(020e0338c96a8870479f2396c373cc7696ba124e8635d41b0ea581112b67817261),\
//! c:pk_k(0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352)\
//! )))\
//! let desc = miniscript::Descriptor::<bitcoin::PublicKey>::from_str("\
//! sh(wsh(or_d(\
//! c:pk_k(020e0338c96a8870479f2396c373cc7696ba124e8635d41b0ea581112b67817261),\
//! c:pk_k(0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352)\
//! )))\
//! ").unwrap();
//!
//! // Derive the P2SH address
//! assert_eq!(
//! desc.address(bitcoin::Network::Bitcoin).unwrap().to_string(),
//! "3CJxbQBfWAe1ZkKiGQNEYrioV73ZwvBWns"
//! );
//! // Derive the P2SH address
//! assert_eq!(
//! desc.address(bitcoin::Network::Bitcoin).unwrap().to_string(),
//! "3CJxbQBfWAe1ZkKiGQNEYrioV73ZwvBWns"
//! );
//!
//! // Check whether the descriptor is safe
//! // This checks whether all spend paths are accessible in bitcoin network.
//! // It maybe possible that some of the spend require more than 100 elements in Wsh scripts
//! // Or they contain a combination of timelock and heightlock.
//! assert!(desc.sanity_check().is_ok());
//! // Check whether the descriptor is safe. This checks whether all spend paths are accessible in
//! // the Bitcoin network. It may be possible that some of the spend paths require more than 100
//! // elements in Wsh scripts or they contain a combination of timelock and heightlock.
//! assert!(desc.sanity_check().is_ok());
//!
//! // Estimate the satisfaction cost
//! assert_eq!(desc.max_satisfaction_weight().unwrap(), 293);
//! }
//! // Estimate the satisfaction cost
//! assert_eq!(desc.max_satisfaction_weight().unwrap(), 293);
//! ```
//!
//!

#![cfg_attr(all(test, feature = "unstable"), feature(test))]
// Coding conventions
#![deny(unsafe_code)]
Expand Down
2 changes: 1 addition & 1 deletion src/miniscript/astelem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Terminal<Pk, Ctx> {
Arc::new(right.real_translate_pk(fpk, fpkh)?),
),
Terminal::OrI(ref left, ref right) => Terminal::OrI(
Arc::new(left.real_translate_pk(&mut *&mut *fpk, &mut *&mut *fpkh)?),
Arc::new(left.real_translate_pk(&mut *fpk, &mut *fpkh)?),
Arc::new(right.real_translate_pk(fpk, fpkh)?),
),
Terminal::Thresh(k, ref subs) => {
Expand Down
38 changes: 19 additions & 19 deletions src/miniscript/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,37 +166,37 @@ impl<Ctx: ScriptContext> Miniscript<Ctx::Key, Ctx> {
}

/// Attempt to parse a Script into Miniscript representation.
/// This function will fail parsing for scripts that do not clear
/// the [Miniscript::sanity_check] checks. Use [Miniscript::parse_insane] to
///
/// This function will fail parsing for scripts that do not clear the
/// [`Miniscript::sanity_check`] checks. Use [`Miniscript::parse_insane`] to
/// parse such scripts.
///
/// ## Decode/Parse a miniscript from script hex
///
/// ```rust
/// use miniscript::Miniscript;
/// use miniscript::{Segwitv0, Tap};
/// use miniscript::{Miniscript, Segwitv0, Tap};
/// use miniscript::bitcoin::secp256k1::XOnlyPublicKey;
/// use miniscript::bitcoin::hashes::hex::FromHex;
///
/// type Segwitv0Script = Miniscript<bitcoin::PublicKey, Segwitv0>;
/// type TapScript = Miniscript<XOnlyPublicKey, Tap>;
/// use bitcoin::hashes::hex::FromHex;
/// fn main() {
/// // parse x-only miniscript in Taproot context
/// let tapscript_ms = TapScript::parse(&bitcoin::Script::from(Vec::<u8>::from_hex(
/// "202788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99ac",
/// ).expect("Even length hex")))
///
/// // parse x-only miniscript in Taproot context
/// let tapscript_ms = TapScript::parse(&bitcoin::Script::from(Vec::<u8>::from_hex(
/// "202788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99ac",
/// ).expect("Even length hex")))
/// .expect("Xonly keys are valid only in taproot context");
/// // tapscript fails decoding when we use them with compressed keys
/// let err = TapScript::parse(&bitcoin::Script::from(Vec::<u8>::from_hex(
/// "21022788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99ac",
/// ).expect("Even length hex")))
/// // tapscript fails decoding when we use them with compressed keys
/// let err = TapScript::parse(&bitcoin::Script::from(Vec::<u8>::from_hex(
/// "21022788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99ac",
/// ).expect("Even length hex")))
/// .expect_err("Compressed keys cannot be used in Taproot context");
/// // Segwitv0 succeeds decoding with full keys.
/// Segwitv0Script::parse(&bitcoin::Script::from(Vec::<u8>::from_hex(
/// "21022788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99ac",
/// ).expect("Even length hex")))
/// // Segwitv0 succeeds decoding with full keys.
/// Segwitv0Script::parse(&bitcoin::Script::from(Vec::<u8>::from_hex(
/// "21022788ee41e76f4f3af603da5bc8fa22997bc0344bb0f95666ba6aaff0242baa99ac",
/// ).expect("Even length hex")))
/// .expect("Compressed keys are allowed in Segwit context");
///
/// }
/// ```
pub fn parse(script: &script::Script) -> Result<Miniscript<Ctx::Key, Ctx>, Error> {
let ms = Self::parse_insane(script)?;
Expand Down
4 changes: 2 additions & 2 deletions src/miniscript/types/extra_props.rs
Original file line number Diff line number Diff line change
Expand Up @@ -761,9 +761,9 @@ impl Property for ExtData {
S: FnMut(usize) -> Result<Self, ErrorKind>,
{
let mut pk_cost = 1 + script_num_size(k); //Equal and k
let mut ops_count = 0 as usize;
let mut ops_count = 0;
let mut ops_count_sat_vec = Vec::with_capacity(n);
let mut ops_count_nsat_sum = 0 as usize;
let mut ops_count_nsat_sum = 0;
let mut op_count_sat = Some(0);
let mut timelocks = Vec::with_capacity(n);
let mut stack_elem_count_sat_vec = Vec::with_capacity(n);
Expand Down
54 changes: 24 additions & 30 deletions src/policy/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ impl CompilationKey {
CompilationKey {
ty,
expensive_verify,
dissat_prob: dissat_prob.and_then(|x| Some(OrdF64(x))),
dissat_prob: dissat_prob.map(OrdF64),
}
}
}
Expand Down Expand Up @@ -353,6 +353,7 @@ impl Property for CompilerExtData {
})
}

#[allow(clippy::manual_map)] // Complex if/let is better as is.
fn or_i(l: Self, r: Self) -> Result<Self, types::ErrorKind> {
let lprob = l
.branch_prob
Expand Down Expand Up @@ -394,11 +395,7 @@ impl Property for CompilerExtData {
Ok(CompilerExtData {
branch_prob: None,
sat_cost: aprob * (a.sat_cost + b.sat_cost) + cprob * (adis + c.sat_cost),
dissat_cost: if let Some(cdis) = c.dissat_cost {
Some(adis + cdis)
} else {
None
},
dissat_cost: c.dissat_cost.map(|cdis| adis + cdis),
})
}

Expand Down Expand Up @@ -508,8 +505,8 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> AstElemExt<Pk, Ctx> {
let comp_ext_data = CompilerExtData::type_check(&ast, lookup_ext)?;
Ok(AstElemExt {
ms: Arc::new(Miniscript {
ty: ty,
ext: ext,
ty,
ext,
node: ast,
phantom: PhantomData,
}),
Expand Down Expand Up @@ -647,7 +644,7 @@ fn insert_elem<Pk: MiniscriptKey, Ctx: ScriptContext>(
return false;
}

if let Err(_) = Ctx::check_local_validity(&elem.ms) {
if Ctx::check_local_validity(&elem.ms).is_err() {
return false;
}

Expand All @@ -664,11 +661,11 @@ fn insert_elem<Pk: MiniscriptKey, Ctx: ScriptContext>(
let existing_elem_cost = existing_elem.cost_1d(sat_prob, dissat_prob);
existing_key.is_subtype(elem_key) && existing_elem_cost <= elem_cost
})
.fold(false, |acc, x| acc || x);
.any(|x| x);
if !is_worse {
// If the element is not worse any element in the map, remove elements
// whose subtype is the current element and have worse cost.
*map = mem::replace(map, BTreeMap::new())
*map = mem::take(map)
.into_iter()
.filter(|&(ref existing_key, ref existing_elem)| {
let existing_elem_cost = existing_elem.cost_1d(sat_prob, dissat_prob);
Expand Down Expand Up @@ -703,8 +700,8 @@ fn insert_elem_closure<Pk: MiniscriptKey, Ctx: ScriptContext>(
while !cast_stack.is_empty() {
let current = cast_stack.pop_front().unwrap();

for i in 0..casts.len() {
if let Ok(new_ext) = casts[i].cast(&current) {
for c in &casts {
if let Ok(new_ext) = c.cast(&current) {
if insert_elem(map, new_ext.clone(), sat_prob, dissat_prob) {
cast_stack.push_back(new_ext);
}
Expand Down Expand Up @@ -735,9 +732,9 @@ fn insert_best_wrapped<Pk: MiniscriptKey, Ctx: ScriptContext>(
if dissat_prob.is_some() {
let casts: [Cast<Pk, Ctx>; 10] = all_casts::<Pk, Ctx>();

for i in 0..casts.len() {
for c in &casts {
for x in best_compilations(policy_cache, policy, sat_prob, None)?.values() {
if let Ok(new_ext) = casts[i].cast(x) {
if let Ok(new_ext) = c.cast(x) {
insert_elem_closure(map, new_ext, sat_prob, dissat_prob);
}
}
Expand All @@ -760,7 +757,7 @@ where
{
//Check the cache for hits
let ord_sat_prob = OrdF64(sat_prob);
let ord_dissat_prob = dissat_prob.and_then(|x| Some(OrdF64(x)));
let ord_dissat_prob = dissat_prob.map(OrdF64);
if let Some(ret) = policy_cache.get(&(policy.clone(), ord_sat_prob, ord_dissat_prob)) {
return Ok(ret.clone());
}
Expand Down Expand Up @@ -812,9 +809,7 @@ where
insert_wrap!(AstElemExt::terminal(Terminal::True));
}
Concrete::Key(ref pk) => {
insert_wrap!(AstElemExt::terminal(Terminal::PkH(
pk.to_pubkeyhash().clone()
)));
insert_wrap!(AstElemExt::terminal(Terminal::PkH(pk.to_pubkeyhash())));
insert_wrap!(AstElemExt::terminal(Terminal::PkK(pk.clone())));
}
Concrete::After(n) => insert_wrap!(AstElemExt::terminal(Terminal::After(n))),
Expand Down Expand Up @@ -900,12 +895,12 @@ where
};

let dissat_probs = |w: f64| -> Vec<Option<f64>> {
let mut dissat_set = Vec::new();
dissat_set.push(Some(dissat_prob.unwrap_or(0 as f64) + w * sat_prob));
dissat_set.push(Some(w * sat_prob));
dissat_set.push(dissat_prob);
dissat_set.push(None);
dissat_set
vec![
Some(dissat_prob.unwrap_or(0 as f64) + w * sat_prob),
Some(w * sat_prob),
dissat_prob,
None,
]
};

let mut l_comp = vec![];
Expand Down Expand Up @@ -945,7 +940,7 @@ where
let mut best_es = Vec::with_capacity(n);
let mut best_ws = Vec::with_capacity(n);

let mut min_value = (0 as usize, f64::INFINITY as f64);
let mut min_value = (0, f64::INFINITY as f64);
for (i, ast) in subs.iter().enumerate() {
let sp = sat_prob * k_over_n;
//Expressions must be dissatisfiable
Expand Down Expand Up @@ -1013,7 +1008,7 @@ where
for k in ret.keys() {
debug_assert_eq!(k.dissat_prob, ord_dissat_prob);
}
if ret.len() == 0 {
if ret.is_empty() {
// The only reason we are discarding elements out of compiler is because
// compilations exceeded consensus and standardness limits or are non-malleable.
// If there no possible compilations for any policies regardless of dissat
Expand Down Expand Up @@ -1123,8 +1118,7 @@ where
best_compilations(policy_cache, policy, sat_prob, dissat_prob)?
.into_iter()
.filter(|&(key, _)| {
key.ty.corr.base == types::Base::B
&& key.dissat_prob == dissat_prob.and_then(|x| Some(OrdF64(x)))
key.ty.corr.base == types::Base::B && key.dissat_prob == dissat_prob.map(OrdF64)
})
.map(|(_, val)| val)
.min_by_key(|ext| OrdF64(ext.cost_1d(sat_prob, dissat_prob)))
Expand All @@ -1149,7 +1143,7 @@ where
key.ty.corr.base == basic_type
&& key.ty.corr.unit
&& val.ms.ty.mall.dissat == types::Dissat::Unique
&& key.dissat_prob == dissat_prob.and_then(|x| Some(OrdF64(x)))
&& key.dissat_prob == dissat_prob.map(OrdF64)
})
.map(|(_, val)| val)
.min_by_key(|ext| OrdF64(ext.cost_1d(sat_prob, dissat_prob)))
Expand Down