Skip to content

Commit 9cf6e9d

Browse files
committed
Merge #567: Eliminate a bunch of recursion
67e91b9 miniscript: eliminate recursion in substitute_raw_pkh (Andrew Poelstra) d858ffc miniscript: remove recursion from script_size (Andrew Poelstra) 8c32a19 miniscript: eliminate recursion from TranslatePk (Andrew Poelstra) 2930938 miniscript: eliminate recursion in for_each_key (Andrew Poelstra) 3c0ff73 iter: add module, copied in large from rust-simplicity (Andrew Poelstra) Pull request description: This introduces a new `iter` module with facilities for iterating over tree structures, and uses it to eliminate a bunch of recursion. There's a lot more "obvious" work after this, so I figured I'd PR this now for review and then do followup ones if it's accepted. Then there's some less obvious work around getting rid of the recursion in `Expression::from_str` and tightening up the memory allocation/locality there, and some even less obvious work in improving memory allocation/locality in `Miniscript`. But even if those later stages don't work out, this is a step in the right direction because it eliminates a bunch of stack overflow vectors, and reduces the amount of code. ACKs for top commit: sanket1729: reACK 67e91b9 Tree-SHA512: 30038e2e185f9ff5a87d32508a03db61f7de9997900ce381df3974f5dc1818402a2b444808907f5d849f7ca2f9812dd0c2f578a4fbad56ef2cd01b9382a60d70
2 parents 33676d1 + 67e91b9 commit 9cf6e9d

File tree

6 files changed

+560
-287
lines changed

6 files changed

+560
-287
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/iter/mod.rs

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Written in 2023 by Andrew Poelstra <[email protected]>
2+
// SPDX-License-Identifier: CC0-1.0
3+
4+
//! Abstract Tree Iteration
5+
//!
6+
//! This module provides functionality to treat Miniscript objects abstractly
7+
//! as trees, iterating over them in various orders. The iterators in this
8+
//! module can be used to avoid explicitly recursive algorithms.
9+
//!
10+
11+
mod tree;
12+
13+
pub use tree::{
14+
PostOrderIter, PostOrderIterItem, PreOrderIter, PreOrderIterItem, Tree, TreeLike,
15+
VerbosePreOrderIter,
16+
};
17+
18+
use crate::sync::Arc;
19+
use crate::{Miniscript, MiniscriptKey, ScriptContext, Terminal};
20+
21+
impl<'a, Pk: MiniscriptKey, Ctx: ScriptContext> TreeLike for &'a Miniscript<Pk, Ctx> {
22+
fn as_node(&self) -> Tree<Self> {
23+
match self.node {
24+
Terminal::PkK(..)
25+
| Terminal::PkH(..)
26+
| Terminal::RawPkH(..)
27+
| Terminal::After(..)
28+
| Terminal::Older(..)
29+
| Terminal::Sha256(..)
30+
| Terminal::Hash256(..)
31+
| Terminal::Ripemd160(..)
32+
| Terminal::Hash160(..)
33+
| Terminal::True
34+
| Terminal::False
35+
| Terminal::Multi(..)
36+
| Terminal::MultiA(..) => Tree::Nullary,
37+
Terminal::Alt(ref sub)
38+
| Terminal::Swap(ref sub)
39+
| Terminal::Check(ref sub)
40+
| Terminal::DupIf(ref sub)
41+
| Terminal::Verify(ref sub)
42+
| Terminal::NonZero(ref sub)
43+
| Terminal::ZeroNotEqual(ref sub) => Tree::Unary(sub),
44+
Terminal::AndV(ref left, ref right)
45+
| Terminal::AndB(ref left, ref right)
46+
| Terminal::OrB(ref left, ref right)
47+
| Terminal::OrD(ref left, ref right)
48+
| Terminal::OrC(ref left, ref right)
49+
| Terminal::OrI(ref left, ref right) => Tree::Binary(left, right),
50+
Terminal::AndOr(ref a, ref b, ref c) => Tree::Nary(Arc::from([a.as_ref(), b, c])),
51+
Terminal::Thresh(_, ref subs) => Tree::Nary(subs.iter().map(Arc::as_ref).collect()),
52+
}
53+
}
54+
}
55+
56+
impl<Pk: MiniscriptKey, Ctx: ScriptContext> TreeLike for Arc<Miniscript<Pk, Ctx>> {
57+
fn as_node(&self) -> Tree<Self> {
58+
match self.node {
59+
Terminal::PkK(..)
60+
| Terminal::PkH(..)
61+
| Terminal::RawPkH(..)
62+
| Terminal::After(..)
63+
| Terminal::Older(..)
64+
| Terminal::Sha256(..)
65+
| Terminal::Hash256(..)
66+
| Terminal::Ripemd160(..)
67+
| Terminal::Hash160(..)
68+
| Terminal::True
69+
| Terminal::False
70+
| Terminal::Multi(..)
71+
| Terminal::MultiA(..) => Tree::Nullary,
72+
Terminal::Alt(ref sub)
73+
| Terminal::Swap(ref sub)
74+
| Terminal::Check(ref sub)
75+
| Terminal::DupIf(ref sub)
76+
| Terminal::Verify(ref sub)
77+
| Terminal::NonZero(ref sub)
78+
| Terminal::ZeroNotEqual(ref sub) => Tree::Unary(Arc::clone(sub)),
79+
Terminal::AndV(ref left, ref right)
80+
| Terminal::AndB(ref left, ref right)
81+
| Terminal::OrB(ref left, ref right)
82+
| Terminal::OrD(ref left, ref right)
83+
| Terminal::OrC(ref left, ref right)
84+
| Terminal::OrI(ref left, ref right) => {
85+
Tree::Binary(Arc::clone(left), Arc::clone(right))
86+
}
87+
Terminal::AndOr(ref a, ref b, ref c) => {
88+
Tree::Nary(Arc::from([Arc::clone(a), Arc::clone(b), Arc::clone(c)]))
89+
}
90+
Terminal::Thresh(_, ref subs) => Tree::Nary(subs.iter().map(Arc::clone).collect()),
91+
}
92+
}
93+
}

0 commit comments

Comments
 (0)