Fix TapTree hidden branches bug#929
Fix TapTree hidden branches bug#929apoelstra merged 8 commits intorust-bitcoin:masterfrom BP-WG:taproot/hidden
Conversation
src/util/psbt/map/output.rs
Outdated
There was a problem hiding this comment.
The comment here was not updated to reflect the change
sanket1729
left a comment
There was a problem hiding this comment.
Did not do a detail review, but left one which we should discuss before we invest more time
src/util/psbt/map/output.rs
Outdated
There was a problem hiding this comment.
It is rust convention to return inner as Err when it is consumed. So, the caller at least gets the copy it needs.
I don't remember completely, but I think @Kixunil suggested I do this in his review.
There was a problem hiding this comment.
Ah, ok. But it is really confusing when working with an API like that - I was confused myself, as you've seen in the issue
There was a problem hiding this comment.
@sanket1729 what about making IncompleteTapTree type to be a wrapper around TaprootBuilder, implemeting std::error::Error?
There was a problem hiding this comment.
Reworked that way.
There was a problem hiding this comment.
I will let him comment on this.
There was a problem hiding this comment.
FWIW, I like the implemented solution in this PR in case we decide to proceed with this.
There was a problem hiding this comment.
Yes, error wrapper containing original data is even more idiomatic Rust. PoisonError is a good example of this.
It could be interesting to do it the way std does - instead of private field have accessor methods, so that the type can be extended. Or add a dummy field to emulate #[non_exhaustive] (and change it to #[non_exhaustive] after MSRV bump). Not sure how likely the change is here (writing this in hurry).
sanket1729
left a comment
There was a problem hiding this comment.
Some MSRV failures. I like this better, left a few comments that should be discussed
src/util/taproot.rs
Outdated
There was a problem hiding this comment.
nit:
has_hidden_branches or has_hidden_leaves instead? I am not a big fan of names where humans have to reason about things in order to complete them "has hidden what?", "Oh, must be has_hidden_leaves".
There was a problem hiding this comment.
Originally I did it as has_hidden_branches. Than, I had a though, "may be this is leaves?". Than I have found that the only unambiguous guess present in current API is add_hidden, and decided to skip the suffix. No idea how "branch" is different from "node", "part" etc - we have no terminology in place yet in this area.
There was a problem hiding this comment.
I'm out of my depth here but if 'parts' is correct in the rustdoc then wouldn't has_hidden_parts be a descriptive name?
There was a problem hiding this comment.
"Hidden" can be a script leaf or a tree branch, thus we need some term to describe it. I see only two applicable terms here: hidden_tips and hidden_parts. But then we also have to rename TreeBuilder::add_hidden, and I am not happy with both add_hidden_tip and add_hidden_part. This also brings us to #924 (comment) where TipNode can be used as an enum name for both script leafs and hidden (something).
There was a problem hiding this comment.
Had come to conclusion that "hidden something" can always be called a "node". Updated all names accordingly.
src/util/taproot.rs
Outdated
There was a problem hiding this comment.
I don't think we should be updating this function here. Instead, we should be using it in psbt TapTree::from_inner() check. Trees can be complete and well-formed even if they contain hidden nodes.
There was a problem hiding this comment.
Also thought. But than, is the tree considered "complete" having hidden nodes? May be this method should be named "is_finalizable"?
There was a problem hiding this comment.
But than, is the tree considered "complete" having hidden nodes?
I think there are two different things here. Builder is called complete if there is nothing else to add. In that sense using complete makes sense here. I don't mind renaming this to is_finalizable.
TapTree is always complete.
There was a problem hiding this comment.
is_finalizable would be ok but this PR uses is_finalized which does not make sense to me
src/util/psbt/serialize.rs
Outdated
There was a problem hiding this comment.
Had plans to use it in taproot mod to do more extensive tests
src/util/psbt/map/output.rs
Outdated
There was a problem hiding this comment.
I will let him comment on this.
|
@sanket1729 addressed all your comments & rebased |
sanket1729
left a comment
There was a problem hiding this comment.
c9fa3a9a77c7831ba6cedfaa39bf8a4985af85c7 also does not compile.
I think you can squash or re-order "Prevent TapTree from hidden parts" and "TapTree hidden branches unit test".
|
I like the PR, will ACK after the commits pass tests. |
|
If this release is getting delayed anyway, IMO we can do the clean solution with Hidden leaves instead. We don't need to restrict ourselves artificially with trees only containing full leaves. |
src/util/taproot.rs
Outdated
There was a problem hiding this comment.
| return false; | |
| false |
src/util/taproot.rs
Outdated
There was a problem hiding this comment.
I'm out of my depth here but if 'parts' is correct in the rustdoc then wouldn't has_hidden_parts be a descriptive name?
@sanket1729 I did what I think the best solution for now in the latest version of #924 and provided rationale in #924 (comment). Right now we do not have hidden branches to iterate over, so adding that second iterator in this release does not makes a lot of sense. Please let me know if you are ok with this approach. Also pls let me know do I need to discard your review by fixing single non-compilling commit in the history, or it can go like that. @tcharding I will address your comments iff I will be force-pushing again. |
|
@dr-orlovsky , you can force push |
|
@dr-orlovsky if you can force push, I will be prompt to review today. I don't want to merge non-compiling commits. |
|
Force-pushed fully reordering commits, checking each to be compiling & addressing all @sanket1729 and @tcharding comments. Also renamed |
sanket1729
left a comment
There was a problem hiding this comment.
ACK 7771531 .
Reviwed the range diff. Why did you remove the test
- #[test]
- fn taptree_hidden() {
- let mut builder = compose_taproot_builder(0x51, &[2, 2, 2]);
- builder = builder.add_leaf_with_ver(3, Script::from_hex("b9").unwrap(), LeafVersion::from_consensus(0xC2).unwrap()).unwrap();
- builder = builder.add_hidden(3, sha256::Hash::default()).unwrap();
- assert!(TapTree::from_inner(builder.clone()).is_err());
- }
-
|
@sanket1729 s**, this happened during re-ordering of the commitments. Added it back - sorry will do it on top. |
|
Awesome thanks, all looks good to me. |
| .map_err(|_| encode::Error::ParseFailed("Tree not in DFS order"))?; | ||
| } | ||
| if builder.is_finalized() { | ||
| if builder.is_finalized() || !builder.has_hidden_nodes() { |
There was a problem hiding this comment.
In 7771531:
I don't understand the name is_finalized but I'm pretty sure this || is supposed to be a &&.
I really liked the is_complete naming, but that was changed earlier in b0f3992 Was also suggested by Andrew rust-bitcoin#929 (comment)
I really liked the is_complete naming, but that was changed earlier in b0f3992 Was also suggested by Andrew rust-bitcoin/rust-bitcoin#929 (comment)
Closes #928