Skip to content

Commit 9a9f9b1

Browse files
committed
Merge #823: Add Descriptor::iter_pk
aa42cd3 descriptor: add unit tests for iter_pk (Andrew Poelstra) 523654e descriptor: add Descriptor::iter_pk (Andrew Poelstra) Pull request description: Fixes #821. Should backport to 12.x. ACKs for top commit: sanket1729: ACK aa42cd3 Tree-SHA512: 15a5aa6f6d0d7ea5773cdecd4a67320ee89027eaf178c44ad7e1d1465752eb95d835c3dcf1dbb734302e826deeb13803178c7999e15bce710c5fd4dc31c876d6
2 parents 5b862b5 + aa42cd3 commit 9a9f9b1

File tree

2 files changed

+321
-0
lines changed

2 files changed

+321
-0
lines changed

src/descriptor/iter.rs

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
// SPDX-License-Identifier: CC0-1.0
2+
3+
//! Iterators over descriptors
4+
5+
use crate::descriptor::{TapTreeIter, Tr};
6+
use crate::miniscript::context::{BareCtx, Legacy, Segwitv0, Tap};
7+
use crate::{miniscript, Miniscript, MiniscriptKey};
8+
9+
/// Iterator over all the keys in a descriptor.
10+
pub struct PkIter<'desc, Pk: MiniscriptKey> {
11+
single_key: Option<Pk>,
12+
taptree_iter: Option<TapTreeIter<'desc, Pk>>,
13+
ms_iter_bare: Option<miniscript::iter::PkIter<'desc, Pk, BareCtx>>,
14+
ms_iter_legacy: Option<miniscript::iter::PkIter<'desc, Pk, Legacy>>,
15+
ms_iter_segwit: Option<miniscript::iter::PkIter<'desc, Pk, Segwitv0>>,
16+
ms_iter_taproot: Option<miniscript::iter::PkIter<'desc, Pk, Tap>>,
17+
sorted_multi: Option<core::slice::Iter<'desc, Pk>>,
18+
}
19+
20+
impl<'desc, Pk: MiniscriptKey> PkIter<'desc, Pk> {
21+
pub(super) fn from_key(pk: Pk) -> Self {
22+
Self {
23+
single_key: Some(pk),
24+
taptree_iter: None,
25+
ms_iter_bare: None,
26+
ms_iter_legacy: None,
27+
ms_iter_segwit: None,
28+
ms_iter_taproot: None,
29+
sorted_multi: None,
30+
}
31+
}
32+
33+
pub(super) fn from_miniscript_bare(ms: &'desc Miniscript<Pk, BareCtx>) -> Self {
34+
Self {
35+
single_key: None,
36+
taptree_iter: None,
37+
ms_iter_bare: Some(ms.iter_pk()),
38+
ms_iter_legacy: None,
39+
ms_iter_segwit: None,
40+
ms_iter_taproot: None,
41+
sorted_multi: None,
42+
}
43+
}
44+
45+
pub(super) fn from_miniscript_legacy(ms: &'desc Miniscript<Pk, Legacy>) -> Self {
46+
Self {
47+
single_key: None,
48+
taptree_iter: None,
49+
ms_iter_bare: None,
50+
ms_iter_legacy: Some(ms.iter_pk()),
51+
ms_iter_segwit: None,
52+
ms_iter_taproot: None,
53+
sorted_multi: None,
54+
}
55+
}
56+
57+
pub(super) fn from_miniscript_segwit(ms: &'desc Miniscript<Pk, Segwitv0>) -> Self {
58+
Self {
59+
single_key: None,
60+
taptree_iter: None,
61+
ms_iter_bare: None,
62+
ms_iter_legacy: None,
63+
ms_iter_segwit: Some(ms.iter_pk()),
64+
ms_iter_taproot: None,
65+
sorted_multi: None,
66+
}
67+
}
68+
69+
pub(super) fn from_sortedmulti(sm: &'desc [Pk]) -> Self {
70+
Self {
71+
single_key: None,
72+
taptree_iter: None,
73+
ms_iter_bare: None,
74+
ms_iter_legacy: None,
75+
ms_iter_segwit: None,
76+
ms_iter_taproot: None,
77+
sorted_multi: Some(sm.iter()),
78+
}
79+
}
80+
81+
pub(super) fn from_tr(tr: &'desc Tr<Pk>) -> Self {
82+
Self {
83+
single_key: Some(tr.internal_key().clone()),
84+
taptree_iter: Some(tr.leaves()),
85+
ms_iter_bare: None,
86+
ms_iter_legacy: None,
87+
ms_iter_segwit: None,
88+
ms_iter_taproot: None,
89+
sorted_multi: None,
90+
}
91+
}
92+
}
93+
94+
impl<'desc, Pk: MiniscriptKey> Iterator for PkIter<'desc, Pk> {
95+
type Item = Pk;
96+
97+
#[rustfmt::skip] // the tower of .or_elses looks good as is
98+
fn next(&mut self) -> Option<Self::Item> {
99+
// If there is a single key, return it first. (This will be the case
100+
// for all single-key-only iterators but also for Taproot, where the
101+
// single key is the root key.)
102+
if let Some(k) = self.single_key.take() {
103+
return Some(k.clone());
104+
}
105+
106+
// Then attempt to yield something from the Taptree iterator.
107+
loop {
108+
if let Some(item) = self.ms_iter_taproot.as_mut().and_then(Iterator::next) {
109+
return Some(item);
110+
}
111+
if let Some(iter) = self.taptree_iter.as_mut().and_then(Iterator::next) {
112+
self.ms_iter_taproot = Some(iter.miniscript().iter_pk());
113+
} else {
114+
break;
115+
}
116+
}
117+
118+
// Finally run through the train of other iterators.
119+
self.ms_iter_bare.as_mut().and_then(Iterator::next).or_else(
120+
|| self.ms_iter_legacy.as_mut().and_then(Iterator::next).or_else(
121+
|| self.ms_iter_segwit.as_mut().and_then(Iterator::next).or_else(
122+
|| self.sorted_multi.as_mut().and_then(Iterator::next).cloned()
123+
)
124+
)
125+
)
126+
}
127+
}

src/descriptor/mod.rs

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,15 @@ use crate::{
3232
};
3333

3434
mod bare;
35+
mod iter;
3536
mod segwitv0;
3637
mod sh;
3738
mod sortedmulti;
3839
mod tr;
3940

4041
// Descriptor Exports
4142
pub use self::bare::{Bare, Pkh};
43+
pub use self::iter::PkIter;
4244
pub use self::segwitv0::{Wpkh, Wsh, WshInner};
4345
pub use self::sh::{Sh, ShInner};
4446
pub use self::sortedmulti::SortedMultiVec;
@@ -241,6 +243,29 @@ impl<Pk: MiniscriptKey> Descriptor<Pk> {
241243
Ok(Descriptor::Tr(Tr::new(key, script)?))
242244
}
243245

246+
/// An iterator over all the keys referenced in the descriptor.
247+
pub fn iter_pk(&self) -> PkIter<'_, Pk> {
248+
match *self {
249+
Descriptor::Bare(ref bare) => PkIter::from_miniscript_bare(bare.as_inner()),
250+
Descriptor::Pkh(ref pk) => PkIter::from_key(pk.as_inner().clone()),
251+
Descriptor::Wpkh(ref pk) => PkIter::from_key(pk.as_inner().clone()),
252+
Descriptor::Sh(ref sh) => match *sh.as_inner() {
253+
ShInner::Wsh(ref wsh) => match wsh.as_inner() {
254+
WshInner::SortedMulti(ref sorted) => PkIter::from_sortedmulti(sorted.pks()),
255+
WshInner::Ms(ref ms) => PkIter::from_miniscript_segwit(ms),
256+
},
257+
ShInner::Wpkh(ref pk) => PkIter::from_key(pk.as_inner().clone()),
258+
ShInner::SortedMulti(ref sorted) => PkIter::from_sortedmulti(sorted.pks()),
259+
ShInner::Ms(ref ms) => PkIter::from_miniscript_legacy(ms),
260+
},
261+
Descriptor::Wsh(ref wsh) => match wsh.as_inner() {
262+
WshInner::SortedMulti(ref sorted) => PkIter::from_sortedmulti(sorted.pks()),
263+
WshInner::Ms(ref ms) => PkIter::from_miniscript_segwit(ms),
264+
},
265+
Descriptor::Tr(ref tr) => PkIter::from_tr(tr),
266+
}
267+
}
268+
244269
/// For a Taproot descriptor, returns the internal key.
245270
pub fn internal_key(&self) -> Option<&Pk> {
246271
if let Descriptor::Tr(ref tr) = self {
@@ -2237,4 +2262,173 @@ pk(03f28773c2d975288bc7d1d205c3748651b075fbc6610e58cddeeddf8f19405aa8))";
22372262

22382263
assert_eq!(xonly_pk_descriptor.to_string(), xonly_converted_descriptor.to_string());
22392264
}
2265+
2266+
#[test]
2267+
fn test_iter_pk() {
2268+
// Test Bare descriptor
2269+
let bare_desc = Descriptor::<PublicKey>::from_str(
2270+
"pk(020000000000000000000000000000000000000000000000000000000000000002)",
2271+
)
2272+
.unwrap();
2273+
let keys: Vec<_> = bare_desc.iter_pk().collect();
2274+
assert_eq!(keys.len(), 1);
2275+
assert_eq!(
2276+
keys[0].to_string(),
2277+
"020000000000000000000000000000000000000000000000000000000000000002"
2278+
);
2279+
2280+
// Test Pkh descriptor
2281+
let pkh_desc = Descriptor::<PublicKey>::from_str(
2282+
"pkh(020000000000000000000000000000000000000000000000000000000000000002)",
2283+
)
2284+
.unwrap();
2285+
let keys: Vec<_> = pkh_desc.iter_pk().collect();
2286+
assert_eq!(keys.len(), 1);
2287+
assert_eq!(
2288+
keys[0].to_string(),
2289+
"020000000000000000000000000000000000000000000000000000000000000002"
2290+
);
2291+
2292+
// Test Wpkh descriptor
2293+
let wpkh_desc = Descriptor::<PublicKey>::from_str(
2294+
"wpkh(020000000000000000000000000000000000000000000000000000000000000002)",
2295+
)
2296+
.unwrap();
2297+
let keys: Vec<_> = wpkh_desc.iter_pk().collect();
2298+
assert_eq!(keys.len(), 1);
2299+
assert_eq!(
2300+
keys[0].to_string(),
2301+
"020000000000000000000000000000000000000000000000000000000000000002"
2302+
);
2303+
2304+
// Test Sh descriptor with a miniscript
2305+
let sh_desc = Descriptor::<PublicKey>::from_str(
2306+
"sh(or_d(pk(021d4ea7132d4e1a362ee5efd8d0b59dd4d1fe8906eefa7dd812b05a46b73d829b),pk(0302c8bbbb393f32c843149ce36d56405595aaabab2d0e1f4ca5f9de67dd7419f6)))"
2307+
).unwrap();
2308+
let keys: Vec<_> = sh_desc.iter_pk().collect();
2309+
assert_eq!(keys.len(), 2);
2310+
assert_eq!(
2311+
keys[0].to_string(),
2312+
"021d4ea7132d4e1a362ee5efd8d0b59dd4d1fe8906eefa7dd812b05a46b73d829b"
2313+
);
2314+
assert_eq!(
2315+
keys[1].to_string(),
2316+
"0302c8bbbb393f32c843149ce36d56405595aaabab2d0e1f4ca5f9de67dd7419f6"
2317+
);
2318+
2319+
// Test Sh-Wpkh descriptor
2320+
let shwpkh_desc = Descriptor::<PublicKey>::from_str(
2321+
"sh(wpkh(020000000000000000000000000000000000000000000000000000000000000002))",
2322+
)
2323+
.unwrap();
2324+
let keys: Vec<_> = shwpkh_desc.iter_pk().collect();
2325+
assert_eq!(keys.len(), 1);
2326+
assert_eq!(
2327+
keys[0].to_string(),
2328+
"020000000000000000000000000000000000000000000000000000000000000002"
2329+
);
2330+
2331+
// Test Sh-Wsh descriptor
2332+
let shwsh_desc = Descriptor::<PublicKey>::from_str(
2333+
"sh(wsh(or_d(pk(021d4ea7132d4e1a362ee5efd8d0b59dd4d1fe8906eefa7dd812b05a46b73d829b),pk(0302c8bbbb393f32c843149ce36d56405595aaabab2d0e1f4ca5f9de67dd7419f6))))"
2334+
).unwrap();
2335+
let keys: Vec<_> = shwsh_desc.iter_pk().collect();
2336+
assert_eq!(keys.len(), 2);
2337+
assert_eq!(
2338+
keys[0].to_string(),
2339+
"021d4ea7132d4e1a362ee5efd8d0b59dd4d1fe8906eefa7dd812b05a46b73d829b"
2340+
);
2341+
assert_eq!(
2342+
keys[1].to_string(),
2343+
"0302c8bbbb393f32c843149ce36d56405595aaabab2d0e1f4ca5f9de67dd7419f6"
2344+
);
2345+
2346+
// Test Wsh descriptor
2347+
let wsh_desc = Descriptor::<PublicKey>::from_str(
2348+
"wsh(or_d(pk(021d4ea7132d4e1a362ee5efd8d0b59dd4d1fe8906eefa7dd812b05a46b73d829b),pk(0302c8bbbb393f32c843149ce36d56405595aaabab2d0e1f4ca5f9de67dd7419f6)))"
2349+
).unwrap();
2350+
let keys: Vec<_> = wsh_desc.iter_pk().collect();
2351+
assert_eq!(keys.len(), 2);
2352+
assert_eq!(
2353+
keys[0].to_string(),
2354+
"021d4ea7132d4e1a362ee5efd8d0b59dd4d1fe8906eefa7dd812b05a46b73d829b"
2355+
);
2356+
assert_eq!(
2357+
keys[1].to_string(),
2358+
"0302c8bbbb393f32c843149ce36d56405595aaabab2d0e1f4ca5f9de67dd7419f6"
2359+
);
2360+
2361+
// Test SortedMulti descriptors
2362+
let sortedmulti_desc = Descriptor::<PublicKey>::from_str(
2363+
"sh(sortedmulti(2,021d4ea7132d4e1a362ee5efd8d0b59dd4d1fe8906eefa7dd812b05a46b73d829b,0302c8bbbb393f32c843149ce36d56405595aaabab2d0e1f4ca5f9de67dd7419f6,03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556))"
2364+
).unwrap();
2365+
let keys: Vec<_> = sortedmulti_desc.iter_pk().collect();
2366+
assert_eq!(keys.len(), 3);
2367+
// Keys are sorted in the output
2368+
assert!(keys.iter().any(|k| k.to_string()
2369+
== "021d4ea7132d4e1a362ee5efd8d0b59dd4d1fe8906eefa7dd812b05a46b73d829b"));
2370+
assert!(keys.iter().any(|k| k.to_string()
2371+
== "0302c8bbbb393f32c843149ce36d56405595aaabab2d0e1f4ca5f9de67dd7419f6"));
2372+
assert!(keys.iter().any(|k| k.to_string()
2373+
== "03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556"));
2374+
2375+
// Test Taproot descriptor with only key path
2376+
let tr_key_only_desc = Descriptor::<PublicKey>::from_str(
2377+
"tr(020000000000000000000000000000000000000000000000000000000000000002)",
2378+
)
2379+
.unwrap();
2380+
let keys: Vec<_> = tr_key_only_desc.iter_pk().collect();
2381+
assert_eq!(keys.len(), 1);
2382+
assert_eq!(
2383+
keys[0].to_string(),
2384+
"020000000000000000000000000000000000000000000000000000000000000002"
2385+
);
2386+
2387+
// Test Taproot descriptor with script path
2388+
// The internal key should be yielded first
2389+
let internal_key = "020000000000000000000000000000000000000000000000000000000000000002";
2390+
let script_key1 = "021d4ea7132d4e1a362ee5efd8d0b59dd4d1fe8906eefa7dd812b05a46b73d829b";
2391+
let script_key2 = "0302c8bbbb393f32c843149ce36d56405595aaabab2d0e1f4ca5f9de67dd7419f6";
2392+
2393+
let tr_with_script_desc = Descriptor::<PublicKey>::from_str(&format!(
2394+
"tr({},{{pk({}),pk({})}})",
2395+
internal_key, script_key1, script_key2,
2396+
))
2397+
.unwrap();
2398+
2399+
let keys: Vec<_> = tr_with_script_desc.iter_pk().collect();
2400+
assert_eq!(keys.len(), 3);
2401+
2402+
// Verify internal key is first
2403+
assert_eq!(keys[0].to_string(), internal_key);
2404+
2405+
// Verify other keys are present (order after internal key is not guaranteed)
2406+
assert!(keys[1..].iter().any(|k| k.to_string() == script_key1));
2407+
assert!(keys[1..].iter().any(|k| k.to_string() == script_key2));
2408+
2409+
// Test Taproot descriptor with complex script tree
2410+
let tr_complex_desc = Descriptor::<PublicKey>::from_str(&format!(
2411+
"tr({},{{pk({}),{{pk({}),or_d(pk({}),pk({}))}}}})",
2412+
internal_key,
2413+
script_key1,
2414+
script_key2,
2415+
"03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556",
2416+
"0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352"
2417+
))
2418+
.unwrap();
2419+
2420+
let keys: Vec<_> = tr_complex_desc.iter_pk().collect();
2421+
assert_eq!(keys.len(), 5);
2422+
2423+
// Verify internal key is first
2424+
assert_eq!(keys[0].to_string(), internal_key);
2425+
2426+
// Verify all other keys are present
2427+
assert!(keys[1..].iter().any(|k| k.to_string() == script_key1));
2428+
assert!(keys[1..].iter().any(|k| k.to_string() == script_key2));
2429+
assert!(keys[1..].iter().any(|k| k.to_string()
2430+
== "03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556"));
2431+
assert!(keys[1..].iter().any(|k| k.to_string()
2432+
== "0250863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b2352"));
2433+
}
22402434
}

0 commit comments

Comments
 (0)