Skip to content

Commit 8c32a19

Browse files
committed
miniscript: eliminate recursion from TranslatePk
This is again a breaking change because we remove the trait impl from `Terminal`, but again I don't think the trait impl should've existed. This also exposed an "off-label" use of `real_translate_pk` to convert context types as well as pk types, which I apparently explicitly reviewed and ACKed when reviewing rust-bitcoin#426, but which in retrospect looks a little funny. Rename this function to translate_pk_ctx so it's clear that it's doing two jobs.
1 parent 2930938 commit 8c32a19

File tree

3 files changed

+54
-103
lines changed

3 files changed

+54
-103
lines changed

src/interpreter/inner.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ impl<Ctx: ScriptContext> ToNoChecks for Miniscript<bitcoin::PublicKey, Ctx> {
380380
translate_hash_clone!(bitcoin::PublicKey, BitcoinKey, ());
381381
}
382382

383-
self.real_translate_pk(&mut TranslateFullPk)
383+
self.translate_pk_ctx(&mut TranslateFullPk)
384384
.expect("Translation should succeed")
385385
}
386386
}
@@ -397,7 +397,7 @@ impl<Ctx: ScriptContext> ToNoChecks for Miniscript<bitcoin::key::XOnlyPublicKey,
397397

398398
translate_hash_clone!(bitcoin::key::XOnlyPublicKey, BitcoinKey, ());
399399
}
400-
self.real_translate_pk(&mut TranslateXOnlyPk)
400+
self.translate_pk_ctx(&mut TranslateXOnlyPk)
401401
.expect("Translation should succeed")
402402
}
403403
}

src/miniscript/astelem.rs

+1-96
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use crate::prelude::*;
2222
use crate::util::MsKeyBuilder;
2323
use crate::{
2424
errstr, expression, script_num_size, AbsLockTime, Error, Miniscript, MiniscriptKey, Terminal,
25-
ToPublicKey, TranslateErr, TranslatePk, Translator,
25+
ToPublicKey,
2626
};
2727

2828
impl<Pk: MiniscriptKey, Ctx: ScriptContext> Terminal<Pk, Ctx> {
@@ -46,102 +46,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Terminal<Pk, Ctx> {
4646
}
4747
}
4848

49-
impl<Pk, Q, Ctx> TranslatePk<Pk, Q> for Terminal<Pk, Ctx>
50-
where
51-
Pk: MiniscriptKey,
52-
Q: MiniscriptKey,
53-
Ctx: ScriptContext,
54-
{
55-
type Output = Terminal<Q, Ctx>;
56-
57-
/// Converts an AST element with one public key type to one of another public key type.
58-
fn translate_pk<T, E>(&self, translate: &mut T) -> Result<Self::Output, TranslateErr<E>>
59-
where
60-
T: Translator<Pk, Q, E>,
61-
{
62-
self.real_translate_pk(translate)
63-
}
64-
}
65-
6649
impl<Pk: MiniscriptKey, Ctx: ScriptContext> Terminal<Pk, Ctx> {
67-
pub(super) fn real_translate_pk<Q, CtxQ, T, E>(
68-
&self,
69-
t: &mut T,
70-
) -> Result<Terminal<Q, CtxQ>, TranslateErr<E>>
71-
where
72-
Q: MiniscriptKey,
73-
CtxQ: ScriptContext,
74-
T: Translator<Pk, Q, E>,
75-
{
76-
let frag: Terminal<Q, CtxQ> = match *self {
77-
Terminal::PkK(ref p) => Terminal::PkK(t.pk(p)?),
78-
Terminal::PkH(ref p) => Terminal::PkH(t.pk(p)?),
79-
Terminal::RawPkH(ref p) => Terminal::RawPkH(*p),
80-
Terminal::After(n) => Terminal::After(n),
81-
Terminal::Older(n) => Terminal::Older(n),
82-
Terminal::Sha256(ref x) => Terminal::Sha256(t.sha256(x)?),
83-
Terminal::Hash256(ref x) => Terminal::Hash256(t.hash256(x)?),
84-
Terminal::Ripemd160(ref x) => Terminal::Ripemd160(t.ripemd160(x)?),
85-
Terminal::Hash160(ref x) => Terminal::Hash160(t.hash160(x)?),
86-
Terminal::True => Terminal::True,
87-
Terminal::False => Terminal::False,
88-
Terminal::Alt(ref sub) => Terminal::Alt(Arc::new(sub.real_translate_pk(t)?)),
89-
Terminal::Swap(ref sub) => Terminal::Swap(Arc::new(sub.real_translate_pk(t)?)),
90-
Terminal::Check(ref sub) => Terminal::Check(Arc::new(sub.real_translate_pk(t)?)),
91-
Terminal::DupIf(ref sub) => Terminal::DupIf(Arc::new(sub.real_translate_pk(t)?)),
92-
Terminal::Verify(ref sub) => Terminal::Verify(Arc::new(sub.real_translate_pk(t)?)),
93-
Terminal::NonZero(ref sub) => Terminal::NonZero(Arc::new(sub.real_translate_pk(t)?)),
94-
Terminal::ZeroNotEqual(ref sub) => {
95-
Terminal::ZeroNotEqual(Arc::new(sub.real_translate_pk(t)?))
96-
}
97-
Terminal::AndV(ref left, ref right) => Terminal::AndV(
98-
Arc::new(left.real_translate_pk(t)?),
99-
Arc::new(right.real_translate_pk(t)?),
100-
),
101-
Terminal::AndB(ref left, ref right) => Terminal::AndB(
102-
Arc::new(left.real_translate_pk(t)?),
103-
Arc::new(right.real_translate_pk(t)?),
104-
),
105-
Terminal::AndOr(ref a, ref b, ref c) => Terminal::AndOr(
106-
Arc::new(a.real_translate_pk(t)?),
107-
Arc::new(b.real_translate_pk(t)?),
108-
Arc::new(c.real_translate_pk(t)?),
109-
),
110-
Terminal::OrB(ref left, ref right) => Terminal::OrB(
111-
Arc::new(left.real_translate_pk(t)?),
112-
Arc::new(right.real_translate_pk(t)?),
113-
),
114-
Terminal::OrD(ref left, ref right) => Terminal::OrD(
115-
Arc::new(left.real_translate_pk(t)?),
116-
Arc::new(right.real_translate_pk(t)?),
117-
),
118-
Terminal::OrC(ref left, ref right) => Terminal::OrC(
119-
Arc::new(left.real_translate_pk(t)?),
120-
Arc::new(right.real_translate_pk(t)?),
121-
),
122-
Terminal::OrI(ref left, ref right) => Terminal::OrI(
123-
Arc::new(left.real_translate_pk(t)?),
124-
Arc::new(right.real_translate_pk(t)?),
125-
),
126-
Terminal::Thresh(k, ref subs) => {
127-
let subs: Result<Vec<Arc<Miniscript<Q, _>>>, _> = subs
128-
.iter()
129-
.map(|s| s.real_translate_pk(t).map(Arc::new))
130-
.collect();
131-
Terminal::Thresh(k, subs?)
132-
}
133-
Terminal::Multi(k, ref keys) => {
134-
let keys: Result<Vec<Q>, _> = keys.iter().map(|k| t.pk(k)).collect();
135-
Terminal::Multi(k, keys?)
136-
}
137-
Terminal::MultiA(k, ref keys) => {
138-
let keys: Result<Vec<Q>, _> = keys.iter().map(|k| t.pk(k)).collect();
139-
Terminal::MultiA(k, keys?)
140-
}
141-
};
142-
Ok(frag)
143-
}
144-
14550
/// Substitutes raw public keys hashes with the public keys as provided by map.
14651
pub fn substitute_raw_pkh(&self, pk_map: &BTreeMap<hash160::Hash, Pk>) -> Terminal<Pk, Ctx> {
14752
match self {

src/miniscript/mod.rs

+51-5
Original file line numberDiff line numberDiff line change
@@ -331,16 +331,16 @@ where
331331

332332
/// Translates a struct from one generic to another where the translation
333333
/// for Pk is provided by [`Translator`]
334-
fn translate_pk<T, E>(&self, translate: &mut T) -> Result<Self::Output, TranslateErr<E>>
334+
fn translate_pk<T, E>(&self, t: &mut T) -> Result<Self::Output, TranslateErr<E>>
335335
where
336336
T: Translator<Pk, Q, E>,
337337
{
338-
self.real_translate_pk(translate)
338+
self.translate_pk_ctx(t)
339339
}
340340
}
341341

342342
impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
343-
pub(super) fn real_translate_pk<Q, CtxQ, T, FuncError>(
343+
pub(super) fn translate_pk_ctx<Q, CtxQ, T, FuncError>(
344344
&self,
345345
t: &mut T,
346346
) -> Result<Miniscript<Q, CtxQ>, TranslateErr<FuncError>>
@@ -349,8 +349,54 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
349349
CtxQ: ScriptContext,
350350
T: Translator<Pk, Q, FuncError>,
351351
{
352-
let inner = self.node.real_translate_pk(t)?;
353-
Miniscript::from_ast(inner).map_err(TranslateErr::OuterError)
352+
let mut translated = vec![];
353+
for data in Arc::new(self.clone()).post_order_iter() {
354+
// convenience method to reduce typing
355+
let child_n = |n| Arc::clone(&translated[data.child_indices[n]]);
356+
357+
let new_term = match data.node.node {
358+
Terminal::PkK(ref p) => Terminal::PkK(t.pk(p)?),
359+
Terminal::PkH(ref p) => Terminal::PkH(t.pk(p)?),
360+
Terminal::RawPkH(ref p) => Terminal::RawPkH(*p),
361+
Terminal::After(n) => Terminal::After(n),
362+
Terminal::Older(n) => Terminal::Older(n),
363+
Terminal::Sha256(ref x) => Terminal::Sha256(t.sha256(x)?),
364+
Terminal::Hash256(ref x) => Terminal::Hash256(t.hash256(x)?),
365+
Terminal::Ripemd160(ref x) => Terminal::Ripemd160(t.ripemd160(x)?),
366+
Terminal::Hash160(ref x) => Terminal::Hash160(t.hash160(x)?),
367+
Terminal::True => Terminal::True,
368+
Terminal::False => Terminal::False,
369+
Terminal::Alt(..) => Terminal::Alt(child_n(0)),
370+
Terminal::Swap(..) => Terminal::Swap(child_n(0)),
371+
Terminal::Check(..) => Terminal::Check(child_n(0)),
372+
Terminal::DupIf(..) => Terminal::DupIf(child_n(0)),
373+
Terminal::Verify(..) => Terminal::Verify(child_n(0)),
374+
Terminal::NonZero(..) => Terminal::NonZero(child_n(0)),
375+
Terminal::ZeroNotEqual(..) => Terminal::ZeroNotEqual(child_n(0)),
376+
Terminal::AndV(..) => Terminal::AndV(child_n(0), child_n(1)),
377+
Terminal::AndB(..) => Terminal::AndB(child_n(0), child_n(1)),
378+
Terminal::AndOr(..) => Terminal::AndOr(child_n(0), child_n(1), child_n(2)),
379+
Terminal::OrB(..) => Terminal::OrB(child_n(0), child_n(1)),
380+
Terminal::OrD(..) => Terminal::OrD(child_n(0), child_n(1)),
381+
Terminal::OrC(..) => Terminal::OrC(child_n(0), child_n(1)),
382+
Terminal::OrI(..) => Terminal::OrI(child_n(0), child_n(1)),
383+
Terminal::Thresh(k, ref subs) => {
384+
Terminal::Thresh(k, (0..subs.len()).map(child_n).collect())
385+
}
386+
Terminal::Multi(k, ref keys) => {
387+
let keys: Result<Vec<Q>, _> = keys.iter().map(|k| t.pk(k)).collect();
388+
Terminal::Multi(k, keys?)
389+
}
390+
Terminal::MultiA(k, ref keys) => {
391+
let keys: Result<Vec<Q>, _> = keys.iter().map(|k| t.pk(k)).collect();
392+
Terminal::MultiA(k, keys?)
393+
}
394+
};
395+
let new_ms = Miniscript::from_ast(new_term).map_err(TranslateErr::OuterError)?;
396+
translated.push(Arc::new(new_ms));
397+
}
398+
399+
Ok(Arc::try_unwrap(translated.pop().unwrap()).unwrap())
354400
}
355401

356402
/// Substitutes raw public keys hashes with the public keys as provided by map.

0 commit comments

Comments
 (0)