Skip to content

Commit

Permalink
Refactor out type_check
Browse files Browse the repository at this point in the history
  • Loading branch information
RCasatta committed Mar 3, 2024
1 parent fe8f040 commit 9c7bb5b
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 207 deletions.
3 changes: 1 addition & 2 deletions src/miniscript/astelem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ use bitcoin::{absolute, opcodes, script, Sequence};
use sync::Arc;

use crate::miniscript::context::SigType;
use crate::miniscript::types::{self, Property};
use crate::miniscript::ScriptContext;
use crate::miniscript::{types, ScriptContext};
use crate::prelude::*;
use crate::util::MsKeyBuilder;
use crate::{
Expand Down
2 changes: 1 addition & 1 deletion src/miniscript/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use sync::Arc;
use crate::miniscript::lex::{Token as Tk, TokenIter};
use crate::miniscript::limits::MAX_PUBKEYS_PER_MULTISIG;
use crate::miniscript::types::extra_props::ExtData;
use crate::miniscript::types::{Property, Type};
use crate::miniscript::types::Type;
use crate::miniscript::ScriptContext;
use crate::prelude::*;
#[cfg(doc)]
Expand Down
1 change: 0 additions & 1 deletion src/miniscript/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ use core::cmp;
use sync::Arc;

use self::lex::{lex, TokenIter};
use self::types::Property;
pub use crate::miniscript::context::ScriptContext;
use crate::miniscript::decode::Terminal;
use crate::miniscript::types::extra_props::ExtData;
Expand Down
16 changes: 3 additions & 13 deletions src/miniscript/types/extra_props.rs
Original file line number Diff line number Diff line change
Expand Up @@ -856,22 +856,12 @@ impl Property for ExtData {
exec_stack_elem_count_dissat,
})
}
}

fn type_check_with_child<Pk, Ctx, C>(
_fragment: &Terminal<Pk, Ctx>,
mut _child: C,
) -> Result<Self, Error<Pk, Ctx>>
where
C: FnMut(usize) -> Self,
Pk: MiniscriptKey,
Ctx: ScriptContext,
{
unreachable!()
}

impl ExtData {
/// Compute the type of a fragment assuming all the children of
/// Miniscript have been computed already.
fn type_check<Pk, Ctx>(fragment: &Terminal<Pk, Ctx>) -> Result<Self, Error<Pk, Ctx>>
pub fn type_check<Pk, Ctx>(fragment: &Terminal<Pk, Ctx>) -> Result<Self, Error<Pk, Ctx>>
where
Ctx: ScriptContext,
Pk: MiniscriptKey,
Expand Down
185 changes: 3 additions & 182 deletions src/miniscript/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,175 +344,6 @@ pub trait Property: Sized {
fn threshold<S>(k: usize, n: usize, sub_ck: S) -> Result<Self, ErrorKind>
where
S: FnMut(usize) -> Result<Self, ErrorKind>;

/// Compute the type of a fragment, given a function to look up
/// the types of its children, if available and relevant for the
/// given fragment
fn type_check_common<'a, Pk, Ctx, C>(
fragment: &'a Terminal<Pk, Ctx>,
mut get_child: C,
) -> Result<Self, Error<Pk, Ctx>>
where
C: FnMut(&'a Terminal<Pk, Ctx>, usize) -> Result<Self, Error<Pk, Ctx>>,
Pk: MiniscriptKey,
Ctx: ScriptContext,
{
let wrap_err = |result: Result<Self, ErrorKind>| {
result.map_err(|kind| Error { fragment: fragment.clone(), error: kind })
};

let ret = match *fragment {
Terminal::True => Ok(Self::from_true()),
Terminal::False => Ok(Self::from_false()),
Terminal::PkK(..) => Ok(Self::from_pk_k::<Ctx>()),
Terminal::PkH(..) | Terminal::RawPkH(..) => Ok(Self::from_pk_h::<Ctx>()),
Terminal::Multi(k, ref pks) | Terminal::MultiA(k, ref pks) => {
if k == 0 {
return Err(Error {
fragment: fragment.clone(),
error: ErrorKind::ZeroThreshold,
});
}
if k > pks.len() {
return Err(Error {
fragment: fragment.clone(),
error: ErrorKind::OverThreshold(k, pks.len()),
});
}
match *fragment {
Terminal::Multi(..) => Ok(Self::from_multi(k, pks.len())),
Terminal::MultiA(..) => Ok(Self::from_multi_a(k, pks.len())),
_ => unreachable!(),
}
}
Terminal::After(t) => {
// Note that for CLTV this is a limitation not of Bitcoin but Miniscript. The
// number on the stack would be a 5 bytes signed integer but Miniscript's B type
// only consumes 4 bytes from the stack.
if t == absolute::LockTime::ZERO.into() {
return Err(Error {
fragment: fragment.clone(),
error: ErrorKind::InvalidTime,
});
}
Ok(Self::from_after(t.into()))
}
Terminal::Older(t) => {
if t == Sequence::ZERO || !t.is_relative_lock_time() {
return Err(Error {
fragment: fragment.clone(),
error: ErrorKind::InvalidTime,
});
}
Ok(Self::from_older(t))
}
Terminal::Sha256(..) => Ok(Self::from_sha256()),
Terminal::Hash256(..) => Ok(Self::from_hash256()),
Terminal::Ripemd160(..) => Ok(Self::from_ripemd160()),
Terminal::Hash160(..) => Ok(Self::from_hash160()),
Terminal::Alt(ref sub) => wrap_err(Self::cast_alt(get_child(&sub.node, 0)?)),
Terminal::Swap(ref sub) => wrap_err(Self::cast_swap(get_child(&sub.node, 0)?)),
Terminal::Check(ref sub) => wrap_err(Self::cast_check(get_child(&sub.node, 0)?)),
Terminal::DupIf(ref sub) => wrap_err(Self::cast_dupif(get_child(&sub.node, 0)?)),
Terminal::Verify(ref sub) => wrap_err(Self::cast_verify(get_child(&sub.node, 0)?)),
Terminal::NonZero(ref sub) => wrap_err(Self::cast_nonzero(get_child(&sub.node, 0)?)),
Terminal::ZeroNotEqual(ref sub) => {
wrap_err(Self::cast_zeronotequal(get_child(&sub.node, 0)?))
}
Terminal::AndB(ref l, ref r) => {
let ltype = get_child(&l.node, 0)?;
let rtype = get_child(&r.node, 1)?;
wrap_err(Self::and_b(ltype, rtype))
}
Terminal::AndV(ref l, ref r) => {
let ltype = get_child(&l.node, 0)?;
let rtype = get_child(&r.node, 1)?;
wrap_err(Self::and_v(ltype, rtype))
}
Terminal::OrB(ref l, ref r) => {
let ltype = get_child(&l.node, 0)?;
let rtype = get_child(&r.node, 1)?;
wrap_err(Self::or_b(ltype, rtype))
}
Terminal::OrD(ref l, ref r) => {
let ltype = get_child(&l.node, 0)?;
let rtype = get_child(&r.node, 1)?;
wrap_err(Self::or_d(ltype, rtype))
}
Terminal::OrC(ref l, ref r) => {
let ltype = get_child(&l.node, 0)?;
let rtype = get_child(&r.node, 1)?;
wrap_err(Self::or_c(ltype, rtype))
}
Terminal::OrI(ref l, ref r) => {
let ltype = get_child(&l.node, 0)?;
let rtype = get_child(&r.node, 1)?;
wrap_err(Self::or_i(ltype, rtype))
}
Terminal::AndOr(ref a, ref b, ref c) => {
let atype = get_child(&a.node, 0)?;
let btype = get_child(&b.node, 1)?;
let ctype = get_child(&c.node, 2)?;
wrap_err(Self::and_or(atype, btype, ctype))
}
Terminal::Thresh(k, ref subs) => {
if k == 0 {
return Err(Error {
fragment: fragment.clone(),
error: ErrorKind::ZeroThreshold,
});
}
if k > subs.len() {
return Err(Error {
fragment: fragment.clone(),
error: ErrorKind::OverThreshold(k, subs.len()),
});
}

let mut last_err_frag = None;
let res = Self::threshold(k, subs.len(), |n| match get_child(&subs[n].node, n) {
Ok(x) => Ok(x),
Err(e) => {
last_err_frag = Some(e.fragment);
Err(e.error)
}
});

res.map_err(|kind| Error {
fragment: last_err_frag.unwrap_or_else(|| fragment.clone()),
error: kind,
})
}
};
if let Ok(ref ret) = ret {
ret.sanity_checks()
}
ret
}

/// Compute the type of a fragment, given a function to look up
/// the types of its children.
fn type_check_with_child<Pk, Ctx, C>(
fragment: &Terminal<Pk, Ctx>,
mut child: C,
) -> Result<Self, Error<Pk, Ctx>>
where
C: FnMut(usize) -> Self,
Pk: MiniscriptKey,
Ctx: ScriptContext,
{
let get_child = |_sub, n| Ok(child(n));
Self::type_check_common(fragment, get_child)
}

/// Compute the type of a fragment.
fn type_check<Pk, Ctx>(fragment: &Terminal<Pk, Ctx>) -> Result<Self, Error<Pk, Ctx>>
where
Pk: MiniscriptKey,
Ctx: ScriptContext,
{
Self::type_check_common(fragment, |sub, _n| Self::type_check(sub))
}
}

impl Property for Type {
Expand Down Expand Up @@ -693,22 +524,12 @@ impl Property for Type {
mall: Property::threshold(k, n, |n| Ok(sub_ck(n)?.mall))?,
})
}
}

fn type_check_with_child<Pk, Ctx, C>(
_fragment: &Terminal<Pk, Ctx>,
mut _child: C,
) -> Result<Self, Error<Pk, Ctx>>
where
C: FnMut(usize) -> Self,
Pk: MiniscriptKey,
Ctx: ScriptContext,
{
unreachable!()
}

impl Type {
/// Compute the type of a fragment assuming all the children of
/// Miniscript have been computed already.
fn type_check<Pk, Ctx>(fragment: &Terminal<Pk, Ctx>) -> Result<Self, Error<Pk, Ctx>>
pub fn type_check<Pk, Ctx>(fragment: &Terminal<Pk, Ctx>) -> Result<Self, Error<Pk, Ctx>>
where
Pk: MiniscriptKey,
Ctx: ScriptContext,
Expand Down
Loading

0 comments on commit 9c7bb5b

Please sign in to comment.