Skip to content

Commit 4c4597e

Browse files
committed
Merge #649: Refactor out type_check
5f41cb6 change FnMut -> Fn (Riccardo Casatta) cdcd53e Refactor out type_check (Riccardo Casatta) Pull request description: This apply the same logic of ElementsProject/elements-miniscript#74 removing a couple of unreachable, simplify things and very likely reduce binary bloat. ~~However, in doing so, I don't think this MR is equivalent to master for the logic used for `get_child`.~~ ~~I suspect current master is broken and this fix it (or viceversa?), but I have to suspend this work for now.~~ ACKs for top commit: apoelstra: ACK 5f41cb6 this is great, thanks! Tree-SHA512: 4b904fde55ba75895d377babde5e7a3a215cdf3b0ccff0c90572bb286de9d8a80234fc6a4921ad83bcb8c947affa1e3c23b2135534cb4363f38f1bab89368ba4
2 parents 551932e + 5f41cb6 commit 4c4597e

File tree

6 files changed

+183
-200
lines changed

6 files changed

+183
-200
lines changed

src/miniscript/astelem.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ use bitcoin::{absolute, opcodes, script, Sequence};
1515
use sync::Arc;
1616

1717
use crate::miniscript::context::SigType;
18-
use crate::miniscript::types::{self, Property};
19-
use crate::miniscript::ScriptContext;
18+
use crate::miniscript::{types, ScriptContext};
2019
use crate::prelude::*;
2120
use crate::util::MsKeyBuilder;
2221
use crate::{

src/miniscript/decode.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use sync::Arc;
1717
use crate::miniscript::lex::{Token as Tk, TokenIter};
1818
use crate::miniscript::limits::MAX_PUBKEYS_PER_MULTISIG;
1919
use crate::miniscript::types::extra_props::ExtData;
20-
use crate::miniscript::types::{Property, Type};
20+
use crate::miniscript::types::Type;
2121
use crate::miniscript::ScriptContext;
2222
use crate::prelude::*;
2323
#[cfg(doc)]

src/miniscript/mod.rs

-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ use core::cmp;
4040
use sync::Arc;
4141

4242
use self::lex::{lex, TokenIter};
43-
use self::types::Property;
4443
pub use crate::miniscript::context::ScriptContext;
4544
use crate::miniscript::decode::Terminal;
4645
use crate::miniscript::types::extra_props::ExtData;

src/miniscript/types/extra_props.rs

+3-13
Original file line numberDiff line numberDiff line change
@@ -856,22 +856,12 @@ impl Property for ExtData {
856856
exec_stack_elem_count_dissat,
857857
})
858858
}
859+
}
859860

860-
fn type_check_with_child<Pk, Ctx, C>(
861-
_fragment: &Terminal<Pk, Ctx>,
862-
mut _child: C,
863-
) -> Result<Self, Error>
864-
where
865-
C: FnMut(usize) -> Self,
866-
Pk: MiniscriptKey,
867-
Ctx: ScriptContext,
868-
{
869-
unreachable!()
870-
}
871-
861+
impl ExtData {
872862
/// Compute the type of a fragment assuming all the children of
873863
/// Miniscript have been computed already.
874-
fn type_check<Pk, Ctx>(fragment: &Terminal<Pk, Ctx>) -> Result<Self, Error>
864+
pub fn type_check<Pk, Ctx>(fragment: &Terminal<Pk, Ctx>) -> Result<Self, Error>
875865
where
876866
Ctx: ScriptContext,
877867
Pk: MiniscriptKey,

src/miniscript/types/mod.rs

+3-182
Original file line numberDiff line numberDiff line change
@@ -346,175 +346,6 @@ pub trait Property: Sized {
346346
fn threshold<S>(k: usize, n: usize, sub_ck: S) -> Result<Self, ErrorKind>
347347
where
348348
S: FnMut(usize) -> Result<Self, ErrorKind>;
349-
350-
/// Compute the type of a fragment, given a function to look up
351-
/// the types of its children, if available and relevant for the
352-
/// given fragment
353-
fn type_check_common<'a, Pk, Ctx, C>(
354-
fragment: &'a Terminal<Pk, Ctx>,
355-
mut get_child: C,
356-
) -> Result<Self, Error>
357-
where
358-
C: FnMut(&'a Terminal<Pk, Ctx>, usize) -> Result<Self, Error>,
359-
Pk: MiniscriptKey,
360-
Ctx: ScriptContext,
361-
{
362-
let wrap_err = |result: Result<Self, ErrorKind>| {
363-
result.map_err(|kind| Error { fragment_string: fragment.to_string(), error: kind })
364-
};
365-
366-
let ret = match *fragment {
367-
Terminal::True => Ok(Self::from_true()),
368-
Terminal::False => Ok(Self::from_false()),
369-
Terminal::PkK(..) => Ok(Self::from_pk_k::<Ctx>()),
370-
Terminal::PkH(..) | Terminal::RawPkH(..) => Ok(Self::from_pk_h::<Ctx>()),
371-
Terminal::Multi(k, ref pks) | Terminal::MultiA(k, ref pks) => {
372-
if k == 0 {
373-
return Err(Error {
374-
fragment_string: fragment.to_string(),
375-
error: ErrorKind::ZeroThreshold,
376-
});
377-
}
378-
if k > pks.len() {
379-
return Err(Error {
380-
fragment_string: fragment.to_string(),
381-
error: ErrorKind::OverThreshold(k, pks.len()),
382-
});
383-
}
384-
match *fragment {
385-
Terminal::Multi(..) => Ok(Self::from_multi(k, pks.len())),
386-
Terminal::MultiA(..) => Ok(Self::from_multi_a(k, pks.len())),
387-
_ => unreachable!(),
388-
}
389-
}
390-
Terminal::After(t) => {
391-
// Note that for CLTV this is a limitation not of Bitcoin but Miniscript. The
392-
// number on the stack would be a 5 bytes signed integer but Miniscript's B type
393-
// only consumes 4 bytes from the stack.
394-
if t == absolute::LockTime::ZERO.into() {
395-
return Err(Error {
396-
fragment_string: fragment.to_string(),
397-
error: ErrorKind::InvalidTime,
398-
});
399-
}
400-
Ok(Self::from_after(t.into()))
401-
}
402-
Terminal::Older(t) => {
403-
if t == Sequence::ZERO || !t.is_relative_lock_time() {
404-
return Err(Error {
405-
fragment_string: fragment.to_string(),
406-
error: ErrorKind::InvalidTime,
407-
});
408-
}
409-
Ok(Self::from_older(t))
410-
}
411-
Terminal::Sha256(..) => Ok(Self::from_sha256()),
412-
Terminal::Hash256(..) => Ok(Self::from_hash256()),
413-
Terminal::Ripemd160(..) => Ok(Self::from_ripemd160()),
414-
Terminal::Hash160(..) => Ok(Self::from_hash160()),
415-
Terminal::Alt(ref sub) => wrap_err(Self::cast_alt(get_child(&sub.node, 0)?)),
416-
Terminal::Swap(ref sub) => wrap_err(Self::cast_swap(get_child(&sub.node, 0)?)),
417-
Terminal::Check(ref sub) => wrap_err(Self::cast_check(get_child(&sub.node, 0)?)),
418-
Terminal::DupIf(ref sub) => wrap_err(Self::cast_dupif(get_child(&sub.node, 0)?)),
419-
Terminal::Verify(ref sub) => wrap_err(Self::cast_verify(get_child(&sub.node, 0)?)),
420-
Terminal::NonZero(ref sub) => wrap_err(Self::cast_nonzero(get_child(&sub.node, 0)?)),
421-
Terminal::ZeroNotEqual(ref sub) => {
422-
wrap_err(Self::cast_zeronotequal(get_child(&sub.node, 0)?))
423-
}
424-
Terminal::AndB(ref l, ref r) => {
425-
let ltype = get_child(&l.node, 0)?;
426-
let rtype = get_child(&r.node, 1)?;
427-
wrap_err(Self::and_b(ltype, rtype))
428-
}
429-
Terminal::AndV(ref l, ref r) => {
430-
let ltype = get_child(&l.node, 0)?;
431-
let rtype = get_child(&r.node, 1)?;
432-
wrap_err(Self::and_v(ltype, rtype))
433-
}
434-
Terminal::OrB(ref l, ref r) => {
435-
let ltype = get_child(&l.node, 0)?;
436-
let rtype = get_child(&r.node, 1)?;
437-
wrap_err(Self::or_b(ltype, rtype))
438-
}
439-
Terminal::OrD(ref l, ref r) => {
440-
let ltype = get_child(&l.node, 0)?;
441-
let rtype = get_child(&r.node, 1)?;
442-
wrap_err(Self::or_d(ltype, rtype))
443-
}
444-
Terminal::OrC(ref l, ref r) => {
445-
let ltype = get_child(&l.node, 0)?;
446-
let rtype = get_child(&r.node, 1)?;
447-
wrap_err(Self::or_c(ltype, rtype))
448-
}
449-
Terminal::OrI(ref l, ref r) => {
450-
let ltype = get_child(&l.node, 0)?;
451-
let rtype = get_child(&r.node, 1)?;
452-
wrap_err(Self::or_i(ltype, rtype))
453-
}
454-
Terminal::AndOr(ref a, ref b, ref c) => {
455-
let atype = get_child(&a.node, 0)?;
456-
let btype = get_child(&b.node, 1)?;
457-
let ctype = get_child(&c.node, 2)?;
458-
wrap_err(Self::and_or(atype, btype, ctype))
459-
}
460-
Terminal::Thresh(k, ref subs) => {
461-
if k == 0 {
462-
return Err(Error {
463-
fragment_string: fragment.to_string(),
464-
error: ErrorKind::ZeroThreshold,
465-
});
466-
}
467-
if k > subs.len() {
468-
return Err(Error {
469-
fragment_string: fragment.to_string(),
470-
error: ErrorKind::OverThreshold(k, subs.len()),
471-
});
472-
}
473-
474-
let mut last_err_frag = None;
475-
let res = Self::threshold(k, subs.len(), |n| match get_child(&subs[n].node, n) {
476-
Ok(x) => Ok(x),
477-
Err(e) => {
478-
last_err_frag = Some(e.fragment_string);
479-
Err(e.error)
480-
}
481-
});
482-
483-
res.map_err(|kind| Error {
484-
fragment_string: last_err_frag.unwrap_or_else(|| fragment.to_string()),
485-
error: kind,
486-
})
487-
}
488-
};
489-
if let Ok(ref ret) = ret {
490-
ret.sanity_checks()
491-
}
492-
ret
493-
}
494-
495-
/// Compute the type of a fragment, given a function to look up
496-
/// the types of its children.
497-
fn type_check_with_child<Pk, Ctx, C>(
498-
fragment: &Terminal<Pk, Ctx>,
499-
mut child: C,
500-
) -> Result<Self, Error>
501-
where
502-
C: FnMut(usize) -> Self,
503-
Pk: MiniscriptKey,
504-
Ctx: ScriptContext,
505-
{
506-
let get_child = |_sub, n| Ok(child(n));
507-
Self::type_check_common(fragment, get_child)
508-
}
509-
510-
/// Compute the type of a fragment.
511-
fn type_check<Pk, Ctx>(fragment: &Terminal<Pk, Ctx>) -> Result<Self, Error>
512-
where
513-
Pk: MiniscriptKey,
514-
Ctx: ScriptContext,
515-
{
516-
Self::type_check_common(fragment, |sub, _n| Self::type_check(sub))
517-
}
518349
}
519350

520351
impl Property for Type {
@@ -695,22 +526,12 @@ impl Property for Type {
695526
mall: Property::threshold(k, n, |n| Ok(sub_ck(n)?.mall))?,
696527
})
697528
}
529+
}
698530

699-
fn type_check_with_child<Pk, Ctx, C>(
700-
_fragment: &Terminal<Pk, Ctx>,
701-
mut _child: C,
702-
) -> Result<Self, Error>
703-
where
704-
C: FnMut(usize) -> Self,
705-
Pk: MiniscriptKey,
706-
Ctx: ScriptContext,
707-
{
708-
unreachable!()
709-
}
710-
531+
impl Type {
711532
/// Compute the type of a fragment assuming all the children of
712533
/// Miniscript have been computed already.
713-
fn type_check<Pk, Ctx>(fragment: &Terminal<Pk, Ctx>) -> Result<Self, Error>
534+
pub fn type_check<Pk, Ctx>(fragment: &Terminal<Pk, Ctx>) -> Result<Self, Error>
714535
where
715536
Pk: MiniscriptKey,
716537
Ctx: ScriptContext,

0 commit comments

Comments
 (0)