Skip to content

Commit 8c5dce1

Browse files
authored
⚡️ Optimize MerkleTreeLib (#1438)
1 parent b4d2099 commit 8c5dce1

2 files changed

Lines changed: 24 additions & 23 deletions

File tree

src/utils/MerkleTreeLib.sol

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -113,22 +113,14 @@ library MerkleTreeLib {
113113
pure
114114
returns (bytes32[] memory result)
115115
{
116+
uint256 nodeIndex;
116117
/// @solidity memory-safe-assembly
117118
assembly {
118-
result := mload(0x40)
119119
let n := mload(t)
120-
if iszero(lt(leafIndex, sub(n, shr(1, n)))) {
121-
mstore(0x00, 0x7a856a38) // `MerkleTreeOutOfBoundsAccess()`.
122-
revert(0x1c, 0x04)
123-
}
124-
let o := add(result, 0x20)
125-
for { let i := sub(n, add(1, leafIndex)) } i { i := shr(1, sub(i, 1)) } {
126-
mstore(o, mload(add(t, shl(5, add(i, shl(1, and(1, i)))))))
127-
o := add(o, 0x20)
128-
}
129-
mstore(0x40, o) // Allocate memory.
130-
mstore(result, shr(5, sub(o, add(result, 0x20)))) // Store length.
120+
nodeIndex := sub(n, add(1, leafIndex))
121+
if iszero(lt(leafIndex, sub(n, shr(1, n)))) { nodeIndex := not(0) }
131122
}
123+
result = nodeProof(t, nodeIndex);
132124
}
133125

134126
/// @dev Returns the proof for the node at `nodeIndex`.
@@ -167,16 +159,12 @@ library MerkleTreeLib {
167159
function gen(leafIndices_, t_, proof_, flags_) -> _flagsLen, _proofLen {
168160
let q_ := mload(0x40) // Circular buffer.
169161
let c_ := mload(leafIndices_) // Capacity of circular buffer.
170-
let e_ := mload(leafIndices_) // End index of circular buffer.
162+
let e_ := c_ // End index of circular buffer.
171163
let b_ := 0 // Start index of circular buffer.
172-
if iszero(e_) {
173-
mstore(0x00, 0xe9729976) // `MerkleTreeInvalidLeafIndices()`.
174-
revert(0x1c, 0x04)
175-
}
176164
for {
177165
let n_ := mload(t_) // Num nodes.
178166
let l_ := sub(n_, shr(1, n_)) // Num leafs.
179-
let p_ := 0
167+
let p_ := not(0)
180168
let i_ := 0
181169
} 1 {} {
182170
let j_ := mload(add(add(leafIndices_, 0x20), shl(5, i_))) // Leaf index.
@@ -185,7 +173,7 @@ library MerkleTreeLib {
185173
mstore(0x00, 0x7a856a38) // `MerkleTreeOutOfBoundsAccess()`.
186174
revert(0x1c, 0x04)
187175
}
188-
if iszero(or(iszero(i_), gt(j_, p_))) {
176+
if iszero(sgt(j_, p_)) {
189177
mstore(0x00, 0xe9729976) // `MerkleTreeInvalidLeafIndices()`.
190178
revert(0x1c, 0x04)
191179
}
@@ -204,17 +192,21 @@ library MerkleTreeLib {
204192
_flagsLen := add(_flagsLen, 0x20)
205193
let f_ := and(eq(s_, add(1, mload(add(q_, shl(5, mod(b_, c_)))))), lt(b_, e_))
206194
b_ := add(b_, f_)
207-
if flags_ { mstore(add(flags_, _flagsLen), f_) }
208-
if iszero(f_) {
209-
_proofLen := add(_proofLen, 0x20)
210-
if flags_ { mstore(add(proof_, _proofLen), mload(add(t_, shl(5, s_)))) }
195+
_proofLen := add(_proofLen, shl(5, iszero(f_)))
196+
if flags_ {
197+
mstore(add(flags_, _flagsLen), f_)
198+
mstore(mul(iszero(f_), add(proof_, _proofLen)), mload(add(t_, shl(5, s_))))
211199
}
212200
mstore(add(q_, shl(5, mod(e_, c_))), shr(1, sub(j_, 1)))
213201
e_ := add(e_, 1)
214202
}
215203
_proofLen := shr(5, _proofLen)
216204
_flagsLen := shr(5, _flagsLen)
217205
}
206+
if iszero(mload(leafIndices)) {
207+
mstore(0x00, 0xe9729976) // `MerkleTreeInvalidLeafIndices()`.
208+
revert(0x1c, 0x04)
209+
}
218210
let flagsLen, proofLen := gen(leafIndices, t, 0x00, 0x00)
219211
proof := mload(0x40)
220212
mstore(proof, proofLen)

test/MerkleTreeLib.t.sol

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,4 +216,13 @@ contract MerkleTreeLibTest is SoladyTest {
216216
gathered[i] = leafs[indices[i]];
217217
}
218218
}
219+
220+
function testMultiProofRevertsForEmptyLeafs() public {
221+
vm.expectRevert(MerkleTreeLib.MerkleTreeInvalidLeafIndices.selector);
222+
this.multiProofRevertsForEmptyLeafs();
223+
}
224+
225+
function multiProofRevertsForEmptyLeafs() public pure {
226+
(new bytes32[](1)).leafsMultiProof(new uint256[](0));
227+
}
219228
}

0 commit comments

Comments
 (0)