Add taproot data structures#677
Conversation
637ee89 to
032894b
Compare
src/util/taproot.rs
Outdated
There was a problem hiding this comment.
maybe more compact as: self.0.iter().map(|e| e.as_inner()).flatten() ?
Not sure if it's not as efficient...
Also, isn't maybe better to have the serialization logic inside a non-allocating method using a writer and calling it here?
There was a problem hiding this comment.
Agreed, will add another method that has serialization logic inside a writer.
There was a problem hiding this comment.
Iterators should be more efficient because of TrustedLen specialization. (My understanding is that it pre-allocates correct size and then fills it without additional bounds check.) However I'm not sure if it can see that all those slices are equal-sized.
src/util/taproot.rs
Outdated
There was a problem hiding this comment.
maybe more rusty to have first let var_len =sl.len().checked_sub(TAPROOT_CONTROL_BASE_SIZE).unwrap_or_else(...) and then this if simplified?
src/util/taproot.rs
Outdated
There was a problem hiding this comment.
IIRC there is a naming convention in rust for acronyms to be like this NodeNotInDfsOrder
|
Concept ACK 032894b Some small suggestions from an initial review, will spend more time reviewing against the spec. Will also take some time to experiment with building Taproot contracts with this API, and report back. |
src/util/taproot.rs
Outdated
There was a problem hiding this comment.
nit: check for error condition before mutating internal state
| self.0.push(h); | |
| if self.0.len() > TAPROOT_CONTROL_MAX_NODE_COUNT { | |
| return Err(TaprootBuilderError::InvalidMerkleTreeDepth(self.0.len())); | |
| } else { | |
| Ok(()) | |
| } | |
| if self.0.len() + 1 > TAPROOT_CONTROL_MAX_NODE_COUNT { | |
| Err(TaprootBuilderError::InvalidMerkleTreeDepth(self.0.len() + 1)) | |
| } else { | |
| self.0.push(h); | |
| Ok(()) | |
| } |
There was a problem hiding this comment.
Rewriting it to self.0.len() >= TAPROOT_CONTROL_MAX_NODE_COUNT would avoid overflow if the invariant that self.0.len() <= TAPROOT_CONTROL_MAX_NODE_COUNT is ever accidentally broken.
tcharding
left a comment
There was a problem hiding this comment.
Just a few little comments, I didn't get all the way through the review.
src/util/taproot.rs
Outdated
There was a problem hiding this comment.
Is it meant to be 'This serialization does not include the VarInt prefix'? Also: s/why/when
src/util/taproot.rs
Outdated
There was a problem hiding this comment.
Turning the slice into iterator would make it easier to reason about this code IMO, but we really need the extension trait I mentioned somewhere already.
There was a problem hiding this comment.
How do you suggest approaching this? I don't see a way to process an iterator u8 and ask it to yield slices without explicating allocating expected size arrays.
032894b to
9d25f9c
Compare
|
Sorry for the force push, addressed the feedback from @GeneFerneau and @tcharding, did not address comments from @Kixunil. I will add fixup commits from now on for easier review and later squash them when it is ready. |
8ff692f to
b734d95
Compare
89d96c0 to
e740ac0
Compare
|
@dr-orlovsky addressed all of your comments. I think if we get another review for this. We should just merge this and proceed with other taproot stuff. I can work on fixing up and making sure changes in #691 are reflected here. Finally, I think about the API guidelines, I think we should have a broader discussion. My rule is to always follow the current convention in the codebase. Using |
|
My understanding of naming:
|
src/util/sighash.rs
Outdated
There was a problem hiding this comment.
would this be better as Option? Or I suppose ScriptPath always only in Tap context (in which case, small nit, but maybe TapScriptPath would be clearer name)
There was a problem hiding this comment.
This is not a part of the current PR under discussion. But I like the name TapScriptPath over ScriptPath
I thought
I've never managed to work out the pattern for times when we need multiple constructors with multiple args? Amusingly I was looking at all the instances of single arg constructors for I don't mean to bike shed here, I'm genuinely interested in these sorts of conventions. |
JeremyRubin
left a comment
There was a problem hiding this comment.
did some light review
src/util/taproot.rs
Outdated
There was a problem hiding this comment.
and_then would also work, but i'm indifferent (fine as is, altho superfluos else)
src/util/taproot.rs
Outdated
There was a problem hiding this comment.
nit: or the most fee sensitive one? e.g. contested closing?
src/util/taproot.rs
Outdated
There was a problem hiding this comment.
is this a BtreeSet internally in case there are >1 instances of a given script?
There was a problem hiding this comment.
Yes, this is to allow > 1 instances of a given script. In practice, this should never be used, but since descriptors spec does not disallow it, we have to support it.
src/util/taproot.rs
Outdated
There was a problem hiding this comment.
hmm i think you generally shouldn't construct the vec tuple from a btreemap/hashmap as it can introduce subtle bugs (e.g., when you might want a script to appear > 1 time)
src/util/taproot.rs
Outdated
There was a problem hiding this comment.
this shouldn't be an error condition IMO, should fallback to creating a binary tree of all failing (>128) scripts and attaching at the largest possible depth?
but I think it's OK to have it this way for now...
There was a problem hiding this comment.
This is an improvement. I can create a good first issue for this. If someone really wants this, they are welcome to implement this and I am happy to review it.
There was a problem hiding this comment.
If the optimal huffman tree has depth exceeding 128 it means the user has set insane weights. We should error rather than silently doing the wrong thing.
src/util/taproot.rs
Outdated
There was a problem hiding this comment.
given this return type, this should either be a free function or bound to the TapBranchHash impl.
There was a problem hiding this comment.
The return type is TaprootSpendInfo
There was a problem hiding this comment.
ah i misread as TapBranchHash
src/util/taproot.rs
Outdated
There was a problem hiding this comment.
recommend doing a checked_add here because users could be dumb with what values they put in.
src/util/taproot.rs
Outdated
There was a problem hiding this comment.
nit: avoid usize in API, prefer u64 or u32
There was a problem hiding this comment.
thinking: otherwise the serialization/deserialization of types for pluggin in to this function would be platform dependent.
There was a problem hiding this comment.
Probability is usually expressed as float in range 0..=1, so it may be unintuitive/confusing to use integer. Perhaps worth a newtype with some helper methods? Or maybe more details explaining how would one compute the numbers?
src/util/taproot.rs
Outdated
There was a problem hiding this comment.
ack this seeming safe, as PK is fed into the hash.
Would prefer the comment clarifying the hash cycle, but a 'Safe' result API might be future proof if this would ever have any other reason to fail in the future?
src/util/taproot.rs
Outdated
e740ac0 to
aa211de
Compare
Add tests for taproot Builder Add tests for taproot huffman tree encoding Add tests for merkle proof verification
aa211de to
fa8c3f6
Compare
|
This PR has exceeded Github's ability to reasonably display comments. I would prefer future reviews to be in the form of followup PRs. Suggestions for non-github platforms are also welcome but that's a long term thing. |
|
So far, I think the only things I see remaining are:
Anything else that I am missing? If there is nothing critical I would request to proceed on this and I can address all of the nits in a followup PR. |
|
@GeneFerneau @RCasatta, @dr-orlovsky, sorry for dismissing your Acks. if you are interested in taking another look. |
…g tweak for UntweakedPublicKey 5b21a9c Use TapTweakHash method for computing tweak (Noah) Pull request description: Quick follow up PR to #691 using a method from #677. ### Changes - Updated `UntweakedPublicKey::tap_tweak(...)` to use `TapTweakHash::from_key_and_tweak(...)` ACKs for top commit: Kixunil: ACK 5b21a9c dr-orlovsky: utACK 5b21a9c Tree-SHA512: d00455bba51981e9ec942a6cf69672666e227850d073b1fdcd92d2eb6ad553659fb2967aec2ce12d3ed109cee5fa125cdda649cddb25404f08adae2bfd3e19bb
7aacc37 Add tests from BIP341 (sanket1729) 61629cc Make taproot hashes forward display (sanket1729) Pull request description: Add tests for taproot. - ~Also fixes one bug in #677, namely, I was returning `LeafVersion::default()` instead of given version~ - ~ Fixes a bug in #691 about taking secp context as a reference instead of consuming it. This should have not passed my review, but this is easy to miss. ~ - Makes the display on taproot hashes forward instead of the reverse (because the BIP prints in a forward way, I think we should too and it is more natural. ) ACKs for top commit: RCasatta: ACK 7aacc37 apoelstra: ACK 7aacc37 Tree-SHA512: 2e0442131fc036ffa10f88c91c8fc02d9b67ff6c16c592aa6f4e6a220c26a00fc6ca95a288f14aa40667a289fb0446219fd6c76c0196ead766252356592b9941
7d982fa Add all tests from BIP 371 (sanket1729) d22e014 Taproot psbt impl BIP 371 (sanket1729) 108fc3d Impl encodable traits for TapLeafhash (sanket1729) c7478d8 Derive serde for taproot stuctures (sanket1729) Pull request description: Built on top of #677 . Will rebase and mark ready for review after #677 is merged. ACKs for top commit: apoelstra: ACK 7d982fa dr-orlovsky: re-tACK 7d982fa basing on `git range-diff`. The original PR before last re-base was tested commit-by-commit. Tree-SHA512: feb30e4b38d13110a9c0fabf6466d8f0fb7df09a82f4e01d70b8371b34ab0187004a6c63f9796c6585ee30841e8ee765ae9becae139d2e1e3d839553d64c3d1e
I am still working on adding tests and testing these changes against bitcoin core. Feedback on code and API design is welcome.
Supercedes #666
TODO: