Skip to content

Commit e519f52

Browse files
committed
add for_each_key and for_any_key utility functions
1 parent 95811b2 commit e519f52

File tree

10 files changed

+248
-11
lines changed

10 files changed

+248
-11
lines changed

src/descriptor/bare.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ use expression::{self, FromTree};
2626
use miniscript::context::ScriptContext;
2727
use policy::{semantic, Liftable};
2828
use util::{varint_len, witness_to_scriptsig};
29-
use {BareCtx, Error, Miniscript, MiniscriptKey, Satisfier, ToPublicKey, TranslatePk};
29+
use {
30+
BareCtx, Error, ForEach, ForEachKey, Miniscript, MiniscriptKey, Satisfier, ToPublicKey,
31+
TranslatePk,
32+
};
3033

3134
use super::{
3235
checksum::{desc_checksum, verify_checksum},
@@ -163,6 +166,16 @@ where
163166
}
164167
}
165168

169+
impl<Pk: MiniscriptKey> ForEachKey<Pk> for Bare<Pk> {
170+
fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, pred: F) -> bool
171+
where
172+
Pk: 'a,
173+
Pk::Hash: 'a,
174+
{
175+
self.ms.for_each_key(pred)
176+
}
177+
}
178+
166179
impl<P: MiniscriptKey, Q: MiniscriptKey> TranslatePk<P, Q> for Bare<P> {
167180
type Output = Bare<Q>;
168181

@@ -327,6 +340,16 @@ where
327340
}
328341
}
329342

343+
impl<Pk: MiniscriptKey> ForEachKey<Pk> for Pkh<Pk> {
344+
fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, mut pred: F) -> bool
345+
where
346+
Pk: 'a,
347+
Pk::Hash: 'a,
348+
{
349+
pred(ForEach::Key(&self.pk))
350+
}
351+
}
352+
330353
impl<P: MiniscriptKey, Q: MiniscriptKey> TranslatePk<P, Q> for Pkh<P> {
331354
type Output = Pkh<Q>;
332355

src/descriptor/mod.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,10 @@ use self::checksum::verify_checksum;
3636
use expression;
3737
use miniscript;
3838
use miniscript::{Legacy, Miniscript, Segwitv0};
39-
use {BareCtx, Error, MiniscriptKey, Satisfier, ToPublicKey, TranslatePk, TranslatePk2};
39+
use {
40+
BareCtx, Error, ForEach, ForEachKey, MiniscriptKey, Satisfier, ToPublicKey, TranslatePk,
41+
TranslatePk2,
42+
};
4043

4144
mod bare;
4245
mod segwitv0;
@@ -422,6 +425,22 @@ where
422425
}
423426
}
424427

428+
impl<Pk: MiniscriptKey> ForEachKey<Pk> for Descriptor<Pk> {
429+
fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, pred: F) -> bool
430+
where
431+
Pk: 'a,
432+
Pk::Hash: 'a,
433+
{
434+
match *self {
435+
Descriptor::Bare(ref bare) => bare.for_each_key(pred),
436+
Descriptor::Pkh(ref pkh) => pkh.for_each_key(pred),
437+
Descriptor::Wpkh(ref wpkh) => wpkh.for_each_key(pred),
438+
Descriptor::Wsh(ref wsh) => wsh.for_each_key(pred),
439+
Descriptor::Sh(ref sh) => sh.for_each_key(pred),
440+
}
441+
}
442+
}
443+
425444
impl Descriptor<DescriptorPublicKey> {
426445
/// Derives all wildcard keys in the descriptor using the supplied index
427446
///

src/descriptor/segwitv0.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ use expression::{self, FromTree};
2424
use miniscript::context::{ScriptContext, ScriptContextError};
2525
use policy::{semantic, Liftable};
2626
use util::varint_len;
27-
use {Error, Miniscript, MiniscriptKey, Satisfier, Segwitv0, ToPublicKey, TranslatePk};
27+
use {
28+
Error, ForEach, ForEachKey, Miniscript, MiniscriptKey, Satisfier, Segwitv0, ToPublicKey,
29+
TranslatePk,
30+
};
2831

2932
use super::{
3033
checksum::{desc_checksum, verify_checksum},
@@ -232,6 +235,19 @@ where
232235
}
233236
}
234237

238+
impl<Pk: MiniscriptKey> ForEachKey<Pk> for Wsh<Pk> {
239+
fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, pred: F) -> bool
240+
where
241+
Pk: 'a,
242+
Pk::Hash: 'a,
243+
{
244+
match self.inner {
245+
WshInner::SortedMulti(ref smv) => smv.for_each_key(pred),
246+
WshInner::Ms(ref ms) => ms.for_each_key(pred),
247+
}
248+
}
249+
}
250+
235251
impl<P: MiniscriptKey, Q: MiniscriptKey> TranslatePk<P, Q> for Wsh<P> {
236252
type Output = Wsh<Q>;
237253

@@ -411,6 +427,16 @@ where
411427
}
412428
}
413429

430+
impl<Pk: MiniscriptKey> ForEachKey<Pk> for Wpkh<Pk> {
431+
fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, mut pred: F) -> bool
432+
where
433+
Pk: 'a,
434+
Pk::Hash: 'a,
435+
{
436+
pred(ForEach::Key(&self.pk))
437+
}
438+
}
439+
414440
impl<P: MiniscriptKey, Q: MiniscriptKey> TranslatePk<P, Q> for Wpkh<P> {
415441
type Output = Wpkh<Q>;
416442

src/descriptor/sh.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ use miniscript::context::ScriptContext;
2727
use policy::{semantic, Liftable};
2828
use push_opcode_size;
2929
use util::{varint_len, witness_to_scriptsig};
30-
use {Error, Legacy, Miniscript, MiniscriptKey, Satisfier, Segwitv0, ToPublicKey, TranslatePk};
30+
use {
31+
Error, ForEach, ForEachKey, Legacy, Miniscript, MiniscriptKey, Satisfier, Segwitv0,
32+
ToPublicKey, TranslatePk,
33+
};
3134

3235
use super::{
3336
checksum::{desc_checksum, verify_checksum},
@@ -322,6 +325,21 @@ where
322325
}
323326
}
324327

328+
impl<Pk: MiniscriptKey> ForEachKey<Pk> for Sh<Pk> {
329+
fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, pred: F) -> bool
330+
where
331+
Pk: 'a,
332+
Pk::Hash: 'a,
333+
{
334+
match self.inner {
335+
ShInner::Wsh(ref wsh) => wsh.for_each_key(pred),
336+
ShInner::SortedMulti(ref smv) => smv.for_each_key(pred),
337+
ShInner::Wpkh(ref wpkh) => wpkh.for_each_key(pred),
338+
ShInner::Ms(ref ms) => ms.for_each_key(pred),
339+
}
340+
}
341+
}
342+
325343
impl<P: MiniscriptKey, Q: MiniscriptKey> TranslatePk<P, Q> for Sh<P> {
326344
type Output = Sh<Q>;
327345

src/descriptor/sortedmulti.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use expression;
2424
use miniscript::{self, context::ScriptContext, decode::Terminal};
2525
use policy;
2626
use script_num_size;
27-
use {errstr, Error, Miniscript, MiniscriptKey, Satisfier, ToPublicKey};
27+
use {errstr, Error, ForEach, ForEachKey, Miniscript, MiniscriptKey, Satisfier, ToPublicKey};
2828

2929
/// Contents of a "sortedmulti" descriptor
3030
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
@@ -84,9 +84,7 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> SortedMultiVec<Pk, Ctx> {
8484

8585
pks.map(|pks| SortedMultiVec::new(k as usize, pks))?
8686
}
87-
}
8887

89-
impl<Pk: MiniscriptKey, Ctx: ScriptContext> SortedMultiVec<Pk, Ctx> {
9088
/// This will panic if translatefpk returns an uncompressed key when
9189
/// converting to a Segwit descriptor. To prevent this panic, ensure
9290
/// translatefpk returns an error in this case instead.
@@ -106,6 +104,17 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> SortedMultiVec<Pk, Ctx> {
106104
})
107105
}
108106
}
107+
108+
impl<Pk: MiniscriptKey, Ctx: ScriptContext> ForEachKey<Pk> for SortedMultiVec<Pk, Ctx> {
109+
fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, mut pred: F) -> bool
110+
where
111+
Pk: 'a,
112+
Pk::Hash: 'a,
113+
{
114+
self.pks.iter().all(|key| pred(ForEach::Key(key)))
115+
}
116+
}
117+
109118
impl<Pk: MiniscriptKey, Ctx: ScriptContext> SortedMultiVec<Pk, Ctx> {
110119
/// utility function to sanity a sorted multi vec
111120
pub fn sanity_check(&self) -> Result<(), Error> {

src/lib.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,34 @@ impl<
404404
{
405405
}
406406

407+
/// Either a key or a keyhash
408+
pub enum ForEach<'a, Pk: MiniscriptKey + 'a> {
409+
/// A key
410+
Key(&'a Pk),
411+
/// A keyhash
412+
Hash(&'a Pk::Hash),
413+
}
414+
415+
/// Trait describing the ability to iterate over every key
416+
pub trait ForEachKey<Pk: MiniscriptKey> {
417+
/// Run a predicate on every key in the descriptor, returning whether
418+
/// the predicate returned true for every key
419+
fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, pred: F) -> bool
420+
where
421+
Pk: 'a,
422+
Pk::Hash: 'a;
423+
424+
/// Run a predicate on every key in the descriptor, returning whether
425+
/// the predicate returned true for any key
426+
fn for_any_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, mut pred: F) -> bool
427+
where
428+
Pk: 'a,
429+
Pk::Hash: 'a,
430+
{
431+
!self.for_each_key(|key| !pred(key))
432+
}
433+
}
434+
407435
/// Miniscript
408436
409437
#[derive(Debug)]

src/miniscript/astelem.rs

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ use expression;
3232
use miniscript::types::{self, Property};
3333
use miniscript::ScriptContext;
3434
use script_num_size;
35-
use {Error, Miniscript, MiniscriptKey, Terminal, ToPublicKey, TranslatePk};
35+
use {Error, ForEach, ForEachKey, Miniscript, MiniscriptKey, Terminal, ToPublicKey, TranslatePk};
3636

3737
impl<Pk: MiniscriptKey, Ctx: ScriptContext> Terminal<Pk, Ctx> {
3838
/// Internal helper function for displaying wrapper types; returns
@@ -77,6 +77,49 @@ impl<Pk: MiniscriptKey, Q: MiniscriptKey, Ctx: ScriptContext> TranslatePk<Pk, Q>
7777
}
7878

7979
impl<Pk: MiniscriptKey, Ctx: ScriptContext> Terminal<Pk, Ctx> {
80+
pub(super) fn real_for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(
81+
&'a self,
82+
pred: &mut F,
83+
) -> bool
84+
where
85+
Pk: 'a,
86+
Pk::Hash: 'a,
87+
{
88+
match *self {
89+
Terminal::PkK(ref p) => pred(ForEach::Key(p)),
90+
Terminal::PkH(ref p) => pred(ForEach::Hash(p)),
91+
Terminal::After(..)
92+
| Terminal::Older(..)
93+
| Terminal::Sha256(..)
94+
| Terminal::Hash256(..)
95+
| Terminal::Ripemd160(..)
96+
| Terminal::Hash160(..)
97+
| Terminal::True
98+
| Terminal::False => true,
99+
Terminal::Alt(ref sub)
100+
| Terminal::Swap(ref sub)
101+
| Terminal::Check(ref sub)
102+
| Terminal::DupIf(ref sub)
103+
| Terminal::Verify(ref sub)
104+
| Terminal::NonZero(ref sub)
105+
| Terminal::ZeroNotEqual(ref sub) => sub.real_for_each_key(pred),
106+
Terminal::AndV(ref left, ref right)
107+
| Terminal::AndB(ref left, ref right)
108+
| Terminal::OrB(ref left, ref right)
109+
| Terminal::OrD(ref left, ref right)
110+
| Terminal::OrC(ref left, ref right)
111+
| Terminal::OrI(ref left, ref right) => {
112+
left.real_for_each_key(&mut *pred) && right.real_for_each_key(pred)
113+
}
114+
Terminal::AndOr(ref a, ref b, ref c) => {
115+
a.real_for_each_key(&mut *pred)
116+
&& b.real_for_each_key(&mut *pred)
117+
&& c.real_for_each_key(pred)
118+
}
119+
Terminal::Thresh(_, ref subs) => subs.iter().all(|sub| sub.real_for_each_key(pred)),
120+
Terminal::Multi(_, ref keys) => keys.iter().all(|key| pred(ForEach::Key(key))),
121+
}
122+
}
80123
pub(super) fn real_translate_pk<FPk, FPkh, Q, Error>(
81124
&self,
82125
translatefpk: &mut FPk,
@@ -169,6 +212,16 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Terminal<Pk, Ctx> {
169212
}
170213
}
171214

215+
impl<Pk: MiniscriptKey, Ctx: ScriptContext> ForEachKey<Pk> for Terminal<Pk, Ctx> {
216+
fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, mut pred: F) -> bool
217+
where
218+
Pk: 'a,
219+
Pk::Hash: 'a,
220+
{
221+
self.real_for_each_key(&mut pred)
222+
}
223+
}
224+
172225
impl<Pk: MiniscriptKey, Ctx: ScriptContext> fmt::Debug for Terminal<Pk, Ctx> {
173226
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
174227
f.write_str("[")?;

src/miniscript/mod.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ use miniscript::types::Type;
5252
use std::cmp;
5353
use std::sync::Arc;
5454
use MiniscriptKey;
55-
use {expression, Error, ToPublicKey, TranslatePk};
55+
use {expression, Error, ForEach, ForEachKey, ToPublicKey, TranslatePk};
5656

5757
/// Top-level script AST type
5858
#[derive(Clone, Hash)]
@@ -230,6 +230,16 @@ impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
230230
}
231231
}
232232

233+
impl<Pk: MiniscriptKey, Ctx: ScriptContext> ForEachKey<Pk> for Miniscript<Pk, Ctx> {
234+
fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, mut pred: F) -> bool
235+
where
236+
Pk: 'a,
237+
Pk::Hash: 'a,
238+
{
239+
self.real_for_each_key(&mut pred)
240+
}
241+
}
242+
233243
impl<Pk: MiniscriptKey, Q: MiniscriptKey, Ctx: ScriptContext> TranslatePk<Pk, Q>
234244
for Miniscript<Pk, Ctx>
235245
{
@@ -252,6 +262,14 @@ impl<Pk: MiniscriptKey, Q: MiniscriptKey, Ctx: ScriptContext> TranslatePk<Pk, Q>
252262
}
253263

254264
impl<Pk: MiniscriptKey, Ctx: ScriptContext> Miniscript<Pk, Ctx> {
265+
fn real_for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, pred: &mut F) -> bool
266+
where
267+
Pk: 'a,
268+
Pk::Hash: 'a,
269+
{
270+
self.node.real_for_each_key(pred)
271+
}
272+
255273
fn real_translate_pk<FPk, FPkh, Q, FuncError>(
256274
&self,
257275
translatefpk: &mut FPk,

src/policy/concrete.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use policy::compiler;
3333
use policy::compiler::CompilerError;
3434
#[cfg(feature = "compiler")]
3535
use Miniscript;
36-
use {Error, MiniscriptKey};
36+
use {Error, ForEach, ForEachKey, MiniscriptKey};
3737
/// Concrete policy which corresponds directly to a Miniscript structure,
3838
/// and whose disjunctions are annotated with satisfaction probabilities
3939
/// to assist the compiler
@@ -140,6 +140,29 @@ impl<Pk: MiniscriptKey> Policy<Pk> {
140140
}
141141
}
142142

143+
impl<Pk: MiniscriptKey> ForEachKey<Pk> for Policy<Pk> {
144+
fn for_each_key<'a, F: FnMut(ForEach<'a, Pk>) -> bool>(&'a self, mut pred: F) -> bool
145+
where
146+
Pk: 'a,
147+
Pk::Hash: 'a,
148+
{
149+
match *self {
150+
Policy::Unsatisfiable | Policy::Trivial => true,
151+
Policy::Key(ref pk) => pred(ForEach::Key(pk)),
152+
Policy::Sha256(..)
153+
| Policy::Hash256(..)
154+
| Policy::Ripemd160(..)
155+
| Policy::Hash160(..)
156+
| Policy::After(..)
157+
| Policy::Older(..) => true,
158+
Policy::Threshold(_, ref subs) | Policy::And(ref subs) => {
159+
subs.iter().all(|sub| sub.for_each_key(&mut pred))
160+
}
161+
Policy::Or(ref subs) => subs.iter().all(|(_, sub)| sub.for_each_key(&mut pred)),
162+
}
163+
}
164+
}
165+
143166
impl<Pk: MiniscriptKey> Policy<Pk> {
144167
/// Convert a policy using one kind of public key to another
145168
/// type of public key

0 commit comments

Comments
 (0)