Refactor bitcoin_merkle_root functions#710
Conversation
Kixunil
left a comment
There was a problem hiding this comment.
Very good!
ACK 150d9559f164164a5fb30897bec9336a54af0e05
31a469e to
2196e57
Compare
|
I've added two more patches that quite heavily refactor the two functions in question. Please re-review at your leisure, this work is really just for the pure fun of beautiful code. (Includes fix to typo that I recently introduced 'merkel' -> 'merkle' :( |
dr-orlovsky
left a comment
There was a problem hiding this comment.
I think that we should return a error and not panic if the tree is empty, since it may be quite a common situation
src/util/hash.rs
Outdated
There was a problem hiding this comment.
This can be improved even more by
match data.len() {
O => panic!(),
1 => data[1],
2 => merkle_root_r(data),
}There was a problem hiding this comment.
I deleted my original thoughts because they turned out to be wrong and were really long. PR now includes this suggestion.
src/util/hash.rs
Outdated
There was a problem hiding this comment.
This same condition is in markle_root_r, so probably not needed here.
There was a problem hiding this comment.
I added it there for two reasons:
- It gives a line of code that can carry the code comment
- In
merkle_root_rthis call is the recursion base case, here it is not, so slightly different
I was trying to separate the recursion from the two 'higher' functions.
src/util/hash.rs
Outdated
There was a problem hiding this comment.
Unrelated but I think ExactSIzeIterator is not actually required. Just allocate Vec based on size_hint and let the Vec resize itself if the hint is incorrect (that's actually what happens today - len is not strictly guaranteed to be correct).
There was a problem hiding this comment.
But then we cannot call iter.len()?
There was a problem hiding this comment.
I don't think we need to:
let first = iter.next()?;
let second = match iter.next() {
Some(second) => second,
// A single hash is by definition the merkle root.
None => return Some(first),
};
let (min, max) = iter.size_hint();
let mut hashes = Vec::with_capacity(max.unwrap_or(min) / 2 + 1);
let iter = [first, second].iter().chain(iter);
// Continue using `hashes` and `iter` as before.Note: s/hashes/alloc/g, s/iter/hashes per latest change.
There was a problem hiding this comment.
let iter = [first, second].iter().chain(iter);
I couldn't get this line to build, I used instead:
let mut hashes = iter::once(first).chain(iter::once(second)).chain(hashes);
src/util/hash.rs
Outdated
There was a problem hiding this comment.
I think it'd be nice to highlight the word "hashes" here and above to make it more obvious it's not data.
There was a problem hiding this comment.
Nice, more descriptive and further unifies the functions!
There was a problem hiding this comment.
I believe you forgot about highlighting.
Kixunil
left a comment
There was a problem hiding this comment.
Looks good, had a few more ideas. I'm unsure if panic! is better than Option but I think Result would be overkill.
Thanks for the review @dr-orlovsky, I'm leaning towards @Kixunil suggestion of using an
I'll push this change, please comment though if you'd like me to re-consider using an error. |
|
I think the |
2196e57 to
e0e708b
Compare
|
I'm not sure what is the accepted protocol re force pushing in |
Cool, thanks. Easy consensus :) |
|
@tcharding from my experience here it seems that force-pushes are more preferable than bloating commit log with fix commits. As for re-ACKs, the normal solution for that is using |
dr-orlovsky
left a comment
There was a problem hiding this comment.
utACK e0e708b1a4af00fa735c2fb16cb895499ebbef12
2a985ad to
3e59061
Compare
|
This PR was getting out of control, I've squashed all the |
3e59061 to
342bf63
Compare
Kixunil
left a comment
There was a problem hiding this comment.
I believe at least undocumented panics should be resolved.
src/util/hash.rs
Outdated
There was a problem hiding this comment.
I believe you forgot about highlighting.
I don't understand this comment @Kixunil, can you repeat please? (There is no response box under the original comment for some reason.) |
e2ce9f0 to
1eabb77
Compare
1eabb77 to
086f480
Compare
|
I suggested adding asterisks around the word "hashes" in the docs, so it becomes hashes. This will make it clear it's not data. I guess you misunderstood what I meant by "highlighting". |
Kixunil
left a comment
There was a problem hiding this comment.
ACK 086f4807bad8cb5d06f2b8bbc9d1c506d4822328
Nice improvement! I consider my comments to be optional.
src/blockdata/block.rs
Outdated
There was a problem hiding this comment.
Maybe this is nicer, I'm not sure, do as you wish.
self.merkle_root()
.map(|merkle_root| self.header.merkle_root == merkle_root)
.unwrap_or(false)There was a problem hiding this comment.
I played with the combinator here as suggested and also on the call to self.witness_root(). It wasn't clearly better either way to me so I ended going with the code as it is since seemed slightly easier to read.
Ooooh, my bad, good idea. Will add. |
Fix typo in test function name to use the correct spelling of 'merkle' (not 'merkel').
The merkle_root of an empty tree is undefined, this is the only error case we have for the two `bitcoin_merkle_root*` functions. We can fully describe this error case by returning an `Option` if args are found to be empty. We can do the same for the wrapper functions in `block` module. While we are at it, refactor out a recursive helper function to make reading the code between the two functions easier.
086f480 to
b454cf8
Compare
|
Added italics to 'hashes' as suggested, rebased, force pushed. |
dr-orlovsky
left a comment
There was a problem hiding this comment.
Seems like we have a bug in the implementation - pls see my comment
|
'one-ack' badge is stale :) Thanks for all the reviews fellas. |
|
Would merge it but I still didn't setup commit signing properly. My understanding is it's not nice to merge without it. |
Do two minor refactorings to the `bitcoin_merkle_root[_inline] functions.This PR has grown, is no longer a refactoring because the two functions have been changed to return an
Option.First patch is cleanup. Here is the commit message for the second patch