Skip to content

Commit 95f8dac

Browse files
committed
compiler: eliminate unused error paths
Miniscript rules say that for andor(x,y,z), x must be dissatisfiable (must have the 'd' property). This means that we cannot construct a Miniscript with a non-dissatisfiable first child of an AndOr, because we would get a type-checking error. However we do this check again in CompilerExtData::and_or, for some reason. This is actually the *only* non-threshold-related error path in CompilerExtData::type_check, and getting rid of it will let us eliminate a ton of errors. So remove this. NEXT, we remove the two threshold-related error paths. These are the checks in CompilerExtData::type_check_common which check for k == 0 and for k > n. I *think* these paths are possible, but they are not tested, so we can remove them without breaking our tests. So we remove them here, allowing us to eliminate a ton of Ok(), ? and unwraps. The next commit will use the new Threshold type to make these error paths actually impossible.
1 parent 9eb4375 commit 95f8dac

File tree

1 file changed

+59
-95
lines changed

1 file changed

+59
-95
lines changed

src/policy/compiler.rs

Lines changed: 59 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -343,10 +343,7 @@ impl CompilerExtData {
343343
}
344344
}
345345

346-
fn and_or(a: Self, b: Self, c: Self) -> Result<Self, types::ErrorKind> {
347-
if a.dissat_cost.is_none() {
348-
return Err(ErrorKind::LeftNotDissatisfiable);
349-
}
346+
fn and_or(a: Self, b: Self, c: Self) -> Self {
350347
let aprob = a.branch_prob.expect("andor, a prob must be set");
351348
let bprob = b.branch_prob.expect("andor, b prob must be set");
352349
let cprob = c.branch_prob.expect("andor, c prob must be set");
@@ -355,51 +352,48 @@ impl CompilerExtData {
355352
.dissat_cost
356353
.expect("BUG: and_or first arg(a) must be dissatisfiable");
357354
debug_assert_eq!(aprob, bprob); //A and B must have same branch prob.
358-
Ok(CompilerExtData {
355+
CompilerExtData {
359356
branch_prob: None,
360357
sat_cost: aprob * (a.sat_cost + b.sat_cost) + cprob * (adis + c.sat_cost),
361358
dissat_cost: c.dissat_cost.map(|cdis| adis + cdis),
362-
})
359+
}
363360
}
364361

365-
fn threshold<S>(k: usize, n: usize, mut sub_ck: S) -> Result<Self, types::ErrorKind>
362+
fn threshold<S>(k: usize, n: usize, mut sub_ck: S) -> Self
366363
where
367-
S: FnMut(usize) -> Result<Self, types::ErrorKind>,
364+
S: FnMut(usize) -> Self,
368365
{
369366
let k_over_n = k as f64 / n as f64;
370367
let mut sat_cost = 0.0;
371368
let mut dissat_cost = 0.0;
372369
for i in 0..n {
373-
let sub = sub_ck(i)?;
370+
let sub = sub_ck(i);
374371
sat_cost += sub.sat_cost;
375372
dissat_cost += sub.dissat_cost.unwrap();
376373
}
377-
Ok(CompilerExtData {
374+
CompilerExtData {
378375
branch_prob: None,
379376
sat_cost: sat_cost * k_over_n + dissat_cost * (1.0 - k_over_n),
380377
dissat_cost: Some(dissat_cost),
381-
})
378+
}
382379
}
383380
}
384381

385382
impl CompilerExtData {
386383
/// Compute the type of a fragment, given a function to look up
387384
/// the types of its children.
388-
fn type_check_with_child<Pk, Ctx, C>(
389-
fragment: &Terminal<Pk, Ctx>,
390-
child: C,
391-
) -> Result<Self, types::Error>
385+
fn type_check_with_child<Pk, Ctx, C>(fragment: &Terminal<Pk, Ctx>, child: C) -> Self
392386
where
393387
C: Fn(usize) -> Self,
394388
Pk: MiniscriptKey,
395389
Ctx: ScriptContext,
396390
{
397-
let get_child = |_sub, n| Ok(child(n));
391+
let get_child = |_sub, n| child(n);
398392
Self::type_check_common(fragment, get_child)
399393
}
400394

401395
/// Compute the type of a fragment.
402-
fn type_check<Pk, Ctx>(fragment: &Terminal<Pk, Ctx>) -> Result<Self, types::Error>
396+
fn type_check<Pk, Ctx>(fragment: &Terminal<Pk, Ctx>) -> Self
403397
where
404398
Pk: MiniscriptKey,
405399
Ctx: ScriptContext,
@@ -411,99 +405,70 @@ impl CompilerExtData {
411405
/// Compute the type of a fragment, given a function to look up
412406
/// the types of its children, if available and relevant for the
413407
/// given fragment
414-
fn type_check_common<'a, Pk, Ctx, C>(
415-
fragment: &'a Terminal<Pk, Ctx>,
416-
get_child: C,
417-
) -> Result<Self, types::Error>
408+
fn type_check_common<'a, Pk, Ctx, C>(fragment: &'a Terminal<Pk, Ctx>, get_child: C) -> Self
418409
where
419-
C: Fn(&'a Terminal<Pk, Ctx>, usize) -> Result<Self, types::Error>,
410+
C: Fn(&'a Terminal<Pk, Ctx>, usize) -> Self,
420411
Pk: MiniscriptKey,
421412
Ctx: ScriptContext,
422413
{
423414
match *fragment {
424-
Terminal::True => Ok(Self::TRUE),
425-
Terminal::False => Ok(Self::FALSE),
426-
Terminal::PkK(..) => Ok(Self::pk_k::<Ctx>()),
427-
Terminal::PkH(..) | Terminal::RawPkH(..) => Ok(Self::pk_h::<Ctx>()),
428-
Terminal::Multi(ref thresh) => Ok(Self::multi(thresh.k(), thresh.n())),
429-
Terminal::MultiA(ref thresh) => Ok(Self::multi_a(thresh.k(), thresh.n())),
430-
Terminal::After(_) => Ok(Self::time()),
431-
Terminal::Older(_) => Ok(Self::time()),
432-
Terminal::Sha256(..) => Ok(Self::hash()),
433-
Terminal::Hash256(..) => Ok(Self::hash()),
434-
Terminal::Ripemd160(..) => Ok(Self::hash()),
435-
Terminal::Hash160(..) => Ok(Self::hash()),
436-
Terminal::Alt(ref sub) => Ok(Self::cast_alt(get_child(&sub.node, 0)?)),
437-
Terminal::Swap(ref sub) => Ok(Self::cast_swap(get_child(&sub.node, 0)?)),
438-
Terminal::Check(ref sub) => Ok(Self::cast_check(get_child(&sub.node, 0)?)),
439-
Terminal::DupIf(ref sub) => Ok(Self::cast_dupif(get_child(&sub.node, 0)?)),
440-
Terminal::Verify(ref sub) => Ok(Self::cast_verify(get_child(&sub.node, 0)?)),
441-
Terminal::NonZero(ref sub) => Ok(Self::cast_nonzero(get_child(&sub.node, 0)?)),
442-
Terminal::ZeroNotEqual(ref sub) => {
443-
Ok(Self::cast_zeronotequal(get_child(&sub.node, 0)?))
444-
}
415+
Terminal::True => Self::TRUE,
416+
Terminal::False => Self::FALSE,
417+
Terminal::PkK(..) => Self::pk_k::<Ctx>(),
418+
Terminal::PkH(..) | Terminal::RawPkH(..) => Self::pk_h::<Ctx>(),
419+
Terminal::Multi(ref thresh) => Self::multi(thresh.k(), thresh.n()),
420+
Terminal::MultiA(ref thresh) => Self::multi_a(thresh.k(), thresh.n()),
421+
Terminal::After(_) => Self::time(),
422+
Terminal::Older(_) => Self::time(),
423+
Terminal::Sha256(..) => Self::hash(),
424+
Terminal::Hash256(..) => Self::hash(),
425+
Terminal::Ripemd160(..) => Self::hash(),
426+
Terminal::Hash160(..) => Self::hash(),
427+
Terminal::Alt(ref sub) => Self::cast_alt(get_child(&sub.node, 0)),
428+
Terminal::Swap(ref sub) => Self::cast_swap(get_child(&sub.node, 0)),
429+
Terminal::Check(ref sub) => Self::cast_check(get_child(&sub.node, 0)),
430+
Terminal::DupIf(ref sub) => Self::cast_dupif(get_child(&sub.node, 0)),
431+
Terminal::Verify(ref sub) => Self::cast_verify(get_child(&sub.node, 0)),
432+
Terminal::NonZero(ref sub) => Self::cast_nonzero(get_child(&sub.node, 0)),
433+
Terminal::ZeroNotEqual(ref sub) => Self::cast_zeronotequal(get_child(&sub.node, 0)),
445434
Terminal::AndB(ref l, ref r) => {
446-
let ltype = get_child(&l.node, 0)?;
447-
let rtype = get_child(&r.node, 1)?;
448-
Ok(Self::and_b(ltype, rtype))
435+
let ltype = get_child(&l.node, 0);
436+
let rtype = get_child(&r.node, 1);
437+
Self::and_b(ltype, rtype)
449438
}
450439
Terminal::AndV(ref l, ref r) => {
451-
let ltype = get_child(&l.node, 0)?;
452-
let rtype = get_child(&r.node, 1)?;
453-
Ok(Self::and_v(ltype, rtype))
440+
let ltype = get_child(&l.node, 0);
441+
let rtype = get_child(&r.node, 1);
442+
Self::and_v(ltype, rtype)
454443
}
455444
Terminal::OrB(ref l, ref r) => {
456-
let ltype = get_child(&l.node, 0)?;
457-
let rtype = get_child(&r.node, 1)?;
458-
Ok(Self::or_b(ltype, rtype))
445+
let ltype = get_child(&l.node, 0);
446+
let rtype = get_child(&r.node, 1);
447+
Self::or_b(ltype, rtype)
459448
}
460449
Terminal::OrD(ref l, ref r) => {
461-
let ltype = get_child(&l.node, 0)?;
462-
let rtype = get_child(&r.node, 1)?;
463-
Ok(Self::or_d(ltype, rtype))
450+
let ltype = get_child(&l.node, 0);
451+
let rtype = get_child(&r.node, 1);
452+
Self::or_d(ltype, rtype)
464453
}
465454
Terminal::OrC(ref l, ref r) => {
466-
let ltype = get_child(&l.node, 0)?;
467-
let rtype = get_child(&r.node, 1)?;
468-
Ok(Self::or_c(ltype, rtype))
455+
let ltype = get_child(&l.node, 0);
456+
let rtype = get_child(&r.node, 1);
457+
Self::or_c(ltype, rtype)
469458
}
470459
Terminal::OrI(ref l, ref r) => {
471-
let ltype = get_child(&l.node, 0)?;
472-
let rtype = get_child(&r.node, 1)?;
473-
Ok(Self::or_i(ltype, rtype))
460+
let ltype = get_child(&l.node, 0);
461+
let rtype = get_child(&r.node, 1);
462+
Self::or_i(ltype, rtype)
474463
}
475464
Terminal::AndOr(ref a, ref b, ref c) => {
476-
let atype = get_child(&a.node, 0)?;
477-
let btype = get_child(&b.node, 1)?;
478-
let ctype = get_child(&c.node, 2)?;
479-
Self::and_or(atype, btype, ctype).map_err(|kind| types::Error {
480-
fragment_string: fragment.to_string(),
481-
error: kind,
482-
})
465+
let atype = get_child(&a.node, 0);
466+
let btype = get_child(&b.node, 1);
467+
let ctype = get_child(&c.node, 2);
468+
Self::and_or(atype, btype, ctype)
483469
}
484470
Terminal::Thresh(k, ref subs) => {
485-
if k == 0 {
486-
return Err(types::Error {
487-
fragment_string: fragment.to_string(),
488-
error: types::ErrorKind::ZeroThreshold,
489-
});
490-
}
491-
if k > subs.len() {
492-
return Err(types::Error {
493-
fragment_string: fragment.to_string(),
494-
error: types::ErrorKind::OverThreshold(k, subs.len()),
495-
});
496-
}
497-
498-
let mut last_err_frag = None;
499-
Self::threshold(k, subs.len(), |n| match get_child(&subs[n].node, n) {
500-
Ok(x) => Ok(x),
501-
Err(e) => {
502-
last_err_frag = Some(e.fragment_string);
503-
Err(e.error)
504-
}
505-
})
506-
.map_err(|kind| types::Error { fragment_string: fragment.to_string(), error: kind })
471+
Self::threshold(k, subs.len(), |n| get_child(&subs[n].node, n))
507472
}
508473
}
509474
}
@@ -537,7 +502,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> AstElemExt<Pk, Ctx> {
537502
impl<Pk: MiniscriptKey, Ctx: ScriptContext> AstElemExt<Pk, Ctx> {
538503
fn terminal(ast: Terminal<Pk, Ctx>) -> AstElemExt<Pk, Ctx> {
539504
AstElemExt {
540-
comp_ext_data: CompilerExtData::type_check(&ast).unwrap(),
505+
comp_ext_data: CompilerExtData::type_check(&ast),
541506
ms: Arc::new(Miniscript::from_ast(ast).expect("Terminal creation must always succeed")),
542507
}
543508
}
@@ -556,7 +521,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> AstElemExt<Pk, Ctx> {
556521
//type_check without cache. For Compiler extra data, we supply a cache.
557522
let ty = types::Type::type_check(&ast)?;
558523
let ext = types::ExtData::type_check(&ast)?;
559-
let comp_ext_data = CompilerExtData::type_check_with_child(&ast, lookup_ext)?;
524+
let comp_ext_data = CompilerExtData::type_check_with_child(&ast, lookup_ext);
560525
Ok(AstElemExt {
561526
ms: Arc::new(Miniscript::from_components_unchecked(ast, ty, ext)),
562527
comp_ext_data,
@@ -579,7 +544,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> AstElemExt<Pk, Ctx> {
579544
//type_check without cache. For Compiler extra data, we supply a cache.
580545
let ty = types::Type::type_check(&ast)?;
581546
let ext = types::ExtData::type_check(&ast)?;
582-
let comp_ext_data = CompilerExtData::type_check_with_child(&ast, lookup_ext)?;
547+
let comp_ext_data = CompilerExtData::type_check_with_child(&ast, lookup_ext);
583548
Ok(AstElemExt {
584549
ms: Arc::new(Miniscript::from_components_unchecked(ast, ty, ext)),
585550
comp_ext_data,
@@ -1031,8 +996,7 @@ where
1031996
if let Ok(ms) = Miniscript::from_ast(ast) {
1032997
let ast_ext = AstElemExt {
1033998
ms: Arc::new(ms),
1034-
comp_ext_data: CompilerExtData::threshold(k, n, |i| Ok(sub_ext_data[i]))
1035-
.expect("threshold subs, which we just compiled, typeck"),
999+
comp_ext_data: CompilerExtData::threshold(k, n, |i| sub_ext_data[i]),
10361000
};
10371001
insert_wrap!(ast_ext);
10381002
}

0 commit comments

Comments
 (0)