Skip to content

Commit 8e2d90c

Browse files
committed
policy: make lifting algorithm non-recursive, remove Liftable for Terminal
It doesn't really make conceptual sense that Terminal would be Liftable. Terminal itself has no meaning; it isn't even typechecked. The recursive algorithm also repeats a lot of checks unnecessarily. Better to just call lift_check() once at the start of a Miniscript lift.
1 parent 44e0550 commit 8e2d90c

File tree

1 file changed

+56
-59
lines changed

1 file changed

+56
-59
lines changed

src/policy/mod.rs

Lines changed: 56 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ pub mod semantic;
2121
pub use self::concrete::Policy as Concrete;
2222
pub use self::semantic::Policy as Semantic;
2323
use crate::descriptor::Descriptor;
24+
use crate::iter::TreeLike as _;
2425
use crate::miniscript::{Miniscript, ScriptContext};
2526
use crate::sync::Arc;
2627
#[cfg(all(not(feature = "std"), not(test)))]
@@ -111,68 +112,64 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Liftable<Pk> for Miniscript<Pk, Ctx>
111112
// check whether the root miniscript can have a spending path that is
112113
// a combination of heightlock and timelock
113114
self.lift_check()?;
114-
self.as_inner().lift()
115-
}
116-
}
117115

118-
impl<Pk: MiniscriptKey, Ctx: ScriptContext> Liftable<Pk> for Terminal<Pk, Ctx> {
119-
fn lift(&self) -> Result<Semantic<Pk>, Error> {
120-
let ret = match *self {
121-
Terminal::PkK(ref pk) | Terminal::PkH(ref pk) => Semantic::Key(pk.clone()),
122-
Terminal::RawPkH(ref _pkh) => {
123-
return Err(Error::LiftError(LiftError::RawDescriptorLift))
124-
}
125-
Terminal::After(t) => Semantic::After(t),
126-
Terminal::Older(t) => Semantic::Older(t),
127-
Terminal::Sha256(ref h) => Semantic::Sha256(h.clone()),
128-
Terminal::Hash256(ref h) => Semantic::Hash256(h.clone()),
129-
Terminal::Ripemd160(ref h) => Semantic::Ripemd160(h.clone()),
130-
Terminal::Hash160(ref h) => Semantic::Hash160(h.clone()),
131-
Terminal::False => Semantic::Unsatisfiable,
132-
Terminal::True => Semantic::Trivial,
133-
Terminal::Alt(ref sub)
134-
| Terminal::Swap(ref sub)
135-
| Terminal::Check(ref sub)
136-
| Terminal::DupIf(ref sub)
137-
| Terminal::Verify(ref sub)
138-
| Terminal::NonZero(ref sub)
139-
| Terminal::ZeroNotEqual(ref sub) => sub.node.lift()?,
140-
Terminal::AndV(ref left, ref right) | Terminal::AndB(ref left, ref right) => {
141-
Semantic::Thresh(Threshold::and(
142-
Arc::new(left.node.lift()?),
143-
Arc::new(right.node.lift()?),
144-
))
145-
}
146-
Terminal::AndOr(ref a, ref b, ref c) => Semantic::Thresh(Threshold::or(
147-
Arc::new(Semantic::Thresh(Threshold::and(
148-
Arc::new(a.node.lift()?),
149-
Arc::new(b.node.lift()?),
116+
let mut stack = vec![];
117+
for item in self.rtl_post_order_iter() {
118+
let new_term = match item.node.node {
119+
Terminal::PkK(ref pk) | Terminal::PkH(ref pk) => {
120+
Arc::new(Semantic::Key(pk.clone()))
121+
}
122+
Terminal::RawPkH(ref _pkh) => {
123+
return Err(Error::LiftError(LiftError::RawDescriptorLift))
124+
}
125+
Terminal::After(t) => Arc::new(Semantic::After(t)),
126+
Terminal::Older(t) => Arc::new(Semantic::Older(t)),
127+
Terminal::Sha256(ref h) => Arc::new(Semantic::Sha256(h.clone())),
128+
Terminal::Hash256(ref h) => Arc::new(Semantic::Hash256(h.clone())),
129+
Terminal::Ripemd160(ref h) => Arc::new(Semantic::Ripemd160(h.clone())),
130+
Terminal::Hash160(ref h) => Arc::new(Semantic::Hash160(h.clone())),
131+
Terminal::False => Arc::new(Semantic::Unsatisfiable),
132+
Terminal::True => Arc::new(Semantic::Trivial),
133+
Terminal::Alt(..)
134+
| Terminal::Swap(..)
135+
| Terminal::Check(..)
136+
| Terminal::DupIf(..)
137+
| Terminal::Verify(..)
138+
| Terminal::NonZero(..)
139+
| Terminal::ZeroNotEqual(..) => stack.pop().unwrap(),
140+
Terminal::AndV(..) | Terminal::AndB(..) => Arc::new(Semantic::Thresh(
141+
Threshold::and(stack.pop().unwrap(), stack.pop().unwrap()),
142+
)),
143+
Terminal::AndOr(..) => Arc::new(Semantic::Thresh(Threshold::or(
144+
Arc::new(Semantic::Thresh(Threshold::and(
145+
stack.pop().unwrap(),
146+
stack.pop().unwrap(),
147+
))),
148+
stack.pop().unwrap(),
150149
))),
151-
Arc::new(c.node.lift()?),
152-
)),
153-
Terminal::OrB(ref left, ref right)
154-
| Terminal::OrD(ref left, ref right)
155-
| Terminal::OrC(ref left, ref right)
156-
| Terminal::OrI(ref left, ref right) => Semantic::Thresh(Threshold::or(
157-
Arc::new(left.node.lift()?),
158-
Arc::new(right.node.lift()?),
159-
)),
160-
Terminal::Thresh(ref thresh) => thresh
161-
.translate_ref(|sub| sub.lift().map(Arc::new))
162-
.map(Semantic::Thresh)?,
163-
Terminal::Multi(ref thresh) => Semantic::Thresh(
164-
thresh
165-
.map_ref(|key| Arc::new(Semantic::Key(key.clone())))
166-
.forget_maximum(),
167-
),
168-
Terminal::MultiA(ref thresh) => Semantic::Thresh(
169-
thresh
170-
.map_ref(|key| Arc::new(Semantic::Key(key.clone())))
171-
.forget_maximum(),
172-
),
150+
Terminal::OrB(..) | Terminal::OrD(..) | Terminal::OrC(..) | Terminal::OrI(..) => {
151+
Arc::new(Semantic::Thresh(Threshold::or(
152+
stack.pop().unwrap(),
153+
stack.pop().unwrap(),
154+
)))
155+
}
156+
Terminal::Thresh(ref thresh) => {
157+
Arc::new(Semantic::Thresh(thresh.map_ref(|_| stack.pop().unwrap())))
158+
}
159+
Terminal::Multi(ref thresh) => Arc::new(Semantic::Thresh(
160+
thresh
161+
.map_ref(|key| Arc::new(Semantic::Key(key.clone())))
162+
.forget_maximum(),
163+
)),
164+
Terminal::MultiA(ref thresh) => Arc::new(Semantic::Thresh(
165+
thresh
166+
.map_ref(|key| Arc::new(Semantic::Key(key.clone())))
167+
.forget_maximum(),
168+
)),
169+
};
170+
stack.push(new_term)
173171
}
174-
.normalized();
175-
Ok(ret)
172+
Ok(Arc::try_unwrap(stack.pop().unwrap()).unwrap().normalized())
176173
}
177174
}
178175

0 commit comments

Comments
 (0)