Skip to content

Commit f3704d1

Browse files
committed
Merge #784: expression: implement parsing of policies and miniscripts non-recursively
26c6dc3 miniscript: implement from_tree nonrecursively (Andrew Poelstra) 2c422af policy: make Concrete::from_tree non-recursive (Andrew Poelstra) 61a89a2 policy: make Semantic::from_tree non-recursive (Andrew Poelstra) 8a78025 miniscript: add constructors for all the terminals (Andrew Poelstra) Pull request description: This brings us to the end of my cached "rewrite expression module" branch, by making expression parsing non-recursive. The diff here is actually reasonably short but it's pretty invasive. Hopefully the new fuzz test from the last PR is enough to convince us of correctness. I have some more work to do in two directions: * Breaking up the two `Policy` types into a structs with inner enums (or possibly just a flat tree type), which will allow us to attach metadata to nodes and trees; after this, I will introduce the `ValidationParams` structure and start moving sanity/validation/parsing logic into there as suggested in #723. I have some incomplete commits in this direction but I probably want to redo them with lessons learned from the Taproot work. * Replacing the `TapTree` enum with a non-recursive type, which will let us replace the taproot iteration API with a more natural one (as well as getting some performance benefit). I have more-complete work on this, but I'm getting a bit hamstrung right now handling the difference between `MiniscriptKey` and `ToPublicKey` in this specialization-less language. ACKs for top commit: sanket1729: ACK 26c6dc3 Tree-SHA512: b576d779ec1bf495176867e8e35602e1ed8e2a6a9df99fb0058ab437f9e43cf680a0b3bd459c27ba4e21ac58f534b35f7cac6566273c66615d7dc47015243c9a
2 parents 772d7de + 26c6dc3 commit f3704d1

File tree

4 files changed

+497
-336
lines changed

4 files changed

+497
-336
lines changed

src/miniscript/astelem.rs

Lines changed: 1 addition & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -9,147 +9,11 @@
99
1010
use bitcoin::hashes::Hash;
1111
use bitcoin::{absolute, opcodes, script};
12-
use sync::Arc;
1312

1413
use crate::miniscript::context::SigType;
1514
use crate::miniscript::ScriptContext;
16-
use crate::prelude::*;
1715
use crate::util::MsKeyBuilder;
18-
use crate::{expression, Error, FromStrKey, Miniscript, MiniscriptKey, Terminal, ToPublicKey};
19-
20-
impl<Pk: FromStrKey, Ctx: ScriptContext> crate::expression::FromTree for Arc<Terminal<Pk, Ctx>> {
21-
fn from_tree(root: expression::TreeIterItem) -> Result<Arc<Terminal<Pk, Ctx>>, Error> {
22-
Ok(Arc::new(expression::FromTree::from_tree(root)?))
23-
}
24-
}
25-
26-
impl<Pk: FromStrKey, Ctx: ScriptContext> crate::expression::FromTree for Terminal<Pk, Ctx> {
27-
fn from_tree(top: expression::TreeIterItem) -> Result<Terminal<Pk, Ctx>, Error> {
28-
let binary = |node: expression::TreeIterItem,
29-
name,
30-
termfn: fn(_, _) -> Self|
31-
-> Result<Self, Error> {
32-
node.verify_binary(name)
33-
.map_err(From::from)
34-
.map_err(Error::Parse)
35-
.and_then(|(x, y)| {
36-
let x = Arc::<Miniscript<Pk, Ctx>>::from_tree(x)?;
37-
let y = Arc::<Miniscript<Pk, Ctx>>::from_tree(y)?;
38-
Ok(termfn(x, y))
39-
})
40-
};
41-
42-
let (frag_wrap, frag_name) = top
43-
.name_separated(':')
44-
.map_err(From::from)
45-
.map_err(Error::Parse)?;
46-
// "pk" and "pkh" are aliases for "c:pk_k" and "c:pk_h" respectively.
47-
let unwrapped = match frag_name {
48-
"expr_raw_pkh" => top
49-
.verify_terminal_parent("expr_raw_pkh", "public key hash")
50-
.map(Terminal::RawPkH)
51-
.map_err(Error::Parse),
52-
"pk" => top
53-
.verify_terminal_parent("pk", "public key")
54-
.map(Terminal::PkK)
55-
.map_err(Error::Parse)
56-
.and_then(|term| Miniscript::from_ast(term))
57-
.map(|ms| Terminal::Check(Arc::new(ms))),
58-
"pkh" => top
59-
.verify_terminal_parent("pkh", "public key")
60-
.map(Terminal::PkH)
61-
.map_err(Error::Parse)
62-
.and_then(|term| Miniscript::from_ast(term))
63-
.map(|ms| Terminal::Check(Arc::new(ms))),
64-
"pk_k" => top
65-
.verify_terminal_parent("pk_k", "public key")
66-
.map(Terminal::PkK)
67-
.map_err(Error::Parse),
68-
"pk_h" => top
69-
.verify_terminal_parent("pk_h", "public key")
70-
.map(Terminal::PkH)
71-
.map_err(Error::Parse),
72-
"after" => top
73-
.verify_after()
74-
.map_err(Error::Parse)
75-
.map(Terminal::After),
76-
"older" => top
77-
.verify_older()
78-
.map_err(Error::Parse)
79-
.map(Terminal::Older),
80-
"sha256" => top
81-
.verify_terminal_parent("sha256", "hash")
82-
.map(Terminal::Sha256)
83-
.map_err(Error::Parse),
84-
"hash256" => top
85-
.verify_terminal_parent("hash256", "hash")
86-
.map(Terminal::Hash256)
87-
.map_err(Error::Parse),
88-
"ripemd160" => top
89-
.verify_terminal_parent("ripemd160", "hash")
90-
.map(Terminal::Ripemd160)
91-
.map_err(Error::Parse),
92-
"hash160" => top
93-
.verify_terminal_parent("hash160", "hash")
94-
.map(Terminal::Hash160)
95-
.map_err(Error::Parse),
96-
"1" => {
97-
top.verify_n_children("1", 0..=0)
98-
.map_err(From::from)
99-
.map_err(Error::Parse)?;
100-
Ok(Terminal::True)
101-
}
102-
"0" => {
103-
top.verify_n_children("0", 0..=0)
104-
.map_err(From::from)
105-
.map_err(Error::Parse)?;
106-
Ok(Terminal::False)
107-
}
108-
"and_v" => binary(top, "and_v", Terminal::AndV),
109-
"and_b" => binary(top, "and_b", Terminal::AndB),
110-
"and_n" => {
111-
binary(top, "and_n", |x, y| Terminal::AndOr(x, y, Arc::new(Miniscript::FALSE)))
112-
}
113-
"andor" => {
114-
top.verify_n_children("andor", 3..=3)
115-
.map_err(From::from)
116-
.map_err(Error::Parse)?;
117-
let mut child_iter = top
118-
.children()
119-
.map(|x| Arc::<Miniscript<Pk, Ctx>>::from_tree(x));
120-
Ok(Terminal::AndOr(
121-
child_iter.next().unwrap()?,
122-
child_iter.next().unwrap()?,
123-
child_iter.next().unwrap()?,
124-
))
125-
}
126-
"or_b" => binary(top, "or_b", Terminal::OrB),
127-
"or_d" => binary(top, "or_d", Terminal::OrD),
128-
"or_c" => binary(top, "or_c", Terminal::OrC),
129-
"or_i" => binary(top, "or_i", Terminal::OrI),
130-
"thresh" => top
131-
.verify_threshold(|sub| Miniscript::from_tree(sub).map(Arc::new))
132-
.map(Terminal::Thresh),
133-
"multi" => top
134-
.verify_threshold(|sub| sub.verify_terminal("public_key").map_err(Error::Parse))
135-
.map(Terminal::Multi),
136-
"multi_a" => top
137-
.verify_threshold(|sub| sub.verify_terminal("public_key").map_err(Error::Parse))
138-
.map(Terminal::MultiA),
139-
x => Err(Error::Parse(crate::ParseError::Tree(crate::ParseTreeError::UnknownName {
140-
name: x.to_owned(),
141-
}))),
142-
}?;
143-
144-
if frag_wrap == Some("") {
145-
return Err(Error::Parse(crate::ParseError::Tree(
146-
crate::ParseTreeError::UnknownName { name: top.name().to_owned() },
147-
)));
148-
}
149-
let ms = super::wrap_into_miniscript(unwrapped, frag_wrap.unwrap_or(""))?;
150-
Ok(ms.node)
151-
}
152-
}
16+
use crate::{Miniscript, MiniscriptKey, Terminal, ToPublicKey};
15317

15418
/// Helper trait to add a `push_astelem` method to `script::Builder`
15519
trait PushAstElem<Pk: MiniscriptKey, Ctx: ScriptContext> {

0 commit comments

Comments
 (0)