Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor out type_check #649

Merged
merged 2 commits into from
Mar 4, 2024
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
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>
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>
pub fn type_check<Pk, Ctx>(fragment: &Terminal<Pk, Ctx>) -> Result<Self, Error>
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 @@ -346,175 +346,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>
where
C: FnMut(&'a Terminal<Pk, Ctx>, usize) -> Result<Self, Error>,
Pk: MiniscriptKey,
Ctx: ScriptContext,
{
let wrap_err = |result: Result<Self, ErrorKind>| {
result.map_err(|kind| Error { fragment_string: fragment.to_string(), 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_string: fragment.to_string(),
error: ErrorKind::ZeroThreshold,
});
}
if k > pks.len() {
return Err(Error {
fragment_string: fragment.to_string(),
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_string: fragment.to_string(),
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_string: fragment.to_string(),
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_string: fragment.to_string(),
error: ErrorKind::ZeroThreshold,
});
}
if k > subs.len() {
return Err(Error {
fragment_string: fragment.to_string(),
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_string);
Err(e.error)
}
});

res.map_err(|kind| Error {
fragment_string: last_err_frag.unwrap_or_else(|| fragment.to_string()),
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>
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>
where
Pk: MiniscriptKey,
Ctx: ScriptContext,
{
Self::type_check_common(fragment, |sub, _n| Self::type_check(sub))
}
}

impl Property for Type {
Expand Down Expand Up @@ -695,22 +526,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>
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>
pub fn type_check<Pk, Ctx>(fragment: &Terminal<Pk, Ctx>) -> Result<Self, Error>
where
Pk: MiniscriptKey,
Ctx: ScriptContext,
Expand Down
Loading
Loading