Return specific hash type when calculating merkle tree#2853
Return specific hash type when calculating merkle tree#2853tcharding wants to merge 3 commits intorust-bitcoin:masterfrom
Conversation
37e338c to
89cc0cc
Compare
|
The original function doesn't get "clobbered". Its argument is just a type that has two names, and the API script only uses one of them (which happens to be different than the old one). So I don't see the issue here. |
|
Approach NACK 89cc0cc81bdb640a0ce5a4cce07f09ef202e773d. I think we should take a different tack. Note that currently we have a Instead, we should:
This way our types at all steps are the correct types, we avoid making the internals of our txid type |
|
Ah nice, I like it. Thanks for the patient explanation.
Derp, type alias ... |
Currently we are defining the two merkle tree hash types in the `block` module, a better home for them is the `merkle_tree` module. This is an API breaking change because the types were public in the `block` module, however the change should/could be unnoticeable to users if they use the crate level re-export - which is maintained.
|
Oh I think I've got it. |
Currently we return a `Txid` or `Wtxid` when calculating a Merkle tree, however we have specific hash types for this - the `TxMerkleNode` and `WitnessMerkleNode` types. Add a trait that ties together the `Txid`/`TxMerkleNode` and `Wtxid`/`WitnessMerkleNode` types and return the specific type when calculating a Merkle tree.
89cc0cc to
a718079
Compare
|
FTR this PR does not implement the suggestions by @Kixunil in #2770 (comment) for two reasons
|
|
That sounds good. This particular Merkle tree construction is questionable anyway because it does not domain-separate nodes and leaves, meaning that it is possible to have one Merkle root representing different trees. (IIRC there is some out-of-bound consensus rule preventing this from happening, but I don't remember now.) It also does a weird doubling-up construction to handle incomplete trees, which is okay for transactions which are guaranteed to be unique within a block but not great in general. So I think having a specific trait for Txid and Wtxid is probably the way to go. |
| impl From<Txid> for TxMerkleNode { | ||
| fn from(txid: Txid) -> Self { Self::from_byte_array(txid.to_byte_array()) } | ||
| /// A trait that defines a hash that can appear as a node in a Merkle tree. | ||
| pub trait MerkleNode: Hash + Encodable { |
There was a problem hiding this comment.
In a718079:
This trait should be inverted. It should be implemented on the node types, have type Leaf (which I don't think needs any bounds) and a from_leaf method.
Right now it is confusingly named because it's called MerkleNode but it's implemented on the leaves of the merkle tree, not the nodes.
There was a problem hiding this comment.
Yeah, after sleeping on this I'm not happy with it. The reasons you state are valid, I tried the other way and it also has problems. Its problematic because of the recursive function coupled with the inline function, because of inline we can't change the type (without unsafe) and because of the recursive function the leaf and internal nodes need to be the same type.
Second thing I woke up thinking, this is not going to work with the make-txid-not-a-general-purpose-hash thing, it might using to/from_byte_array but I'm not sure. I'm starting to think that we should just have two separate functions with suffix _txid and _wtxid and just be done with it. Like you say, this merkle construct is unique to merkelising transaction ids.
There was a problem hiding this comment.
Its problematic because of the recursive function coupled with the inline function, because of inline we can't change the type (without unsafe) and because of the recursive function the leaf and internal nodes need to be the same type.
Possibly you need a recursive function combined with a thin wrapper function.
Second thing I woke up thinking, this is not going to work with the make-txid-not-a-general-purpose-hash thing, it might using
to/from_byte_arraybut I'm not sure
It will. to/from_byte_array is how you "cast" hashes between each other, which is exactly what's happening here. It looks ugly because it's a bad idea that resulted in these Merkle trees having bad behavior on-chain. So that is a win for our new API to make the ugly thing look ugly.
There was a problem hiding this comment.
I can take this one on if you're tired of it.
There was a problem hiding this comment.
I did it in #2864. I didn't have any issue with recursion and definitely did not need unsafe code.
|
Replaced by #2864 |
90b6d67 merkle_tree: remove some now-redundant code from block.rs (Andrew Poelstra) 48ad5e4 api changes for "rewrite merkle root calculation" (Andrew Poelstra) f7ce9bb merkle_node: rewrite algorithm (Andrew Poelstra) 2bc97b2 api changes for new calculate_root method (Andrew Poelstra) 8d5cb01 merkle_tree: introduce MerkleNode trait to better-type merkle tree calculation (Andrew Poelstra) 0435390 api changes after moving the hashes (Andrew Poelstra) 5d8aa94 Move merkle_tree hash types (Andrew Poelstra) Pull request description: Alternate to #2853. Takes patch 1 from that PR. ACKs for top commit: Kixunil: ACK 90b6d67 tcharding: ACK 90b6d67 Tree-SHA512: 0e0a3f532e2efb4116f4ebc50719d3a2022c37405b0a22b15f79189b54b623e906e8fdd53997efc611eac5ceaee4c0ef12dab1d5cb595755c0c9e091c0a5904f
Currently we return a
TxidorWtxidwhen calculating a Merkle tree, however we have specific hash types for this - theTxMerkleNodeandWitnessMerkleNodetypes.Add a trait that ties together the
Txid/TxMerkleNodeandWtxid/WitnessMerkleNodetypes and return the specific type when calculating a Merkle tree.Patch 1 is preparatory, moves the Merkle tree hash types as suggested below.