Skip to content

Commit

Permalink
fix: Merkle tests to pass in stable Foundy release
Browse files Browse the repository at this point in the history
  • Loading branch information
guidanoli committed Feb 18, 2025
1 parent d7892f7 commit 886f518
Showing 1 changed file with 38 additions and 38 deletions.
76 changes: 38 additions & 38 deletions cartesi-rollups/contracts/test/Merkle.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,17 @@ import {MerkleConstants} from "src/MerkleConstants.sol";
import {PristineMerkleTree} from "src/PristineMerkleTree.sol";
import {Merkle} from "src/Merkle.sol";

contract PristineMerkleTreeContract {
library PristineMerkleTreeWrapper {
function getNodeAtHeight(uint256 height) external pure returns (bytes32) {
return PristineMerkleTree.getNodeAtHeight(height);
}
}

contract MerkleContract {
library MerkleWrapper {
function join(bytes32 a, bytes32 b) external pure returns (bytes32) {
return Merkle.join(a, b);
}

function getRootAfterReplacementInDrive(
uint256 position,
uint256 log2SizeOfReplacement,
Expand All @@ -42,9 +46,6 @@ contract MerkleContract {
}

contract MerkleTest is Test {
PristineMerkleTreeContract pristineMerkle;
MerkleContract merkle;

uint256 constant LEAF_SIZE = (1 << MerkleConstants.LOG2_LEAF_SIZE);
bytes32 constant WORD_0 = keccak256("foo");
bytes32 constant WORD_1 = keccak256("bar");
Expand All @@ -59,30 +60,25 @@ contract MerkleTest is Test {
bytes32 constant ROOT = keccak256(abi.encode(NODE_01, NODE_23));
uint256 constant MAX_HEIGHT = MerkleConstants.LOG2_MEMORY_SIZE - MerkleConstants.LOG2_LEAF_SIZE;

function setUp() external {
pristineMerkle = new PristineMerkleTreeContract();
merkle = new MerkleContract();
}

function testJoinEquivalence(bytes32 a, bytes32 b) external pure {
assertEq(Merkle.join(a, b), keccak256(abi.encodePacked(a, b)));
assertEq(MerkleWrapper.join(a, b), keccak256(abi.encodePacked(a, b)));
}

function testPristineMerkleTree() external pure {
bytes32 node = keccak256(abi.encode(0));
for (uint256 height; height <= MerkleConstants.TREE_HEIGHT; ++height) {
assertEq(PristineMerkleTree.getNodeAtHeight(height), node);
node = Merkle.join(node, node);
node = MerkleWrapper.join(node, node);
}
}

function testPristineMerkleTreeRevert(uint256 height) external {
height = bound(height, MerkleConstants.TREE_HEIGHT + 1, type(uint256).max);
vm.expectRevert("Height out of bounds");
pristineMerkle.getNodeAtHeight(height);
PristineMerkleTreeWrapper.getNodeAtHeight(height);
}

function testGetRootAfterReplacementInDrive() external view {
function testGetRootAfterReplacementInDrive() external pure {
{
uint256 log2SizeOfReplacement = MerkleConstants.LOG2_LEAF_SIZE;
uint256 position = 0 << log2SizeOfReplacement;
Expand Down Expand Up @@ -110,7 +106,7 @@ contract MerkleTest is Test {

assertEq(
ROOT,
merkle.getRootAfterReplacementInDrive(
MerkleWrapper.getRootAfterReplacementInDrive(
position, log2SizeOfReplacement, log2SizeOfDrive, replacement, siblings
)
);
Expand Down Expand Up @@ -142,7 +138,7 @@ contract MerkleTest is Test {

assertEq(
ROOT,
merkle.getRootAfterReplacementInDrive(
MerkleWrapper.getRootAfterReplacementInDrive(
position, log2SizeOfReplacement, log2SizeOfDrive, replacement, siblings
)
);
Expand Down Expand Up @@ -174,7 +170,7 @@ contract MerkleTest is Test {

assertEq(
ROOT,
merkle.getRootAfterReplacementInDrive(
MerkleWrapper.getRootAfterReplacementInDrive(
position, log2SizeOfReplacement, log2SizeOfDrive, replacement, siblings
)
);
Expand Down Expand Up @@ -206,7 +202,7 @@ contract MerkleTest is Test {

assertEq(
ROOT,
merkle.getRootAfterReplacementInDrive(
MerkleWrapper.getRootAfterReplacementInDrive(
position, log2SizeOfReplacement, log2SizeOfDrive, replacement, siblings
)
);
Expand All @@ -231,7 +227,7 @@ contract MerkleTest is Test {

assertEq(
ROOT,
merkle.getRootAfterReplacementInDrive(
MerkleWrapper.getRootAfterReplacementInDrive(
position, log2SizeOfReplacement, log2SizeOfDrive, replacement, siblings
)
);
Expand All @@ -256,7 +252,7 @@ contract MerkleTest is Test {

assertEq(
ROOT,
merkle.getRootAfterReplacementInDrive(
MerkleWrapper.getRootAfterReplacementInDrive(
position, log2SizeOfReplacement, log2SizeOfDrive, replacement, siblings
)
);
Expand All @@ -273,7 +269,7 @@ contract MerkleTest is Test {
siblings[0] = LEAF_1;
siblings[1] = NODE_23;
vm.expectRevert("Position is not aligned");
merkle.getRootAfterReplacementInDrive(
MerkleWrapper.getRootAfterReplacementInDrive(
position, log2SizeOfReplacement, log2SizeOfDrive, replacement, siblings
);
}
Expand All @@ -291,71 +287,75 @@ contract MerkleTest is Test {
vm.assume(siblings.length != log2SizeOfDrive - log2SizeOfReplacement);
position = (position >> log2SizeOfReplacement) << log2SizeOfReplacement;
vm.expectRevert("Proof length does not match");
Merkle.getRootAfterReplacementInDrive(position, log2SizeOfReplacement, log2SizeOfDrive, replacement, siblings);
MerkleWrapper.getRootAfterReplacementInDrive(
position, log2SizeOfReplacement, log2SizeOfDrive, replacement, siblings
);
}

function testGetRootAfterAnyReplacementInDrive(
uint256 position,
uint256 log2SizeOfReplacement,
uint256 log2SizeOfDrive,
bytes32 replacement
) external view {
) external pure {
log2SizeOfDrive = bound(log2SizeOfDrive, MerkleConstants.LOG2_LEAF_SIZE, MerkleConstants.LOG2_MEMORY_SIZE);
log2SizeOfReplacement = bound(log2SizeOfReplacement, MerkleConstants.LOG2_LEAF_SIZE, log2SizeOfDrive);
bytes32[] memory siblings = new bytes32[](log2SizeOfDrive - log2SizeOfReplacement);
position = (position >> log2SizeOfReplacement) << log2SizeOfReplacement;
merkle.getRootAfterReplacementInDrive(position, log2SizeOfReplacement, log2SizeOfDrive, replacement, siblings);
MerkleWrapper.getRootAfterReplacementInDrive(
position, log2SizeOfReplacement, log2SizeOfDrive, replacement, siblings
);
}

function testGetMinLog2SizeOfDrive(bytes calldata data) external view {
uint256 log2SizeOfDrive = merkle.getMinLog2SizeOfDrive(data);
function testGetMinLog2SizeOfDrive(bytes calldata data) external pure {
uint256 log2SizeOfDrive = MerkleWrapper.getMinLog2SizeOfDrive(data);
assertLe(data.length, 1 << log2SizeOfDrive);
if (data.length <= LEAF_SIZE) {
assertEq(log2SizeOfDrive, MerkleConstants.LOG2_LEAF_SIZE);
} else {
assertGt(data.length, 1 << (log2SizeOfDrive - 1));
}
merkle.getMerkleRootFromBytes(data, log2SizeOfDrive);
MerkleWrapper.getMerkleRootFromBytes(data, log2SizeOfDrive);
}

function testGetMerkleRootFromBytes() external view {
function testGetMerkleRootFromBytes() external pure {
bytes memory data = _getTestData();
bytes32 root = ROOT;
for (uint256 i; MerkleConstants.LOG2_LEAF_SIZE + HEIGHT + i <= MerkleConstants.LOG2_MEMORY_SIZE; ++i) {
assertEq(merkle.getMerkleRootFromBytes(data, MerkleConstants.LOG2_LEAF_SIZE + HEIGHT + i), root);
root = Merkle.join(root, PristineMerkleTree.getNodeAtHeight(HEIGHT + i));
assertEq(MerkleWrapper.getMerkleRootFromBytes(data, MerkleConstants.LOG2_LEAF_SIZE + HEIGHT + i), root);
root = MerkleWrapper.join(root, PristineMerkleTree.getNodeAtHeight(HEIGHT + i));
}
}

function testGetMerkleRootFromBytesRevertDriveSmallerThanLeaf(uint256 log2SizeOfDrive) external {
log2SizeOfDrive = bound(log2SizeOfDrive, 0, MerkleConstants.LOG2_LEAF_SIZE - 1);
vm.expectRevert("Drive smaller than leaf");
merkle.getMerkleRootFromBytes(_getTestData(), log2SizeOfDrive);
MerkleWrapper.getMerkleRootFromBytes(_getTestData(), log2SizeOfDrive);
}

function testGetMerkleRootFromBytesRevertDataLargerThanDrive(uint256 log2SizeOfDrive) external {
log2SizeOfDrive = MerkleConstants.LOG2_LEAF_SIZE + bound(log2SizeOfDrive, 0, HEIGHT - 1);
vm.expectRevert("Data larger than drive");
merkle.getMerkleRootFromBytes(_getTestData(), log2SizeOfDrive);
MerkleWrapper.getMerkleRootFromBytes(_getTestData(), log2SizeOfDrive);
}

function testGetMerkleRootFromBytesRevertDriveLargerThanMemory(uint256 log2SizeOfDrive) external {
log2SizeOfDrive = bound(log2SizeOfDrive, MerkleConstants.LOG2_MEMORY_SIZE + 1, type(uint256).max);
vm.expectRevert("Drive larger than memory");
merkle.getMerkleRootFromBytes(_getTestData(), log2SizeOfDrive);
MerkleWrapper.getMerkleRootFromBytes(_getTestData(), log2SizeOfDrive);
}

function testGetHashOfLeafAtIndex() external view {
function testGetHashOfLeafAtIndex() external pure {
bytes memory data = _getTestData();
assertEq(merkle.getHashOfLeafAtIndex(data, 0), LEAF_0);
assertEq(merkle.getHashOfLeafAtIndex(data, 1), LEAF_1);
assertEq(merkle.getHashOfLeafAtIndex(data, 2), LEAF_2);
assertEq(MerkleWrapper.getHashOfLeafAtIndex(data, 0), LEAF_0);
assertEq(MerkleWrapper.getHashOfLeafAtIndex(data, 1), LEAF_1);
assertEq(MerkleWrapper.getHashOfLeafAtIndex(data, 2), LEAF_2);
}

function testGetHashOfLeafAtIndex(bytes calldata data, uint256 index) external pure {
index = bound(index, _getNumOfLeaves(data.length), type(uint256).max);
bytes32 leafHash = PristineMerkleTree.getNodeAtHeight(0);
assertEq(Merkle.getHashOfLeafAtIndex(data, index), leafHash);
assertEq(MerkleWrapper.getHashOfLeafAtIndex(data, index), leafHash);
}

function _getTestData() internal pure returns (bytes memory) {
Expand Down

0 comments on commit 886f518

Please sign in to comment.