refactor: remove SortedMultiVec and use Terminal::SortedMulti#915
refactor: remove SortedMultiVec and use Terminal::SortedMulti#915apoelstra merged 1 commit intorust-bitcoin:masterfrom
Conversation
2c77295 to
9b0b1c0
Compare
|
(CI is failing because the integration tests don't compile) Hmmmm, okay, this seems reasonable enough to me. Does Core allow |
Working on fixing the integration tests now! Will ping you when it's ready, my bad. |
9b0b1c0 to
816620a
Compare
| Descriptor::Sh(sh) => match sh.as_inner() { | ||
| miniscript::descriptor::ShInner::Wsh(wsh) => match wsh.as_inner() { | ||
| miniscript::descriptor::WshInner::SortedMulti(ref smv) => { | ||
| let ms = Miniscript::from_ast(smv.sorted_node()).unwrap(); |
There was a problem hiding this comment.
The key point here was to call sorted_node() and now we don't have something so convenient. See the HACK in find_sks_ms
There was a problem hiding this comment.
Interesting. So, the issue is that we want to get all the keys in the descriptor, in the order they'd be needed, and we're using pk_iter for this. Since pk_iter can't sort the keys, we have to sort them after the fact.
This is a bit of a weird thing to desire -- does this test actually fail without this? It seems like we never use the ordering of sks_reqd. In fact, we lose the ordering because we iterate over it, produce signatures, then stick them into the BTreeMap psbt.inputs[0].partial_sigs.
Also, since #910 I think the logic in this example is actually wrong, or at least inconsistent -- it would sort sortedmulti but not sortedmulti_a. And your hack doesn't change this.
So can we just drop the sortedmulti logic here and treat sortedmulti like multi?
| ShInner::Wsh(ref wsh) => { | ||
| let ms = wsh.as_inner(); | ||
| if let Terminal::SortedMulti(ref thresh) = ms.node { | ||
| PkIter::from_sortedmulti(thresh.data()) |
There was a problem hiding this comment.
Cannot call thresh.into_sorted_bip67() due to lacking ToPublicKey on Pk here. It would clean up the integration test changes (. I'm sure it would be useful for users as well.HACK)
There was a problem hiding this comment.
Right -- I get the desire that pk_iter return the keys in the correct order. But as you note, without a ToPublicKey bound, we don't actually know the correct order (and the user might not either, e.g. if there are wildcards in the keys).
We also can't make this do the right thing for ToPublicKey keys because Rust lacks specialization. (There are tons of places in this crate where we suffer from this, and you'll find that if you keep trying to clean stuff up, you will run into missing language features basically every single time.)
I think we need to just live with this.
There was a problem hiding this comment.
There are tons of places in this crate where we suffer from this, and you'll find that if you keep trying to clean stuff up, you will run into missing language features basically every single time.
@apoelstra don't worry, in 2035 when specialization stabilizes we can get to it!
| } | ||
|
|
||
| #[test] | ||
| fn too_many_pubkeys_for_p2sh() { |
There was a problem hiding this comment.
FYI: migrated from deleted sortedmulti.rs file.
| let mut witness = match self.inner { | ||
| WshInner::SortedMulti(ref smv) => smv.satisfy(satisfier)?, | ||
| WshInner::Ms(ref ms) => ms.satisfy_malleable(satisfier)?, | ||
| let mut witness = if let Terminal::SortedMulti(..) = self.ms.node { |
There was a problem hiding this comment.
All the if let Terminal::SortedMulti(..)'s are kind of bothering me.
Does it make sense to add a function on Miniscript called is_sortedmulti() or something?
There was a problem hiding this comment.
Probably yes, but I'm curious what the heck is going on here. Why are we calling the non-malleable satisfier for sortedmultis? (What I suspect is: the old SortedMultiVec type had a satisfy method but no satisfy_malleable method, presumably because for multisigs, malleability is irrelevant. We needed to branch because SortedMultiVec is a distinct type, and then the branch wound up looking sus with one side saying satisfy and the other side saying satisfy_malleable, just because of this API gap.)
SO I think that in this PR, we just always want to call self.ms.satisfy_malleable, and not branch at all.
There was a problem hiding this comment.
I based it off of this, which is from the deleted SortedMultiVec.
- /// Attempt to produce a satisfying witness for the
- /// witness script represented by the parse tree
- pub fn satisfy<S>(&self, satisfier: S) -> Result<Vec<Vec<u8>>, Error>
- where
- Pk: ToPublicKey,
- S: Satisfier<Pk>,
- {
- let ms = Miniscript::from_ast(self.sorted_node()).expect("Multi node typecheck");
- ms.satisfy(satisfier)We needed to branch because SortedMultiVec is a distinct type, and then the branch wound up looking sus with one side saying satisfy and the other side saying satisfy_malleable, just because of this API gap.
I don't think I could have guessed that lol...trusting you and changing to only call satisfy_malleable
|
@apoelstra did a self-review with some questions. Let me know what you think, thanks! |
|
816620a needs rebase |
816620a to
f9d0bdd
Compare
|
f9d0bdd needs rebase |
b4d73ec to
366974f
Compare
| ShInner::Wsh(ref wsh) => { | ||
| let ms = wsh.as_inner(); | ||
| if let Terminal::SortedMulti(ref thresh) = ms.node { | ||
| PkIter::from_sortedmulti(thresh.data()) |
There was a problem hiding this comment.
There are tons of places in this crate where we suffer from this, and you'll find that if you keep trying to clean stuff up, you will run into missing language features basically every single time.
@apoelstra don't worry, in 2035 when specialization stabilizes we can get to it!
| let mut witness = match self.inner { | ||
| WshInner::SortedMulti(ref smv) => smv.satisfy(satisfier)?, | ||
| WshInner::Ms(ref ms) => ms.satisfy_malleable(satisfier)?, | ||
| let mut witness = if let Terminal::SortedMulti(..) = self.ms.node { |
There was a problem hiding this comment.
I based it off of this, which is from the deleted SortedMultiVec.
- /// Attempt to produce a satisfying witness for the
- /// witness script represented by the parse tree
- pub fn satisfy<S>(&self, satisfier: S) -> Result<Vec<Vec<u8>>, Error>
- where
- Pk: ToPublicKey,
- S: Satisfier<Pk>,
- {
- let ms = Miniscript::from_ast(self.sorted_node()).expect("Multi node typecheck");
- ms.satisfy(satisfier)We needed to branch because SortedMultiVec is a distinct type, and then the branch wound up looking sus with one side saying satisfy and the other side saying satisfy_malleable, just because of this API gap.
I don't think I could have guessed that lol...trusting you and changing to only call satisfy_malleable
| | Terminal::Multi(_) | ||
| | Terminal::SortedMulti(_) | ||
| | Terminal::MultiA(_) | ||
| | Terminal::SortedMultiA(_) => { |
There was a problem hiding this comment.
Saw SortedMultiA was also missing from this.
| match (&self.node, n) { | ||
| (Terminal::PkK(key), 0) | (Terminal::PkH(key), 0) => Some(key.clone()), | ||
| (Terminal::Multi(thresh), _) => thresh.data().get(n).cloned(), | ||
| (Terminal::SortedMulti(thresh), _) => thresh.data().get(n).cloned(), |
There was a problem hiding this comment.
I missed this on the first iteration since type-driven development failed me with the _ => fallback.
@apoelstra It resolves the HACK that was mentioned in this comment.
| Terminal::Multi(ref thresh) | Terminal::SortedMulti(ref thresh) | ||
| if !thresh.iter().all(&mut pred) => | ||
| { |
366974f to
941205b
Compare
febyeji
left a comment
There was a problem hiding this comment.
I left a couple of comments. One on missing SortedMulti arms in context.rs and one stale comment nit.
941205b to
a65deea
Compare
Thanks again, @febyeji ! Can't believe I missed so many match arms 😞 |
| ShInner::Wsh(ref wsh) => { | ||
| let ms = wsh.as_inner(); | ||
| if let Terminal::SortedMulti(ref thresh) = ms.node { | ||
| PkIter::from_sortedmulti(thresh.data()) |
There was a problem hiding this comment.
In a65deea:
Here, and below, you can just delete the from_sortedmulti method and get rid of this branch. It is now covered by the from_miniscript_* methods.
| }, | ||
| ShInner::Wsh(ref wsh) => { | ||
| if let Terminal::SortedMulti(..) = wsh.as_inner().node { | ||
| DescriptorType::ShWshSortedMulti |
There was a problem hiding this comment.
In a65deea:
As a followup let's maybe delete this from DescriptorType since it's no longer a distinct kind of descriptor. But let's not do it here since it'd be an API-breaking change and I'm not certain that we want to do it.
|
Done reviewing a65deea. All good except the iterpk thing. Frustrating how many |
- Utilize the Miniscript parsing to handle sortedmulti as a Terminal. - Deleted sortedmulti.rs (SortedMultiVec) - Refactor Wsh to only wrap a Miniscript now that SortedMultiVec isn't used. - Refactor ShInner to remove SortedMulti variant and only use the Ms variant for sortedmulti scripts
a65deea to
01d25c1
Compare
|
Nice :) great to see such a red diff. |
| } | ||
| } | ||
| Terminal::Multi(ref thresh) => { | ||
| Terminal::Multi(ref thresh) | Terminal::SortedMulti(ref thresh) => { |
There was a problem hiding this comment.
Oops, I missed this -- in this case we need to change the logic. In SortedMultiA we have special logic to sort keys, but in SortedMulti we don't.
We should also add a test case for this.
There was a problem hiding this comment.
I will fix this in #895 -- though if you have an earlier fix I'd appreciate since that PR is likely to be in limbo for at least several more weeks.
There was a problem hiding this comment.
Yes, big oversight on my part...I will fix that and a test. I guess we test it in the bitcoind tests but not using our own satisfier.
3f20a69 fix: add sorting to satisfy_helper for sortedmulti (Trevor Arjeski) Pull request description: This logic was done in sortedmulti_a but accidentally overlooked when refactoring sortedmulti. Wrote a test that proves two differently ordered sortedmulti descriptors produce the same witness. Found by Andrew in #915 (comment) ACKs for top commit: apoelstra: ACK 3f20a69; successfully ran local tests Tree-SHA512: f81642afeb8415aec564260d352176cf479f316fae1e07f2b9d455449d4749224c0bb05b51f7836718d43cdfe59387062596d4282c9b208bb1b2ae651e19da79
sortedmulti scripts
Now that sortedmulti_a is supported as a Terminal, I think it makes sense to
move sortedmulti over in the same way by following what multi does and applying
the sorting functions that were introduced in eba1aff.
Like sortedmulti_a, sortedmulti is sorted upon encoding and cannot be decoded
into from Script.