Remove root from MerkleTree (#4949)
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
This commit is contained in:
@ -9,19 +9,20 @@ contract MerkleTreeMock {
|
|||||||
|
|
||||||
MerkleTree.Bytes32PushTree private _tree;
|
MerkleTree.Bytes32PushTree private _tree;
|
||||||
|
|
||||||
|
// This mock only stored the latest root.
|
||||||
|
// Production contract may want to store historical values.
|
||||||
|
bytes32 public root;
|
||||||
|
|
||||||
event LeafInserted(bytes32 leaf, uint256 index, bytes32 root);
|
event LeafInserted(bytes32 leaf, uint256 index, bytes32 root);
|
||||||
|
|
||||||
function setup(uint8 _depth, bytes32 _zero) public {
|
function setup(uint8 _depth, bytes32 _zero) public {
|
||||||
_tree.setup(_depth, _zero);
|
root = _tree.setup(_depth, _zero);
|
||||||
}
|
}
|
||||||
|
|
||||||
function push(bytes32 leaf) public {
|
function push(bytes32 leaf) public {
|
||||||
(uint256 leafIndex, bytes32 currentRoot) = _tree.push(leaf);
|
(uint256 leafIndex, bytes32 currentRoot) = _tree.push(leaf);
|
||||||
emit LeafInserted(leaf, leafIndex, currentRoot);
|
emit LeafInserted(leaf, leafIndex, currentRoot);
|
||||||
}
|
root = currentRoot;
|
||||||
|
|
||||||
function root() public view returns (bytes32) {
|
|
||||||
return _tree.root();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function depth() public view returns (uint256) {
|
function depth() public view returns (uint256) {
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import {Panic} from "../Panic.sol";
|
|||||||
*
|
*
|
||||||
* Each tree is a complete binary tree with the ability to sequentially insert leaves, changing them from a zero to a
|
* Each tree is a complete binary tree with the ability to sequentially insert leaves, changing them from a zero to a
|
||||||
* non-zero value and updating its root. This structure allows inserting commitments (or other entries) that are not
|
* non-zero value and updating its root. This structure allows inserting commitments (or other entries) that are not
|
||||||
* stored, but can be proven to be part of the tree at a later time. See {MerkleProof}.
|
* stored, but can be proven to be part of the tree at a later time if the root is kept. See {MerkleProof}.
|
||||||
*
|
*
|
||||||
* A tree is defined by the following parameters:
|
* A tree is defined by the following parameters:
|
||||||
*
|
*
|
||||||
@ -34,13 +34,13 @@ library MerkleTree {
|
|||||||
* directly. Use the functions provided below instead. Modifying the struct manually may violate assumptions and
|
* directly. Use the functions provided below instead. Modifying the struct manually may violate assumptions and
|
||||||
* lead to unexpected behavior.
|
* lead to unexpected behavior.
|
||||||
*
|
*
|
||||||
* NOTE: The `root` is kept up to date after each insertion without keeping track of its history. Consider
|
* NOTE: The `root` and the updates history is not stored within the tree. Consider using a secondary structure to
|
||||||
* using a secondary structure to store a list of historical roots (e.g. a mapping, {BitMaps} or {Checkpoints}).
|
* store a list of historical roots from the values returned from {setup} and {push} (e.g. a mapping, {BitMaps} or
|
||||||
|
* {Checkpoints}).
|
||||||
*
|
*
|
||||||
* WARNING: Updating any of the tree's parameters after the first insertion will result in a corrupted tree.
|
* WARNING: Updating any of the tree's parameters after the first insertion will result in a corrupted tree.
|
||||||
*/
|
*/
|
||||||
struct Bytes32PushTree {
|
struct Bytes32PushTree {
|
||||||
bytes32 _root;
|
|
||||||
uint256 _nextLeafIndex;
|
uint256 _nextLeafIndex;
|
||||||
bytes32[] _sides;
|
bytes32[] _sides;
|
||||||
bytes32[] _zeros;
|
bytes32[] _zeros;
|
||||||
@ -56,7 +56,7 @@ library MerkleTree {
|
|||||||
* IMPORTANT: The zero value should be carefully chosen since it will be stored in the tree representing
|
* IMPORTANT: The zero value should be carefully chosen since it will be stored in the tree representing
|
||||||
* empty leaves. It should be a value that is not expected to be part of the tree.
|
* empty leaves. It should be a value that is not expected to be part of the tree.
|
||||||
*/
|
*/
|
||||||
function setup(Bytes32PushTree storage self, uint8 levels, bytes32 zero) internal {
|
function setup(Bytes32PushTree storage self, uint8 levels, bytes32 zero) internal returns (bytes32 initialRoot) {
|
||||||
return setup(self, levels, zero, Hashes.commutativeKeccak256);
|
return setup(self, levels, zero, Hashes.commutativeKeccak256);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ library MerkleTree {
|
|||||||
uint8 levels,
|
uint8 levels,
|
||||||
bytes32 zero,
|
bytes32 zero,
|
||||||
function(bytes32, bytes32) view returns (bytes32) fnHash
|
function(bytes32, bytes32) view returns (bytes32) fnHash
|
||||||
) internal {
|
) internal returns (bytes32 initialRoot) {
|
||||||
// Store depth in the dynamic array
|
// Store depth in the dynamic array
|
||||||
Arrays.unsafeSetLength(self._sides, levels);
|
Arrays.unsafeSetLength(self._sides, levels);
|
||||||
Arrays.unsafeSetLength(self._zeros, levels);
|
Arrays.unsafeSetLength(self._zeros, levels);
|
||||||
@ -84,9 +84,10 @@ library MerkleTree {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set the first root
|
// Set the first root
|
||||||
self._root = currentZero;
|
|
||||||
self._nextLeafIndex = 0;
|
self._nextLeafIndex = 0;
|
||||||
self._fnHash = fnHash;
|
self._fnHash = fnHash;
|
||||||
|
|
||||||
|
return currentZero;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -102,15 +103,15 @@ library MerkleTree {
|
|||||||
function(bytes32, bytes32) view returns (bytes32) fnHash = self._fnHash;
|
function(bytes32, bytes32) view returns (bytes32) fnHash = self._fnHash;
|
||||||
|
|
||||||
// Get leaf index
|
// Get leaf index
|
||||||
uint256 leafIndex = self._nextLeafIndex++;
|
index = self._nextLeafIndex++;
|
||||||
|
|
||||||
// Check if tree is full.
|
// Check if tree is full.
|
||||||
if (leafIndex >= 1 << levels) {
|
if (index >= 1 << levels) {
|
||||||
Panic.panic(Panic.RESOURCE_ERROR);
|
Panic.panic(Panic.RESOURCE_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rebuild branch from leaf to root
|
// Rebuild branch from leaf to root
|
||||||
uint256 currentIndex = leafIndex;
|
uint256 currentIndex = index;
|
||||||
bytes32 currentLevelHash = leaf;
|
bytes32 currentLevelHash = leaf;
|
||||||
for (uint32 i = 0; i < levels; i++) {
|
for (uint32 i = 0; i < levels; i++) {
|
||||||
// Reaching the parent node, is currentLevelHash the left child?
|
// Reaching the parent node, is currentLevelHash the left child?
|
||||||
@ -132,17 +133,7 @@ library MerkleTree {
|
|||||||
currentIndex >>= 1;
|
currentIndex >>= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record new root
|
return (index, currentLevelHash);
|
||||||
self._root = currentLevelHash;
|
|
||||||
|
|
||||||
return (leafIndex, currentLevelHash);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @dev Tree's current root
|
|
||||||
*/
|
|
||||||
function root(Bytes32PushTree storage self) internal view returns (bytes32) {
|
|
||||||
return self._root;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user