-
Notifications
You must be signed in to change notification settings - Fork 154
Add Descriptor::iter_pk() #821
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Interesting about the Taproot internal key appearing last instead of first. Agreed that is weird and it was probably just an accident. In general I also don't remember why we did this "internal iteration" API with Anyway concept ACK adding If you're feeling motivated, can you think through what the "API for accessing, collecting and mapping keys" should look like? If not I'll give it a shot and open a mega-PR sometime in the coming weeks. If all you want is |
Thanks.
Here is a snippet to implement |
I misread this at first and now see that you asked me to do it 😄 I can give it a shot. What's the reason for backporting it? Is a 13.x release far out? |
@benma yeah, I think 13.x is fairly far out -- we've made some really big, but incomplete, changes to the main And so far everyone who has requested changes has done so in a way where we can just backport to 12.x, so there's been no pressure.. |
And I did ask you to do it, but if you don't I'll probably get around to making an issue in the next week or so :) |
I am trying to do it with a proper iterator, but am finding it very hard to wrestle with the iterator types. Maybe my approach is totally wrong. In pub fn iter_pk(&self) -> ??? {
core::iter::once(self.internal_key.clone())
.chain(self.leaves().flat_map(|leaf| leaf.miniscript().iter_pk()))
} In descriptor/mod.rs: impl<Pk: MiniscriptKey> Descriptor<Pk> {
pub fn iter_pk(&self) -> PkIter<Pk> { PkIter::new(self) }
}
pub enum PkIter<Pk: MiniscriptKey> {
Once(core::iter::Once<Pk>),
Tr(???),
}
impl<Pk: MiniscriptKey> PkIter<Pk> {
fn new(descriptor: &Descriptor<Pk>) -> Self {
match descriptor {
Descriptor::Bare(bare) => todo!(),
Descriptor::Pkh(pkh) => PkIter::Once(pkh.iter_pk()),
Descriptor::Wpkh(wpkh) => PkIter::Once(wpkh.iter_pk()),
Descriptor::Sh(sh) => todo!(),
Descriptor::Wsh(wsh) => todo!(),
Descriptor::Tr(tr) => PkIter::Tr(tr.iter_pk()),
}
}
}
impl<Pk: MiniscriptKey> Iterator for PkIter<Pk> {
type Item = Pk;
fn next(&mut self) -> Option<Self::Item> {
match self {
PkIter::Once(iter) => iter.next(),
PkIter::Tr(iter) => iter.next(),
}
}
} But I can't figure out the type of Long story short, I'd be happy if you could do it instead, let me know if that is okay for you. |
For sure, I'll give it a shot. Though I can tell you that you won't be able to use In this library I'm not that opposed to 'Box |
What does What prevents the use of struct ExactSize<T> {
iterator: Box<dyn Iterator<Item = T>>,
remaining: usize,
}
impl<T> ExactSize<T> {
fn new(iterator: Box<dyn Iterator<Item = T>>, len: usize) -> Self {
ExactSize {
iterator,
remaining: len,
}
}
}
impl<T> Iterator for ExactSize<T> {
type Item = T;
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
match self.iterator.next() {
item @ Some(_) => {
self.remaining -= 1;
item
}
None => None,
}
}
} If the use of // in tr.rs
pub fn iter_pk(&self) -> impl Iterator<Item = Pk> + '_ {
core::iter::once(self.internal_key.clone())
.chain(self.leaves().flat_map(|leaf| leaf.miniscript().iter_pk()))
}
// in descriptor/mod.rs:
pub fn iter_pk(&self) -> Box<dyn Iterator<Item = Pk> + '_> {
match self {
Descriptor::Pkh(pk) => Box::new(pk.iter_pk()),
Descriptor::Wpkh(pk) => Box::new(pk.iter_pk()),
Descriptor::Tr(tr) => Box::new(tr.iter_pk()),
_ => todo!(), // etc.
}
} |
@apoelstra how about something like this? https://github.com/benma/rust-miniscript/commit/iter_pk/ Feel free to pick this commit up and adapt it as you see fit, or to throw it away and go with manually writing the custom iterators. |
No, a I'm not sure what you're getting at with the
|
Note that the commit I linked above does not deal with My point was that the use of Box (to be able to use chain/flat_map etc. without manually emulating them) in my commit (with some changes to return a wrapper struct instead) does not prevent implementing |
I really don't understand what you're saying. What is "use of Box (to be able to use chain/flat_map etc. without manually emulating them)" if not the use of |
Yeah it's confusing, apologies. We don't need to spend much more time here, just to wrap it up: When you said
I just thought that was not generally correct. For clarity, here is a commit thatt uses Box and implements ExactSizeIterator: Box here: The The descriptor PkIter also implements ExactSizeIterator. pk_iter() just needs to precompute the number of keys, where I inserted a But I can see that this is not very composable or nice, and it's also possible I am completely missing your point 😅 So let's shelve this discussion about Boxes and I'll be looking forward to your implementation. |
Ok, I understand what you mean now. However, I would definitely not accept code like this. If you are implementing an iterator trait for a struct wrapping an iterator, you should always pass through to the inner iterator. e.g. What you've written here is equivalent
Sounds good! |
I think the reason this hasn't existed before is that the For 12.x I am tempted to just box it and not support any traits except |
Uh oh!
There was an error while loading. Please reload this page.
Hi
I am looking for a way to gather all descriptor keys into a vector.
On Miniscript, it exists:
https://docs.rs/miniscript/12.3.2/miniscript/miniscript/struct.Miniscript.html#method.iter_pk
For descriptors, there is for_each_key and for_any_key which could be (ab)used to collect the keys into a vector, but that is not ideal.
Edit: related, why are for_each_key/for_any_key iterating over the Taproot leaf script keys before the internal key? It seems more natural to iterate the keys from left-to-right as they appear in the descriptor string. This is also a requirement if one wants to convert it to a BIP-388 wallet policy.
The text was updated successfully, but these errors were encountered: