-
Notifications
You must be signed in to change notification settings - Fork 112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add SimpleMerkleTree #36
Conversation
We would need to find a way to support any[] values. Elements of the leafs are not all const leaves = [
[0, []],
[1, ['openzeppelin']],
[2, ['hello', 'world']],
[3, ['merkle', 'tree']],
];
const types = [ 'uint256', 'string[]' ];
const tree = StandardMerkleTree.of(leaves, types); We should also be able to load dumps that have been produced with older version of the library EDIT: solved in this comment |
There is also something that is bothering me with the way options are stored in the trees. If possible I'd like to avoid that. I get that its necessary to set the options in EDIT: solved in this comment |
Another think I just realized is broken in this PR is the interface of |
I iterated on this PR in https://github.com/OpenZeppelin/merkle-tree/tree/support-raw-leaves-inheritance-amxx Main differences:
I think this is looking better than #31 |
src/standard.ts
Outdated
this.hashLookup = Object.fromEntries( | ||
values.map(({ value }, valueIndex) => [hex(standardLeafHash(value, leafEncoding)), valueIndex]), | ||
); | ||
super(tree, values, standardLeafHasher.bind(null, leafEncoding)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any reason to use .bind
? I think it's more confusing than:
super(tree, values, standardLeafHasher.bind(null, leafEncoding)); | |
super(tree, values, v => standardLeafHasher(leafEncoding, v)); |
src/standard.ts
Outdated
leafEncoding: string[], | ||
options: MerkleTreeOptions = {}, | ||
): StandardMerkleTree<T> { | ||
const [tree, indexedValues] = MerkleTreeImpl.prepare(values, options, standardLeafHasher.bind(null, leafEncoding)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as the other
const [tree, indexedValues] = MerkleTreeImpl.prepare(values, options, standardLeafHasher.bind(null, leafEncoding)); | |
const [tree, indexedValues] = MerkleTreeImpl.prepare(values, options, v => standardLeafHasher(leafEncoding, v)); |
I reviewed the updates and generally addressed comments because I think they're not too controversial. Added explanations accordingly. The main differences are:
At this point, the PR looks good to me. I left a couple of open comments that need comments. Also, appreciate feedback on point number 3 regarding errors. If that's too much to discuss here let's revert to ada28f1 |
values: { value: T; treeIndex: number }[]; | ||
}; | ||
|
||
export interface MerkleTree<T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally we would have a way to prevent T from being number
, as this leads to confusion between leaf value and leaf index.
I tried doing:
export abstract class MerkleTreeImpl<T, _ = Exclude<T, number>> implements MerkleTree<T> {
But it doesn't work as I intended.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couldn't make it work. I think the best we can do is restrict it at the MerkleTree constructor.
I added an update, it'd be the last thing imo, otherwise LGTM.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For your curiosity, a way in which it's possible to achieve something like Exclude<any, number>
is to use conditional types.
function foo<T>(n : T extends number ? never : T): void {}
foo(1) // error
foo("a") // ok
But this is obscure and I would not recommend it. I'm not even sure I understand why it works. 😛
The new "snapshot" files don't convince me but I think it's not a big deal given we don't have too many variations. I guess we can merge this but I guess is another strong argument in favor of Ava as a testing framework. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly minor comments but also I think one blocker. Feel free to ignore any nitpicks.
Description
Alternative to #31 with less repeated code.
The SimpleMerkleTree also receives
BytesLikes
leaves so that the input is consistent with StandardMerkleTree and we can use inheritance to avoid code repetition.I removed the
T extends BytesLike[]
for simplicity and becauseBytesLike[]
is the only input supported.Note that StandardMerkleTree overloaded functions are for backwards compatibility. We can get rid of them if we release a new non-backwards compatible version