Add support for foundry compilation and testing (#277)

* step 1/2

* fix

* setup 2/2, foundry test added

* readme added

* fix gitmodules

* fix gitmodule

* fix git module

* :(

* forge install: forge-std

v1.9.4

* readme fix
This commit is contained in:
Nadeem Bhati
2025-01-09 16:08:55 +05:30
committed by GitHub
parent 59e7cf7fc5
commit 469bb8b925
6 changed files with 218 additions and 5 deletions

View File

@@ -5,6 +5,7 @@ coverage.json
typechain
typechain-types
cache
cache_forge
build
.openzeppelin

View File

@@ -167,4 +167,4 @@ pnpm run test
pnpm run test:reportgas
pnpm run coverage
```
```

View File

@@ -19,4 +19,4 @@ additional_compiler_profiles = [ { name = "london", evm_version = "london" } ]
compilation_restrictions = [
{ paths = "./**/L2MessageService.sol", evm_version = "london" },
{ paths = "./**/TokenBridge.sol", evm_version = "london" },
]
]

View File

@@ -1,6 +1,7 @@
import "@nomicfoundation/hardhat-toolbox";
import "@nomicfoundation/hardhat-foundry";
import "@openzeppelin/hardhat-upgrades";
import "@nomicfoundation/hardhat-foundry";
import * as dotenv from "dotenv";
import "hardhat-deploy";
import "hardhat-storage-layout";

View File

@@ -0,0 +1,211 @@
// SPDX-License-Identifier: AGPL-3.0
pragma solidity 0.8.26;
import "forge-std/Test.sol";
import "../../contracts/LineaRollup.sol";
import "../../contracts/interfaces/l1/ILineaRollup.sol";
import "../../contracts/lib/Utils.sol";
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
contract LineaRollupTestHelper is LineaRollup {
function calculateY(bytes calldata data, bytes32 dataEvaluationPoint) external pure returns (bytes32) {
return _calculateY(data, dataEvaluationPoint);
}
}
contract LineaRollupTest is Test {
LineaRollupTestHelper lineaRollup;
LineaRollupTestHelper implementation;
address operator;
address defaultAdmin;
address verifier;
address nonAuthorizedAccount;
address securityCouncil;
address fallbackOperator;
bytes32 VERIFIER_SETTER_ROLE;
bytes32 VERIFIER_UNSETTER_ROLE;
bytes32 OPERATOR_ROLE;
bytes32 DEFAULT_ADMIN_ROLE;
function setUp() public {
operator = address(0x1);
defaultAdmin = address(0x2);
verifier = address(0x3);
securityCouncil = defaultAdmin;
fallbackOperator = address(0x4);
nonAuthorizedAccount = address(0x5);
implementation = new LineaRollupTestHelper();
ILineaRollup.InitializationData memory initData;
initData.initialStateRootHash = bytes32(0x0);
initData.initialL2BlockNumber = 0;
initData.genesisTimestamp = block.timestamp;
initData.defaultVerifier = verifier;
initData.rateLimitPeriodInSeconds = 86400; // 1 day
initData.rateLimitAmountInWei = 100 ether;
initData.roleAddresses = new IPermissionsManager.RoleAddress[](1);
initData.roleAddresses[0] = IPermissionsManager.RoleAddress({
addressWithRole: operator,
role: implementation.OPERATOR_ROLE()
});
initData.pauseTypeRoles = new IPauseManager.PauseTypeRole[](0);
initData.unpauseTypeRoles = new IPauseManager.PauseTypeRole[](0);
initData.fallbackOperator = fallbackOperator;
initData.defaultAdmin = defaultAdmin;
bytes memory initializer = abi.encodeWithSelector(
LineaRollup.initialize.selector,
initData
);
ERC1967Proxy proxy = new ERC1967Proxy(address(implementation), initializer);
lineaRollup = LineaRollupTestHelper(address(proxy));
VERIFIER_SETTER_ROLE = lineaRollup.VERIFIER_SETTER_ROLE();
VERIFIER_UNSETTER_ROLE = lineaRollup.VERIFIER_UNSETTER_ROLE();
OPERATOR_ROLE = lineaRollup.OPERATOR_ROLE();
DEFAULT_ADMIN_ROLE = lineaRollup.DEFAULT_ADMIN_ROLE();
assertEq(lineaRollup.hasRole(DEFAULT_ADMIN_ROLE, defaultAdmin), true, "Default admin not set");
assertEq(lineaRollup.hasRole(OPERATOR_ROLE, operator), true, "Operator not set");
}
function testSubmitDataAsCalldata() public {
ILineaRollup.CompressedCalldataSubmission memory submission;
submission.finalStateRootHash = keccak256(abi.encodePacked("finalStateRootHash"));
submission.snarkHash = keccak256(abi.encodePacked("snarkHash"));
// Adjust compressedData to start with 0x00
submission.compressedData = hex"00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff";
bytes32 dataEvaluationPoint = Utils._efficientKeccak(
submission.snarkHash,
keccak256(submission.compressedData)
);
bytes32 dataEvaluationClaim = lineaRollup.calculateY(submission.compressedData, dataEvaluationPoint);
bytes32 parentShnarf = lineaRollup.GENESIS_SHNARF();
bytes32 expectedShnarf = keccak256(
abi.encodePacked(
parentShnarf,
submission.snarkHash,
submission.finalStateRootHash,
dataEvaluationPoint,
dataEvaluationClaim
)
);
vm.prank(operator);
lineaRollup.submitDataAsCalldata(submission, parentShnarf, expectedShnarf);
uint256 exists = lineaRollup.blobShnarfExists(expectedShnarf);
assertEq(exists, 1, "Blob shnarf should exist after submission");
}
function testChangeVerifierNotAuthorized() public {
address newVerifier = address(0x1234);
vm.prank(nonAuthorizedAccount);
vm.expectRevert(
abi.encodePacked(
"AccessControl: account ",
_toAsciiString(nonAuthorizedAccount),
" is missing role ",
_toHexString(VERIFIER_SETTER_ROLE)
)
);
lineaRollup.setVerifierAddress(newVerifier, 2);
}
function testSetVerifierAddressSuccess() public {
vm.startPrank(defaultAdmin);
lineaRollup.grantRole(VERIFIER_SETTER_ROLE, defaultAdmin);
vm.stopPrank();
address newVerifier = address(0x1234);
vm.prank(defaultAdmin);
lineaRollup.setVerifierAddress(newVerifier, 2);
assertEq(lineaRollup.verifiers(2), newVerifier, "Verifier address not updated");
}
function testUnsetVerifierAddress() public {
vm.startPrank(defaultAdmin);
lineaRollup.grantRole(VERIFIER_UNSETTER_ROLE, defaultAdmin);
lineaRollup.grantRole(VERIFIER_SETTER_ROLE, defaultAdmin);
address newVerifier = address(0x1234);
lineaRollup.setVerifierAddress(newVerifier, 0);
vm.stopPrank();
vm.prank(defaultAdmin);
lineaRollup.unsetVerifierAddress(0);
assertEq(lineaRollup.verifiers(0), address(0), "Verifier address not unset");
}
function testUnsetVerifierNotAuthorized() public {
vm.prank(nonAuthorizedAccount);
vm.expectRevert(
abi.encodePacked(
"AccessControl: account ",
_toAsciiString(nonAuthorizedAccount),
" is missing role ",
_toHexString(VERIFIER_UNSETTER_ROLE)
)
);
lineaRollup.unsetVerifierAddress(0);
}
// Helper function to convert address to ascii string
function _toAsciiString(address x) internal pure returns (string memory) {
bytes memory s = new bytes(42);
s[0] = "0";
s[1] = "x";
for (uint256 i = 0; i < 20; i++) {
uint8 b = uint8(uint256(uint160(x)) / (2**(8 * (19 - i))));
uint8 hi = b / 16;
uint8 lo = b - 16 * hi;
s[2 + 2 * i] = _char(hi);
s[3 + 2 * i] = _char(lo);
}
return string(s);
}
// Helper function to convert byte to char
function _char(uint8 b) internal pure returns (bytes1 c) {
if (b < 10) {
return bytes1(b + 0x30);
} else {
return bytes1(b + 0x57);
}
}
// Helper function to convert bytes32 to hex string
function _toHexString(bytes32 data) internal pure returns (string memory) {
return _toHexString(abi.encodePacked(data));
}
// Helper function to convert bytes to hex string
function _toHexString(bytes memory data) internal pure returns (string memory) {
bytes memory hexString = new bytes(data.length * 2 + 2);
hexString[0] = "0";
hexString[1] = "x";
bytes memory hexChars = "0123456789abcdef";
for (uint256 i = 0; i < data.length; i++) {
hexString[2 + i * 2] = hexChars[uint8(data[i] >> 4)];
hexString[3 + i * 2] = hexChars[uint8(data[i] & 0x0f)];
}
return string(hexString);
}
}

6
pnpm-lock.yaml generated
View File

@@ -15962,7 +15962,7 @@ snapshots:
debug: 4.3.7(supports-color@8.1.1)
enhanced-resolve: 5.17.1
eslint: 8.57.0
eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.6.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0)
eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.6.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.6.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0)
fast-glob: 3.3.2
get-tsconfig: 4.8.1
is-bun-module: 1.2.1
@@ -15975,7 +15975,7 @@ snapshots:
- eslint-import-resolver-webpack
- supports-color
eslint-module-utils@2.12.0(@typescript-eslint/parser@7.6.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0):
eslint-module-utils@2.12.0(@typescript-eslint/parser@7.6.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.6.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0):
dependencies:
debug: 3.2.7
optionalDependencies:
@@ -15997,7 +15997,7 @@ snapshots:
doctrine: 2.1.0
eslint: 8.57.0
eslint-import-resolver-node: 0.3.9
eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.6.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0)
eslint-module-utils: 2.12.0(@typescript-eslint/parser@7.6.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@7.6.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0)
hasown: 2.0.2
is-core-module: 2.15.1
is-glob: 4.0.3