Skip to content

Commit 1b53dec

Browse files
committed
miniscript: nonrecursive implementation of PartialEq/Eq/Hash
1 parent 1337f7f commit 1b53dec

File tree

2 files changed

+87
-2
lines changed

2 files changed

+87
-2
lines changed

src/iter/mod.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,33 @@ impl<'a, Pk: MiniscriptKey, Ctx: ScriptContext> TreeLike for &'a Arc<Miniscript<
7676
}
7777
}
7878
}
79+
80+
impl<'a, Pk: MiniscriptKey, Ctx: ScriptContext> TreeLike for &'a Terminal<Pk, Ctx> {
81+
type NaryChildren = &'a [Arc<Miniscript<Pk, Ctx>>];
82+
83+
fn nary_len(tc: &Self::NaryChildren) -> usize { tc.len() }
84+
fn nary_index(tc: Self::NaryChildren, idx: usize) -> Self { tc[idx].as_inner() }
85+
86+
fn as_node(&self) -> Tree<Self, Self::NaryChildren> {
87+
use Terminal::*;
88+
match self {
89+
PkK(..) | PkH(..) | RawPkH(..) | After(..) | Older(..) | Sha256(..) | Hash256(..)
90+
| Ripemd160(..) | Hash160(..) | True | False | Multi(..) | MultiA(..) => Tree::Nullary,
91+
Alt(ref sub)
92+
| Swap(ref sub)
93+
| Check(ref sub)
94+
| DupIf(ref sub)
95+
| Verify(ref sub)
96+
| NonZero(ref sub)
97+
| ZeroNotEqual(ref sub) => Tree::Unary(sub.as_inner()),
98+
AndV(ref left, ref right)
99+
| AndB(ref left, ref right)
100+
| OrB(ref left, ref right)
101+
| OrD(ref left, ref right)
102+
| OrC(ref left, ref right)
103+
| OrI(ref left, ref right) => Tree::Binary(left.as_inner(), right.as_inner()),
104+
AndOr(ref a, ref b, ref c) => Tree::Ternary(a.as_inner(), b.as_inner(), c.as_inner()),
105+
Thresh(ref thresh) => Tree::Nary(thresh.data()),
106+
}
107+
}
108+
}

src/miniscript/decode.rs

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@
55
//! Functionality to parse a Bitcoin Script into a `Miniscript`
66
//!
77
8-
use core::fmt;
8+
use core::{fmt, mem};
99
#[cfg(feature = "std")]
1010
use std::error;
1111

1212
use bitcoin::hashes::{hash160, ripemd160, sha256, Hash};
1313
use sync::Arc;
1414

15+
use crate::iter::TreeLike;
1516
use crate::miniscript::lex::{Token as Tk, TokenIter};
1617
use crate::miniscript::limits::{MAX_PUBKEYS_IN_CHECKSIGADD, MAX_PUBKEYS_PER_MULTISIG};
1718
use crate::miniscript::ScriptContext;
@@ -114,7 +115,7 @@ enum NonTerm {
114115
///
115116
/// The average user should always use the [`Descriptor`] APIs. Advanced users who want deal
116117
/// with Miniscript ASTs should use the [`Miniscript`] APIs.
117-
#[derive(Clone, PartialEq, Eq, Hash)]
118+
#[derive(Clone)]
118119
pub enum Terminal<Pk: MiniscriptKey, Ctx: ScriptContext> {
119120
/// `1`
120121
True,
@@ -185,6 +186,60 @@ pub enum Terminal<Pk: MiniscriptKey, Ctx: ScriptContext> {
185186
MultiA(Threshold<Pk, MAX_PUBKEYS_IN_CHECKSIGADD>),
186187
}
187188

189+
impl<Pk: MiniscriptKey, Ctx: ScriptContext> PartialEq for Terminal<Pk, Ctx> {
190+
fn eq(&self, other: &Self) -> bool {
191+
for (me, you) in self.pre_order_iter().zip(other.pre_order_iter()) {
192+
match (me, you) {
193+
(Terminal::PkK(key1), Terminal::PkK(key2)) if key1 != key2 => return false,
194+
(Terminal::PkH(key1), Terminal::PkH(key2)) if key1 != key2 => return false,
195+
(Terminal::RawPkH(h1), Terminal::RawPkH(h2)) if h1 != h2 => return false,
196+
(Terminal::After(t1), Terminal::After(t2)) if t1 != t2 => return false,
197+
(Terminal::Older(t1), Terminal::Older(t2)) if t1 != t2 => return false,
198+
(Terminal::Sha256(h1), Terminal::Sha256(h2)) if h1 != h2 => return false,
199+
(Terminal::Hash256(h1), Terminal::Hash256(h2)) if h1 != h2 => return false,
200+
(Terminal::Ripemd160(h1), Terminal::Ripemd160(h2)) if h1 != h2 => return false,
201+
(Terminal::Hash160(h1), Terminal::Hash160(h2)) if h1 != h2 => return false,
202+
(Terminal::Multi(th1), Terminal::Multi(th2)) if th1 != th2 => return false,
203+
(Terminal::MultiA(th1), Terminal::MultiA(th2)) if th1 != th2 => return false,
204+
_ => {
205+
if mem::discriminant(me) != mem::discriminant(you) {
206+
return false;
207+
}
208+
}
209+
}
210+
}
211+
true
212+
}
213+
}
214+
impl<Pk: MiniscriptKey, Ctx: ScriptContext> Eq for Terminal<Pk, Ctx> {}
215+
216+
impl<Pk: MiniscriptKey, Ctx: ScriptContext> core::hash::Hash for Terminal<Pk, Ctx> {
217+
fn hash<H: core::hash::Hasher>(&self, hasher: &mut H) {
218+
for term in self.pre_order_iter() {
219+
mem::discriminant(term).hash(hasher);
220+
match term {
221+
Terminal::PkK(key) => key.hash(hasher),
222+
Terminal::PkH(key) => key.hash(hasher),
223+
Terminal::RawPkH(h) => h.hash(hasher),
224+
Terminal::After(t) => t.hash(hasher),
225+
Terminal::Older(t) => t.hash(hasher),
226+
Terminal::Sha256(h) => h.hash(hasher),
227+
Terminal::Hash256(h) => h.hash(hasher),
228+
Terminal::Ripemd160(h) => h.hash(hasher),
229+
Terminal::Hash160(h) => h.hash(hasher),
230+
Terminal::Thresh(th) => {
231+
th.k().hash(hasher);
232+
th.n().hash(hasher);
233+
// The actual children will be hashed when we iterate
234+
}
235+
Terminal::Multi(th) => th.hash(hasher),
236+
Terminal::MultiA(th) => th.hash(hasher),
237+
_ => {}
238+
}
239+
}
240+
}
241+
}
242+
188243
macro_rules! match_token {
189244
// Base case
190245
($tokens:expr => $sub:expr,) => { $sub };

0 commit comments

Comments
 (0)