Skip to content

Commit 6b4ec6c

Browse files
ernestognwAmxx
andauthored
Remove root from MerkleTree (#4949)
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
1 parent 8cc7f2d commit 6b4ec6c

File tree

2 files changed

+18
-26
lines changed

2 files changed

+18
-26
lines changed

contracts/mocks/MerkleTreeMock.sol

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,20 @@ contract MerkleTreeMock {
99

1010
MerkleTree.Bytes32PushTree private _tree;
1111

12+
// This mock only stored the latest root.
13+
// Production contract may want to store historical values.
14+
bytes32 public root;
15+
1216
event LeafInserted(bytes32 leaf, uint256 index, bytes32 root);
1317

1418
function setup(uint8 _depth, bytes32 _zero) public {
15-
_tree.setup(_depth, _zero);
19+
root = _tree.setup(_depth, _zero);
1620
}
1721

1822
function push(bytes32 leaf) public {
1923
(uint256 leafIndex, bytes32 currentRoot) = _tree.push(leaf);
2024
emit LeafInserted(leaf, leafIndex, currentRoot);
21-
}
22-
23-
function root() public view returns (bytes32) {
24-
return _tree.root();
25+
root = currentRoot;
2526
}
2627

2728
function depth() public view returns (uint256) {

contracts/utils/structs/MerkleTree.sol

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {Panic} from "../Panic.sol";
1111
*
1212
* Each tree is a complete binary tree with the ability to sequentially insert leaves, changing them from a zero to a
1313
* non-zero value and updating its root. This structure allows inserting commitments (or other entries) that are not
14-
* stored, but can be proven to be part of the tree at a later time. See {MerkleProof}.
14+
* stored, but can be proven to be part of the tree at a later time if the root is kept. See {MerkleProof}.
1515
*
1616
* A tree is defined by the following parameters:
1717
*
@@ -34,13 +34,13 @@ library MerkleTree {
3434
* directly. Use the functions provided below instead. Modifying the struct manually may violate assumptions and
3535
* lead to unexpected behavior.
3636
*
37-
* NOTE: The `root` is kept up to date after each insertion without keeping track of its history. Consider
38-
* using a secondary structure to store a list of historical roots (e.g. a mapping, {BitMaps} or {Checkpoints}).
37+
* NOTE: The `root` and the updates history is not stored within the tree. Consider using a secondary structure to
38+
* store a list of historical roots from the values returned from {setup} and {push} (e.g. a mapping, {BitMaps} or
39+
* {Checkpoints}).
3940
*
4041
* WARNING: Updating any of the tree's parameters after the first insertion will result in a corrupted tree.
4142
*/
4243
struct Bytes32PushTree {
43-
bytes32 _root;
4444
uint256 _nextLeafIndex;
4545
bytes32[] _sides;
4646
bytes32[] _zeros;
@@ -56,7 +56,7 @@ library MerkleTree {
5656
* IMPORTANT: The zero value should be carefully chosen since it will be stored in the tree representing
5757
* empty leaves. It should be a value that is not expected to be part of the tree.
5858
*/
59-
function setup(Bytes32PushTree storage self, uint8 levels, bytes32 zero) internal {
59+
function setup(Bytes32PushTree storage self, uint8 levels, bytes32 zero) internal returns (bytes32 initialRoot) {
6060
return setup(self, levels, zero, Hashes.commutativeKeccak256);
6161
}
6262

@@ -71,7 +71,7 @@ library MerkleTree {
7171
uint8 levels,
7272
bytes32 zero,
7373
function(bytes32, bytes32) view returns (bytes32) fnHash
74-
) internal {
74+
) internal returns (bytes32 initialRoot) {
7575
// Store depth in the dynamic array
7676
Arrays.unsafeSetLength(self._sides, levels);
7777
Arrays.unsafeSetLength(self._zeros, levels);
@@ -84,9 +84,10 @@ library MerkleTree {
8484
}
8585

8686
// Set the first root
87-
self._root = currentZero;
8887
self._nextLeafIndex = 0;
8988
self._fnHash = fnHash;
89+
90+
return currentZero;
9091
}
9192

9293
/**
@@ -102,15 +103,15 @@ library MerkleTree {
102103
function(bytes32, bytes32) view returns (bytes32) fnHash = self._fnHash;
103104

104105
// Get leaf index
105-
uint256 leafIndex = self._nextLeafIndex++;
106+
index = self._nextLeafIndex++;
106107

107108
// Check if tree is full.
108-
if (leafIndex >= 1 << levels) {
109+
if (index >= 1 << levels) {
109110
Panic.panic(Panic.RESOURCE_ERROR);
110111
}
111112

112113
// Rebuild branch from leaf to root
113-
uint256 currentIndex = leafIndex;
114+
uint256 currentIndex = index;
114115
bytes32 currentLevelHash = leaf;
115116
for (uint32 i = 0; i < levels; i++) {
116117
// Reaching the parent node, is currentLevelHash the left child?
@@ -132,17 +133,7 @@ library MerkleTree {
132133
currentIndex >>= 1;
133134
}
134135

135-
// Record new root
136-
self._root = currentLevelHash;
137-
138-
return (leafIndex, currentLevelHash);
139-
}
140-
141-
/**
142-
* @dev Tree's current root
143-
*/
144-
function root(Bytes32PushTree storage self) internal view returns (bytes32) {
145-
return self._root;
136+
return (index, currentLevelHash);
146137
}
147138

148139
/**

0 commit comments

Comments
 (0)