diff --git a/l1-contracts/test/foundry/unit/concrete/Executor/Committing.t.sol b/l1-contracts/test/foundry/unit/concrete/Executor/Committing.t.sol index ce3e5947c..b1b51d7d8 100644 --- a/l1-contracts/test/foundry/unit/concrete/Executor/Committing.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/Executor/Committing.t.sol @@ -2,15 +2,42 @@ pragma solidity 0.8.24; import {Vm} from "forge-std/Test.sol"; -import {Utils, L2_BOOTLOADER_ADDRESS, L2_SYSTEM_CONTEXT_ADDRESS} from "../Utils/Utils.sol"; +import {Utils, L2_BOOTLOADER_ADDRESS, L2_SYSTEM_CONTEXT_ADDRESS, DEFAULT_L2_LOGS_TREE_ROOT_HASH} from "../Utils/Utils.sol"; import {ExecutorTest} from "./_Executor_Shared.t.sol"; - -import {IExecutor, MAX_NUMBER_OF_BLOBS} from "contracts/state-transition/chain-interfaces/IExecutor.sol"; +import {VerifierParams, FeeParams, PubdataPricingMode} from "contracts/state-transition/chain-deps/ZkSyncHyperchainStorage.sol"; +import {IExecutor, MAX_NUMBER_OF_BLOBS, PubdataSource, BLOB_SIZE_BYTES} from "contracts/state-transition/chain-interfaces/IExecutor.sol"; import {SystemLogKey} from "contracts/state-transition/chain-interfaces/IExecutor.sol"; import {POINT_EVALUATION_PRECOMPILE_ADDR} from "contracts/common/Config.sol"; -import {L2_PUBDATA_CHUNK_PUBLISHER_ADDR} from "contracts/common/L2ContractAddresses.sol"; +import {L2_PUBDATA_CHUNK_PUBLISHER_ADDR, L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR} from "contracts/common/L2ContractAddresses.sol"; +import {IStateTransitionManager} from "contracts/state-transition/IStateTransitionManager.sol"; contract CommittingTest is ExecutorTest { + function test_revertWhen_wrongCaller(address randomCaller) public { + if (randomCaller != validator) { + IExecutor.CommitBatchInfo[] memory newCommitBatchInfoArray = new IExecutor.CommitBatchInfo[](1); + newCommitBatchInfoArray[0] = newCommitBatchInfo; + + vm.prank(randomCaller); + vm.expectRevert("Hyperchain: not validator"); + executor.commitBatches(genesisStoredBatchInfo, newCommitBatchInfoArray); + } + } + + function test_RevertWhen_wrongProtocolVersion() public { + IExecutor.CommitBatchInfo[] memory newCommitBatchInfoArray = new IExecutor.CommitBatchInfo[](1); + newCommitBatchInfoArray[0] = newCommitBatchInfo; + + vm.mockCall( + stmAddress, + abi.encodeWithSelector(IStateTransitionManager.protocolVersionIsActive.selector), + abi.encode(bool(false)) + ); + + vm.prank(validator); + vm.expectRevert("Executor facet: wrong protocol version"); + executor.commitBatches(genesisStoredBatchInfo, newCommitBatchInfoArray); + } + function test_RevertWhen_CommittingWithWrongLastCommittedBatchData() public { IExecutor.CommitBatchInfo[] memory newCommitBatchInfoArray = new IExecutor.CommitBatchInfo[](1); newCommitBatchInfoArray[0] = newCommitBatchInfo; @@ -24,6 +51,21 @@ contract CommittingTest is ExecutorTest { executor.commitBatches(wrongGenesisStoredBatchInfo, newCommitBatchInfoArray); } + function test_RevertWhen_wrongPubdataSource(uint8 pubdataSource) public { + vm.assume(pubdataSource != uint8(PubdataSource.Blob) && pubdataSource != uint8(PubdataSource.Calldata)); + + IExecutor.CommitBatchInfo memory wrongNewCommitBatchInfo = newCommitBatchInfo; + wrongNewCommitBatchInfo.batchNumber = 1; + wrongNewCommitBatchInfo.pubdataCommitments[0] = bytes1(pubdataSource); + + IExecutor.CommitBatchInfo[] memory wrongNewCommitBatchInfoArray = new IExecutor.CommitBatchInfo[](1); + wrongNewCommitBatchInfoArray[0] = wrongNewCommitBatchInfo; + + vm.prank(validator); + vm.expectRevert(bytes.concat("us")); + executor.commitBatches(genesisStoredBatchInfo, wrongNewCommitBatchInfoArray); + } + function test_RevertWhen_CommittingWithWrongOrderOfBatches() public { IExecutor.CommitBatchInfo memory wrongNewCommitBatchInfo = newCommitBatchInfo; wrongNewCommitBatchInfo.batchNumber = 2; // wrong batch number @@ -83,6 +125,43 @@ contract CommittingTest is ExecutorTest { executor.commitBatches(genesisStoredBatchInfo, wrongNewCommitBatchInfoArray); } + function test_RevertWhen_previousTimestampWrong() public { + IExecutor.StoredBatchInfo memory someStoredBatchInfo = IExecutor.StoredBatchInfo({ + batchNumber: 1, + batchHash: bytes32(""), + indexRepeatedStorageChanges: 0, + numberOfLayer1Txs: 0, + priorityOperationsHash: keccak256(""), + l2LogsTreeRoot: DEFAULT_L2_LOGS_TREE_ROOT_HASH, + timestamp: 101, + commitment: bytes32("") + }); + + bytes32 _storedBatchHash = keccak256(abi.encode(someStoredBatchInfo)); + utils.util_setStoredBatchHashes(1, _storedBatchHash); + utils.util_setTotalBatchesCommitted(1); + + bytes[] memory wrongL2Logs = Utils.createSystemLogs(); + wrongL2Logs[uint256(uint256(SystemLogKey.PACKED_BATCH_AND_L2_BLOCK_TIMESTAMP_KEY))] = Utils.constructL2Log( + true, + L2_SYSTEM_CONTEXT_ADDRESS, + uint256(SystemLogKey.PACKED_BATCH_AND_L2_BLOCK_TIMESTAMP_KEY), + Utils.packBatchTimestampAndBlockTimestamp(100, 100) + ); + + IExecutor.CommitBatchInfo memory wrongNewCommitBatchInfo = newCommitBatchInfo; + wrongNewCommitBatchInfo.systemLogs = Utils.encodePacked(wrongL2Logs); + wrongNewCommitBatchInfo.timestamp = uint64(100); + wrongNewCommitBatchInfo.batchNumber = 2; + + IExecutor.CommitBatchInfo[] memory wrongNewCommitBatchInfoArray = new IExecutor.CommitBatchInfo[](1); + wrongNewCommitBatchInfoArray[0] = wrongNewCommitBatchInfo; + + vm.prank(validator); + vm.expectRevert(bytes.concat("h3")); + executor.commitBatches(someStoredBatchInfo, wrongNewCommitBatchInfoArray); + } + function test_RevertWhen_CommittingTooBigLastL2BatchTimestamp() public { uint64 wrongNewBatchTimestamp = 0xffffffff; bytes[] memory wrongL2Logs = Utils.createSystemLogs(); @@ -106,6 +185,69 @@ contract CommittingTest is ExecutorTest { executor.commitBatches(genesisStoredBatchInfo, wrongNewCommitBatchInfoArray); } + function test_RevertWhen_validiumDataWrongCommitmentsLength() public { + FeeParams memory feeParams = defaultFeeParams(); + feeParams.pubdataPricingMode = PubdataPricingMode.Validium; + utils.util_setFeeParams(feeParams); + + bytes[] memory wrongL2Logs = Utils.createSystemLogs(); + IExecutor.CommitBatchInfo memory wrongNewCommitBatchInfo = newCommitBatchInfo; + wrongNewCommitBatchInfo.systemLogs = Utils.encodePacked(wrongL2Logs); + IExecutor.CommitBatchInfo[] memory wrongNewCommitBatchInfoArray = new IExecutor.CommitBatchInfo[](1); + wrongNewCommitBatchInfoArray[0] = wrongNewCommitBatchInfo; + + vm.prank(validator); + vm.expectRevert(bytes.concat("EF: v0l")); + executor.commitBatches(genesisStoredBatchInfo, wrongNewCommitBatchInfoArray); + } + + function test_RevertWhen_tooLongPubdataCommitment() public { + IExecutor.CommitBatchInfo memory wrongNewCommitBatchInfo = newCommitBatchInfo; + wrongNewCommitBatchInfo.batchNumber = 1; + bytes memory pubdataCommitment = new bytes(BLOB_SIZE_BYTES + 1); + wrongNewCommitBatchInfo.pubdataCommitments = pubdataCommitment; + wrongNewCommitBatchInfo.pubdataCommitments[0] = bytes1(uint8(PubdataSource.Calldata)); + + IExecutor.CommitBatchInfo[] memory wrongNewCommitBatchInfoArray = new IExecutor.CommitBatchInfo[](1); + wrongNewCommitBatchInfoArray[0] = wrongNewCommitBatchInfo; + + vm.prank(validator); + vm.expectRevert(bytes.concat("cz")); + executor.commitBatches(genesisStoredBatchInfo, wrongNewCommitBatchInfoArray); + } + + function hashSlice(bytes memory data, uint256 start, uint256 end) internal pure returns (bytes32) { + bytes memory slice = new bytes(end - start); + for (uint256 i = start; i < end; i++) { + slice[i - start] = data[i]; + } + return keccak256(slice); + } + + function test_RevertWhen_pubdataHashAndCommitmentMismatch() public { + bytes[] memory wrongL2Logs = Utils.createSystemLogs(); + bytes memory pubdataCommitment = new bytes(64); + bytes32 pubdataCommitmentHash = hashSlice(pubdataCommitment, 1, pubdataCommitment.length - 32); + wrongL2Logs[uint256(uint256(SystemLogKey.TOTAL_L2_TO_L1_PUBDATA_KEY))] = Utils.constructL2Log( + true, + L2_TO_L1_MESSENGER_SYSTEM_CONTRACT_ADDR, + uint256(SystemLogKey.TOTAL_L2_TO_L1_PUBDATA_KEY), + bytes32("") + ); + IExecutor.CommitBatchInfo memory wrongNewCommitBatchInfo = newCommitBatchInfo; + wrongNewCommitBatchInfo.batchNumber = 1; + wrongNewCommitBatchInfo.systemLogs = Utils.encodePacked(wrongL2Logs); + wrongNewCommitBatchInfo.pubdataCommitments = pubdataCommitment; + wrongNewCommitBatchInfo.pubdataCommitments[0] = bytes1(uint8(PubdataSource.Calldata)); + + IExecutor.CommitBatchInfo[] memory wrongNewCommitBatchInfoArray = new IExecutor.CommitBatchInfo[](1); + wrongNewCommitBatchInfoArray[0] = wrongNewCommitBatchInfo; + + vm.prank(validator); + vm.expectRevert(bytes.concat("wp")); + executor.commitBatches(genesisStoredBatchInfo, wrongNewCommitBatchInfoArray); + } + function test_RevertWhen_CommittingWithWrongPreviousBatchHash() public { bytes32 wrongPreviousBatchHash = Utils.randomBytes32("wrongPreviousBatchHash"); bytes[] memory wrongL2Logs = Utils.createSystemLogs(); @@ -256,61 +398,199 @@ contract CommittingTest is ExecutorTest { executor.commitBatches(genesisStoredBatchInfo, wrongNewCommitBatchInfoArray); } + function _getCommitInfoWithLogs(bytes[] memory logs) internal returns (IExecutor.CommitBatchInfo[] memory) { + IExecutor.CommitBatchInfo memory wrongNewCommitBatchInfo = newCommitBatchInfo; + wrongNewCommitBatchInfo.systemLogs = Utils.encodePacked(logs); + IExecutor.CommitBatchInfo[] memory wrongNewCommitBatchInfoArray = new IExecutor.CommitBatchInfo[](1); + wrongNewCommitBatchInfoArray[0] = wrongNewCommitBatchInfo; + + return wrongNewCommitBatchInfoArray; + } + function test_RevertWhen_SystemLogIsFromIncorrectAddress() public { - bytes32[7] memory values = [ + bytes32[15] memory values = [ bytes32(""), bytes32(0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563), bytes32(""), bytes32(""), bytes32(""), keccak256(""), + bytes32(""), + bytes32(""), + bytes32(""), + bytes32(""), + bytes32(""), + bytes32(""), + bytes32(""), + bytes32(""), bytes32("") ]; - bytes[7] memory errors = [ + bytes[15] memory errors = [ bytes.concat("lm"), bytes.concat("ln"), bytes.concat("lb"), bytes.concat("sc"), bytes.concat("sv"), bytes.concat("bl"), - bytes.concat("bk") + bytes.concat("bk"), + bytes.concat("pc"), + bytes.concat("pc"), + bytes.concat("pc"), + bytes.concat("pc"), + bytes.concat("pc"), + bytes.concat("pc"), + bytes.concat("bu"), + bytes.concat("ul") ]; + address wrongAddress = makeAddr("randomAddress"); + for (uint256 i = 0; i < values.length; i++) { - bytes[] memory wrongL2Logs = Utils.createSystemLogs(); - address wrongAddress = makeAddr("randomAddress"); - wrongL2Logs[i] = Utils.constructL2Log(true, wrongAddress, i, values[i]); + bytes[] memory wrongL2Logs = Utils.createSystemLogsWithUpgradeTransaction(bytes32("")); + bytes[] memory tooManyLogs = new bytes[](15); - IExecutor.CommitBatchInfo memory wrongNewCommitBatchInfo = newCommitBatchInfo; - wrongNewCommitBatchInfo.systemLogs = Utils.encodePacked(wrongL2Logs); + for (uint256 i = 0; i < wrongL2Logs.length; i++) { + tooManyLogs[i] = wrongL2Logs[i]; + } + + tooManyLogs[i] = Utils.constructL2Log(true, wrongAddress, i, values[i]); + IExecutor.CommitBatchInfo memory wrongNewCommitBatchInfo = newCommitBatchInfo; + wrongNewCommitBatchInfo.systemLogs = Utils.encodePacked(tooManyLogs); IExecutor.CommitBatchInfo[] memory wrongNewCommitBatchInfoArray = new IExecutor.CommitBatchInfo[](1); wrongNewCommitBatchInfoArray[0] = wrongNewCommitBatchInfo; vm.prank(validator); - vm.expectRevert(errors[i]); executor.commitBatches(genesisStoredBatchInfo, wrongNewCommitBatchInfoArray); } + + bytes[] memory logsWithWrongHash = Utils.createSystemLogsWithUpgradeTransaction(bytes32("")); + logsWithWrongHash[logsWithWrongHash.length - 1] = Utils.constructL2Log( + true, + L2_BOOTLOADER_ADDRESS, + logsWithWrongHash.length - 1, + bytes32("1") + ); + + IExecutor.CommitBatchInfo memory wrongNewCommitBatchInfo = newCommitBatchInfo; + wrongNewCommitBatchInfo.systemLogs = Utils.encodePacked(logsWithWrongHash); + IExecutor.CommitBatchInfo[] memory wrongNewCommitBatchInfoArray = new IExecutor.CommitBatchInfo[](1); + wrongNewCommitBatchInfoArray[0] = wrongNewCommitBatchInfo; + + vm.prank(validator); + vm.expectRevert(bytes.concat("ut")); + executor.commitBatches(genesisStoredBatchInfo, wrongNewCommitBatchInfoArray); + } + + function test_RevertWhen_systemLogsBadLength() public { + utils.util_setL2SystemContractsUpgradeTxHash(bytes32("not default")); + bytes[] memory logs = Utils.createSystemLogsWithUpgradeTransaction(bytes32("not default")); + delete logs[0]; + + IExecutor.CommitBatchInfo memory wrongNewCommitBatchInfo = newCommitBatchInfo; + wrongNewCommitBatchInfo.systemLogs = Utils.encodePacked(logs); + IExecutor.CommitBatchInfo[] memory wrongNewCommitBatchInfoArray = new IExecutor.CommitBatchInfo[](1); + wrongNewCommitBatchInfoArray[0] = wrongNewCommitBatchInfo; + + vm.prank(validator); + vm.expectRevert(bytes.concat("b8")); + executor.commitBatches(genesisStoredBatchInfo, wrongNewCommitBatchInfoArray); } function test_RevertWhen_SystemLogIsMissing() public { - for (uint256 i = 0; i < 7; i++) { - bytes[] memory l2Logs = Utils.createSystemLogs(); - delete l2Logs[i]; + bytes[] memory logs = Utils.createSystemLogs(); + delete logs[0]; - IExecutor.CommitBatchInfo memory wrongNewCommitBatchInfo = newCommitBatchInfo; - wrongNewCommitBatchInfo.systemLogs = Utils.encodePacked(l2Logs); + IExecutor.CommitBatchInfo memory wrongNewCommitBatchInfo = newCommitBatchInfo; + wrongNewCommitBatchInfo.systemLogs = Utils.encodePacked(logs); + IExecutor.CommitBatchInfo[] memory wrongNewCommitBatchInfoArray = new IExecutor.CommitBatchInfo[](1); + wrongNewCommitBatchInfoArray[0] = wrongNewCommitBatchInfo; - IExecutor.CommitBatchInfo[] memory wrongNewCommitBatchInfoArray = new IExecutor.CommitBatchInfo[](1); - wrongNewCommitBatchInfoArray[0] = wrongNewCommitBatchInfo; + vm.prank(validator); + vm.expectRevert(bytes.concat("b7")); + executor.commitBatches(genesisStoredBatchInfo, wrongNewCommitBatchInfoArray); + } - vm.prank(validator); + function test_successfullyCommitBatchWithSystemUpgrade() public { + // upgrade batch number must be zero to proceed + utils.util_setL2SystemContractsUpgradeBatchNumber(0); + // upgrade tx hash must be non zero to proceed + utils.util_setL2SystemContractsUpgradeTxHash(bytes32("not default")); - vm.expectRevert(bytes.concat("b7")); - executor.commitBatches(genesisStoredBatchInfo, wrongNewCommitBatchInfoArray); - } + // first new batch logs must contain upgrade transaction + // ugrade batch number will be batch number of this batch + bytes[] memory upgradeLogs = Utils.createSystemLogsWithUpgradeTransaction(bytes32("not default")); + uint64 upgradeBatchNumber = 1; + + upgradeLogs[uint256(SystemLogKey.PACKED_BATCH_AND_L2_BLOCK_TIMESTAMP_KEY)] = Utils.constructL2Log( + true, + L2_SYSTEM_CONTEXT_ADDRESS, + uint256(SystemLogKey.PACKED_BATCH_AND_L2_BLOCK_TIMESTAMP_KEY), + Utils.packBatchTimestampAndBlockTimestamp(currentTimestamp, currentTimestamp) + ); + upgradeLogs[uint256(SystemLogKey.BLOB_ONE_HASH_KEY)] = Utils.constructL2Log( + true, + L2_PUBDATA_CHUNK_PUBLISHER_ADDR, + uint256(SystemLogKey.BLOB_ONE_HASH_KEY), + 0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563 + ); + + IExecutor.CommitBatchInfo memory upgradeBatch = newCommitBatchInfo; + upgradeBatch.batchNumber = upgradeBatchNumber; + upgradeBatch.systemLogs = Utils.encodePacked(upgradeLogs); + upgradeBatch.pubdataCommitments = abi.encodePacked( + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", + bytes32(uint256(0xbeef)) + ); + + bytes32[] memory blobHashes = new bytes32[](MAX_NUMBER_OF_BLOBS); + blobHashes[0] = 0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563; + + bytes32[] memory blobCommitments = new bytes32[](MAX_NUMBER_OF_BLOBS); + blobCommitments[0] = bytes32(uint256(0xbeef)); + + bytes32 expectedBatchCommitment = Utils.createBatchCommitment( + upgradeBatch, + bytes32(""), + blobCommitments, + blobHashes + ); + + IExecutor.CommitBatchInfo[] memory batchInfoArray = new IExecutor.CommitBatchInfo[](1); + batchInfoArray[0] = upgradeBatch; + + vm.prank(validator); + // solhint-disable-next-line func-named-parameters + vm.expectEmit(true, true, true, true, address(executor)); + emit BlockCommit(1, upgradeBatch.newStateRoot, expectedBatchCommitment); + executor.commitBatches(genesisStoredBatchInfo, batchInfoArray); + + assertEq(getters.getTotalBatchesCommitted(), 1); + assertEq(getters.getL2SystemContractsUpgradeBatchNumber(), upgradeBatchNumber); + assertEq(getters.getL2SystemContractsUpgradeTxHash(), bytes32("not default")); + + IExecutor.StoredBatchInfo memory lastBatch = IExecutor.StoredBatchInfo({ + batchNumber: 1, + batchHash: Utils.randomBytes32("newStateRoot"), + indexRepeatedStorageChanges: 0, + numberOfLayer1Txs: 0, + priorityOperationsHash: keccak256(""), + l2LogsTreeRoot: DEFAULT_L2_LOGS_TREE_ROOT_HASH, + timestamp: currentTimestamp, + commitment: expectedBatchCommitment + }); + + assertEq(utils.util_getStoredBatchHashes(1), keccak256(abi.encode(lastBatch))); + + batchInfoArray[0].batchNumber += 1; + + // this proves that upgrade batch number is not zero in second call + // and it doesn't go through branch with upgrade + vm.expectRevert(bytes.concat("ut")); + vm.prank(validator); + executor.commitBatches(lastBatch, batchInfoArray); } function test_SuccessfullyCommitBatch() public { @@ -352,21 +632,12 @@ contract CommittingTest is ExecutorTest { correctCommitBatchInfoArray[0] = correctNewCommitBatchInfo; vm.prank(validator); - - vm.recordLogs(); + // solhint-disable-next-line func-named-parameters + vm.expectEmit(true, true, true, true, address(executor)); + emit BlockCommit(1, correctNewCommitBatchInfo.newStateRoot, expectedBatchCommitment); executor.commitBatches(genesisStoredBatchInfo, correctCommitBatchInfoArray); - - Vm.Log[] memory entries = vm.getRecordedLogs(); - - assertEq(entries.length, 1); - assertEq(entries[0].topics[0], keccak256("BlockCommit(uint256,bytes32,bytes32)")); - assertEq(entries[0].topics[1], bytes32(uint256(1))); // batchNumber - assertEq(entries[0].topics[2], correctNewCommitBatchInfo.newStateRoot); // batchHash - assertEq(entries[0].topics[3], expectedBatchCommitment); // commitment - - uint256 totalBatchesCommitted = getters.getTotalBatchesCommitted(); - assertEq(totalBatchesCommitted, 1); + assertEq(getters.getTotalBatchesCommitted(), 1); } function test_SuccessfullyCommitBatchWithOneBlob() public { @@ -407,17 +678,10 @@ contract CommittingTest is ExecutorTest { correctCommitBatchInfoArray[0].pubdataCommitments = pubdataCommitment; vm.prank(validator); - - vm.recordLogs(); - + vm.expectEmit(true, false, false, false, address(executor)); + emit BlockCommit(1, bytes32(0), bytes32(0)); executor.commitBatches(genesisStoredBatchInfo, correctCommitBatchInfoArray); - Vm.Log[] memory entries = vm.getRecordedLogs(); - - assertEq(entries.length, 1); - assertEq(entries[0].topics[0], keccak256("BlockCommit(uint256,bytes32,bytes32)")); - assertEq(entries[0].topics[1], bytes32(uint256(1))); // batchNumber - uint256 totalBatchesCommitted = getters.getTotalBatchesCommitted(); assertEq(totalBatchesCommitted, 1); @@ -480,20 +744,12 @@ contract CommittingTest is ExecutorTest { correctCommitBatchInfoArray[0].pubdataCommitments = pubdataCommitment; vm.prank(validator); - - vm.recordLogs(); - + // solhint-disable-next-line func-named-parameters + vm.expectEmit(true, false, false, false, address(executor)); + emit BlockCommit(1, bytes32(0), bytes32(0)); executor.commitBatches(genesisStoredBatchInfo, correctCommitBatchInfoArray); - Vm.Log[] memory entries = vm.getRecordedLogs(); - - assertEq(entries.length, 1); - assertEq(entries[0].topics[0], keccak256("BlockCommit(uint256,bytes32,bytes32)")); - assertEq(entries[0].topics[1], bytes32(uint256(1))); // batchNumber - - uint256 totalBatchesCommitted = getters.getTotalBatchesCommitted(); - assertEq(totalBatchesCommitted, 1); - + assertEq(getters.getTotalBatchesCommitted(), 1); vm.clearMockedCalls(); } diff --git a/l1-contracts/test/foundry/unit/concrete/Executor/Executing.t.sol b/l1-contracts/test/foundry/unit/concrete/Executor/Executing.t.sol index 3360150d5..3889acbab 100644 --- a/l1-contracts/test/foundry/unit/concrete/Executor/Executing.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/Executor/Executing.t.sol @@ -54,6 +54,74 @@ contract ExecutingTest is ExecutorTest { executor.proveBatches(genesisStoredBatchInfo, storedBatchInfoArray, proofInput); } + function _commitAndProveMultipleBatches( + uint256 _count, + uint256 _startBatchNumber + ) internal returns (IExecutor.StoredBatchInfo[] memory storedBatchInfos) { + uint256 timestamp = currentTimestamp + 1; + + IExecutor.StoredBatchInfo[] memory storedBatchInfoArray = new IExecutor.StoredBatchInfo[](_count); + IExecutor.StoredBatchInfo memory lastCommitted = newStoredBatchInfo; + IExecutor.StoredBatchInfo memory lastProved = newStoredBatchInfo; + + for (uint256 i = 0; i < _count; i++) { + uint256 batchTimestamp = timestamp + i; + bytes[] memory correctL2Logs = Utils.createSystemLogs(); + + correctL2Logs[uint256(uint256(SystemLogKey.PACKED_BATCH_AND_L2_BLOCK_TIMESTAMP_KEY))] = Utils + .constructL2Log( + true, + L2_SYSTEM_CONTEXT_ADDRESS, + uint256(SystemLogKey.PACKED_BATCH_AND_L2_BLOCK_TIMESTAMP_KEY), + Utils.packBatchTimestampAndBlockTimestamp(batchTimestamp, batchTimestamp) + ); + + correctL2Logs[uint256(uint256(SystemLogKey.PREV_BATCH_HASH_KEY))] = Utils.constructL2Log( + true, + L2_SYSTEM_CONTEXT_ADDRESS, + uint256(SystemLogKey.PREV_BATCH_HASH_KEY), + lastCommitted.batchHash + ); + + bytes memory l2Logs = Utils.encodePacked(correctL2Logs); + + IExecutor.CommitBatchInfo memory commitBatch = newCommitBatchInfo; + commitBatch.systemLogs = l2Logs; + commitBatch.timestamp = uint64(batchTimestamp); + commitBatch.batchNumber = uint64(_startBatchNumber + i); + + IExecutor.CommitBatchInfo[] memory commitBatchInfoArray = new IExecutor.CommitBatchInfo[](1); + commitBatchInfoArray[0] = commitBatch; + + vm.recordLogs(); + vm.prank(validator); + executor.commitBatches(lastCommitted, commitBatchInfoArray); + + Vm.Log[] memory entries = vm.getRecordedLogs(); + lastCommitted = IExecutor.StoredBatchInfo({ + batchNumber: uint64(_startBatchNumber + i), + batchHash: entries[0].topics[2], + indexRepeatedStorageChanges: 0, + numberOfLayer1Txs: 0, + priorityOperationsHash: keccak256(""), + l2LogsTreeRoot: 0, + timestamp: batchTimestamp, + commitment: entries[0].topics[3] + }); + + IExecutor.StoredBatchInfo[] memory toProve = new IExecutor.StoredBatchInfo[](1); + toProve[0] = lastCommitted; + + vm.prank(validator); + executor.proveBatches(lastProved, toProve, proofInput); + + storedBatchInfoArray[i] = lastCommitted; + lastProved = lastCommitted; + } + + return storedBatchInfoArray; + } + function test_RevertWhen_ExecutingBlockWithWrongBatchNumber() public { IExecutor.StoredBatchInfo memory wrongNewStoredBatchInfo = newStoredBatchInfo; wrongNewStoredBatchInfo.batchNumber = 10; // Correct is 1 @@ -254,10 +322,71 @@ contract ExecutingTest is ExecutorTest { IExecutor.StoredBatchInfo[] memory storedBatchInfoArray = new IExecutor.StoredBatchInfo[](1); storedBatchInfoArray[0] = newStoredBatchInfo; + // solhint-disable-next-line func-named-parameters + vm.expectEmit(true, true, true, true, address(executor)); + emit BlockExecution( + newStoredBatchInfo.batchNumber, + newStoredBatchInfo.batchHash, + newStoredBatchInfo.commitment + ); + + vm.prank(validator); + executor.executeBatches(storedBatchInfoArray); + + assertEq(getters.getTotalBlocksExecuted(), 1); + assertEq(getters.l2LogsRootHash(newStoredBatchInfo.batchNumber), newStoredBatchInfo.l2LogsTreeRoot); + } + + function test_shouldDeleteSystemUpgradeData(uint256 batchNumberBefore) public { + IExecutor.StoredBatchInfo[] memory storedBatchInfoArray = new IExecutor.StoredBatchInfo[](4); + IExecutor.StoredBatchInfo[] memory newbatches = _commitAndProveMultipleBatches(3, 2); + storedBatchInfoArray[0] = newStoredBatchInfo; + storedBatchInfoArray[1] = newbatches[0]; + storedBatchInfoArray[2] = newbatches[1]; + storedBatchInfoArray[3] = newbatches[2]; + + batchNumberBefore = bound(batchNumberBefore, 1, newbatches[2].batchNumber); + utils.util_setL2SystemContractsUpgradeBatchNumber(1); + utils.util_setL2SystemContractsUpgradeTxHash(bytes32("upgrade hash")); + + vm.prank(validator); + executor.executeBatches(storedBatchInfoArray); + + assertEq(getters.getTotalBlocksExecuted(), 4); + assertEq(getters.getL2SystemContractsUpgradeBatchNumber(), 0); + assertEq(getters.getL2SystemContractsUpgradeTxHash(), bytes32(0)); + assertEq(getters.l2LogsRootHash(newbatches[2].batchNumber), newbatches[2].l2LogsTreeRoot); + } + + function test_shouldNotDeleteSystemUpgradeData(uint256 batchNumberAfter) public { + IExecutor.StoredBatchInfo[] memory storedBatchInfoArray = new IExecutor.StoredBatchInfo[](4); + IExecutor.StoredBatchInfo[] memory newbatches = _commitAndProveMultipleBatches(3, 2); + storedBatchInfoArray[0] = newStoredBatchInfo; + storedBatchInfoArray[1] = newbatches[0]; + storedBatchInfoArray[2] = newbatches[1]; + storedBatchInfoArray[3] = newbatches[2]; + + batchNumberAfter = bound(batchNumberAfter, newbatches[2].batchNumber + 1, type(uint256).max); + utils.util_setL2SystemContractsUpgradeBatchNumber(batchNumberAfter); + utils.util_setL2SystemContractsUpgradeTxHash(bytes32("upgrade hash")); + vm.prank(validator); executor.executeBatches(storedBatchInfoArray); - uint256 totalBlocksExecuted = getters.getTotalBlocksExecuted(); - assertEq(totalBlocksExecuted, 1); + assertEq(getters.getTotalBlocksExecuted(), 4); + assertEq(getters.getL2SystemContractsUpgradeBatchNumber(), batchNumberAfter); + assertEq(getters.getL2SystemContractsUpgradeTxHash(), bytes32("upgrade hash")); + assertEq(getters.l2LogsRootHash(newbatches[2].batchNumber), newbatches[2].l2LogsTreeRoot); + } + + function test_shouldBeCalledOnlyByValidator(address caller) public { + vm.assume(caller != validator); + + IExecutor.StoredBatchInfo[] memory storedBatchInfoArray = new IExecutor.StoredBatchInfo[](1); + storedBatchInfoArray[0] = newStoredBatchInfo; + + vm.expectRevert("Hyperchain: not validator"); + vm.prank(caller); + executor.executeBatches(storedBatchInfoArray); } } diff --git a/l1-contracts/test/foundry/unit/concrete/Executor/Proving.t.sol b/l1-contracts/test/foundry/unit/concrete/Executor/Proving.t.sol index 184de78e2..1477a21fa 100644 --- a/l1-contracts/test/foundry/unit/concrete/Executor/Proving.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/Executor/Proving.t.sol @@ -6,8 +6,9 @@ import {Utils, L2_SYSTEM_CONTEXT_ADDRESS} from "../Utils/Utils.sol"; import {ExecutorTest} from "./_Executor_Shared.t.sol"; -import {COMMIT_TIMESTAMP_NOT_OLDER} from "contracts/common/Config.sol"; +import {COMMIT_TIMESTAMP_NOT_OLDER, PUBLIC_INPUT_SHIFT} from "contracts/common/Config.sol"; import {IExecutor, SystemLogKey} from "contracts/state-transition/chain-interfaces/IExecutor.sol"; +import {IVerifier} from "contracts/state-transition/chain-interfaces/IVerifier.sol"; contract ProvingTest is ExecutorTest { function setUp() public { @@ -47,6 +48,73 @@ contract ProvingTest is ExecutorTest { }); } + function _commitMultipleBatches( + uint256 _count, + uint256 _startBatchNumber + ) internal returns (IExecutor.StoredBatchInfo[] memory storedBatchInfos) { + uint256 timestamp = currentTimestamp + 1; + + IExecutor.StoredBatchInfo[] memory storedBatchInfoArray = new IExecutor.StoredBatchInfo[](_count); + IExecutor.StoredBatchInfo memory lastCommitted = newStoredBatchInfo; + + for (uint256 i = 0; i < _count; i++) { + uint256 batchTimestamp = timestamp + i; + bytes[] memory correctL2Logs = Utils.createSystemLogs(); + + correctL2Logs[uint256(uint256(SystemLogKey.PACKED_BATCH_AND_L2_BLOCK_TIMESTAMP_KEY))] = Utils + .constructL2Log( + true, + L2_SYSTEM_CONTEXT_ADDRESS, + uint256(SystemLogKey.PACKED_BATCH_AND_L2_BLOCK_TIMESTAMP_KEY), + Utils.packBatchTimestampAndBlockTimestamp(batchTimestamp, batchTimestamp) + ); + + correctL2Logs[uint256(uint256(SystemLogKey.PREV_BATCH_HASH_KEY))] = Utils.constructL2Log( + true, + L2_SYSTEM_CONTEXT_ADDRESS, + uint256(SystemLogKey.PREV_BATCH_HASH_KEY), + lastCommitted.batchHash + ); + + bytes memory l2Logs = Utils.encodePacked(correctL2Logs); + + IExecutor.CommitBatchInfo memory commitBatch = newCommitBatchInfo; + commitBatch.systemLogs = l2Logs; + commitBatch.timestamp = uint64(batchTimestamp); + commitBatch.batchNumber = uint64(_startBatchNumber + i); + + IExecutor.CommitBatchInfo[] memory commitBatchInfoArray = new IExecutor.CommitBatchInfo[](1); + commitBatchInfoArray[0] = commitBatch; + + vm.recordLogs(); + vm.prank(validator); + executor.commitBatches(lastCommitted, commitBatchInfoArray); + + Vm.Log[] memory entries = vm.getRecordedLogs(); + lastCommitted = IExecutor.StoredBatchInfo({ + batchNumber: uint64(_startBatchNumber + i), + batchHash: entries[0].topics[2], + indexRepeatedStorageChanges: 0, + numberOfLayer1Txs: 0, + priorityOperationsHash: keccak256(""), + l2LogsTreeRoot: 0, + timestamp: batchTimestamp, + commitment: entries[0].topics[3] + }); + + storedBatchInfoArray[i] = lastCommitted; + } + + return storedBatchInfoArray; + } + + function test_RevertWhen_wrongCaller(address _caller) public { + vm.assume(_caller != validator); + + vm.expectRevert("Hyperchain: not validator"); + executor.proveBatches(genesisStoredBatchInfo, new IExecutor.StoredBatchInfo[](0), proofInput); + } + function test_RevertWhen_ProvingWithWrongPreviousBlockData() public { IExecutor.StoredBatchInfo memory wrongPreviousStoredBatchInfo = genesisStoredBatchInfo; wrongPreviousStoredBatchInfo.batchNumber = 10; // Correct is 0 @@ -86,15 +154,51 @@ contract ProvingTest is ExecutorTest { executor.proveBatches(genesisStoredBatchInfo, storedBatchInfoArray, proofInput); } + function test_RevertWhen_proveMultipleBatches() public { + IExecutor.StoredBatchInfo[] memory storedBatchInfos = _commitMultipleBatches(2, 2); + IExecutor.StoredBatchInfo[] memory storedBatchInfoArray = new IExecutor.StoredBatchInfo[](3); + storedBatchInfoArray[0] = newStoredBatchInfo; + storedBatchInfoArray[1] = storedBatchInfos[0]; + storedBatchInfoArray[2] = storedBatchInfos[1]; + + vm.prank(validator); + vm.expectRevert(bytes.concat("t4")); + executor.proveBatches(genesisStoredBatchInfo, storedBatchInfoArray, proofInput); + } + + function test_RevertWhen_verifyFailed() public { + IExecutor.StoredBatchInfo[] memory storedBatchInfoArray = new IExecutor.StoredBatchInfo[](1); + storedBatchInfoArray[0] = newStoredBatchInfo; + + vm.prank(validator); + uint256[] memory proofPublicInput = new uint256[](1); + proofPublicInput[0] = + uint256(keccak256(abi.encodePacked(genesisStoredBatchInfo.commitment, newStoredBatchInfo.commitment))) >> + PUBLIC_INPUT_SHIFT; + + vm.mockCall( + testnetVerifierAddress, + abi.encodeWithSelector( + IVerifier.verify.selector, + proofPublicInput, + proofInput.serializedProof, + proofInput.recursiveAggregationInput + ), + abi.encode(false) + ); + vm.expectRevert(bytes.concat("p")); + executor.proveBatches(genesisStoredBatchInfo, storedBatchInfoArray, proofInput); + } + function test_SuccessfulProve() public { IExecutor.StoredBatchInfo[] memory storedBatchInfoArray = new IExecutor.StoredBatchInfo[](1); storedBatchInfoArray[0] = newStoredBatchInfo; vm.prank(validator); + vm.expectEmit(true, false, false, false, address(executor)); + emit BlocksVerification({previousLastVerifiedBatch: 0, currentLastVerifiedBatch: 1}); executor.proveBatches(genesisStoredBatchInfo, storedBatchInfoArray, proofInput); - - uint256 totalBlocksVerified = getters.getTotalBlocksVerified(); - assertEq(totalBlocksVerified, 1); + assertEq(getters.getTotalBlocksVerified(), 1); } } diff --git a/l1-contracts/test/foundry/unit/concrete/Executor/_Executor_Shared.t.sol b/l1-contracts/test/foundry/unit/concrete/Executor/_Executor_Shared.t.sol index b96602f63..10fa5ddc3 100644 --- a/l1-contracts/test/foundry/unit/concrete/Executor/_Executor_Shared.t.sol +++ b/l1-contracts/test/foundry/unit/concrete/Executor/_Executor_Shared.t.sol @@ -20,16 +20,21 @@ import {IExecutor} from "contracts/state-transition/chain-interfaces/IExecutor.s import {IVerifier} from "contracts/state-transition/chain-interfaces/IVerifier.sol"; import {Diamond} from "contracts/state-transition/libraries/Diamond.sol"; import {TestnetVerifier} from "contracts/state-transition/TestnetVerifier.sol"; +import {Utils} from "foundry-test/unit/concrete/Utils/Utils.sol"; +import {UtilsFacet} from "foundry-test/unit/concrete/Utils/UtilsFacet.sol"; contract ExecutorTest is Test { + address internal stmAddress; address internal owner; address internal validator; address internal randomSigner; address internal blobVersionedHashRetriever; + address internal testnetVerifierAddress; AdminFacet internal admin; TestExecutor internal executor; GettersFacet internal getters; MailboxFacet internal mailbox; + UtilsFacet internal utils; bytes32 internal newCommittedBlockBatchHash; bytes32 internal newCommittedBlockCommitment; uint256 internal currentTimestamp; @@ -41,6 +46,10 @@ contract ExecutorTest is Test { IExecutor.StoredBatchInfo internal genesisStoredBatchInfo; IExecutor.ProofInput internal proofInput; + event BlockCommit(uint256 indexed batchNumber, bytes32 indexed batchHash, bytes32 indexed commitment); + event BlockExecution(uint256 indexed batchNumber, bytes32 indexed batchHash, bytes32 indexed commitment); + event BlocksVerification(uint256 indexed previousLastVerifiedBatch, uint256 indexed currentLastVerifiedBatch); + function getAdminSelectors() private view returns (bytes4[] memory) { bytes4[] memory selectors = new bytes4[](11); selectors[0] = admin.setPendingAdmin.selector; @@ -66,39 +75,6 @@ contract ExecutorTest is Test { return selectors; } - function getGettersSelectors() public view returns (bytes4[] memory) { - bytes4[] memory selectors = new bytes4[](28); - selectors[0] = getters.getVerifier.selector; - selectors[1] = getters.getAdmin.selector; - selectors[2] = getters.getPendingAdmin.selector; - selectors[3] = getters.getTotalBlocksCommitted.selector; - selectors[4] = getters.getTotalBlocksVerified.selector; - selectors[5] = getters.getTotalBlocksExecuted.selector; - selectors[6] = getters.getTotalPriorityTxs.selector; - selectors[7] = getters.getFirstUnprocessedPriorityTx.selector; - selectors[8] = getters.getPriorityQueueSize.selector; - selectors[9] = getters.priorityQueueFrontOperation.selector; - selectors[10] = getters.isValidator.selector; - selectors[11] = getters.l2LogsRootHash.selector; - selectors[12] = getters.storedBatchHash.selector; - selectors[13] = getters.getL2BootloaderBytecodeHash.selector; - selectors[14] = getters.getL2DefaultAccountBytecodeHash.selector; - selectors[15] = getters.getVerifierParams.selector; - selectors[16] = getters.isDiamondStorageFrozen.selector; - selectors[17] = getters.getPriorityTxMaxGasLimit.selector; - selectors[18] = getters.isEthWithdrawalFinalized.selector; - selectors[19] = getters.facets.selector; - selectors[20] = getters.facetFunctionSelectors.selector; - selectors[21] = getters.facetAddresses.selector; - selectors[22] = getters.facetAddress.selector; - selectors[23] = getters.isFunctionFreezable.selector; - selectors[24] = getters.isFacetFreezable.selector; - selectors[25] = getters.getTotalBatchesCommitted.selector; - selectors[26] = getters.getTotalBatchesVerified.selector; - selectors[27] = getters.getTotalBatchesExecuted.selector; - return selectors; - } - function getMailboxSelectors() private view returns (bytes4[] memory) { bytes4[] memory selectors = new bytes4[](6); selectors[0] = mailbox.proveL2MessageInclusion.selector; @@ -110,7 +86,7 @@ contract ExecutorTest is Test { return selectors; } - function defaultFeeParams() private pure returns (FeeParams memory feeParams) { + function defaultFeeParams() internal pure returns (FeeParams memory feeParams) { feeParams = FeeParams({ pubdataPricingMode: PubdataPricingMode.Rollup, batchOverheadL1Gas: 1_000_000, @@ -133,6 +109,7 @@ contract ExecutorTest is Test { admin = new AdminFacet(); getters = new GettersFacet(); mailbox = new MailboxFacet(eraChainId); + utils = new UtilsFacet(); DummyStateTransitionManager stateTransitionManager = new DummyStateTransitionManager(); vm.mockCall( @@ -140,6 +117,7 @@ contract ExecutorTest is Test { abi.encodeWithSelector(IStateTransitionManager.protocolVersionIsActive.selector), abi.encode(bool(true)) ); + stmAddress = address(stateTransitionManager); DiamondInit diamondInit = new DiamondInit(); bytes8 dummyHash = 0x1234567890123456; @@ -156,6 +134,7 @@ contract ExecutorTest is Test { }); TestnetVerifier testnetVerifier = new TestnetVerifier(); + testnetVerifierAddress = address(testnetVerifier); InitializeData memory params = InitializeData({ // TODO REVIEW @@ -183,7 +162,7 @@ contract ExecutorTest is Test { bytes memory diamondInitData = abi.encodeWithSelector(diamondInit.initialize.selector, params); - Diamond.FacetCut[] memory facetCuts = new Diamond.FacetCut[](4); + Diamond.FacetCut[] memory facetCuts = new Diamond.FacetCut[](5); facetCuts[0] = Diamond.FacetCut({ facet: address(admin), action: Diamond.Action.Add, @@ -200,7 +179,7 @@ contract ExecutorTest is Test { facet: address(getters), action: Diamond.Action.Add, isFreezable: false, - selectors: getGettersSelectors() + selectors: Utils.getGettersSelectors() }); facetCuts[3] = Diamond.FacetCut({ facet: address(mailbox), @@ -208,6 +187,12 @@ contract ExecutorTest is Test { isFreezable: true, selectors: getMailboxSelectors() }); + facetCuts[4] = Diamond.FacetCut({ + facet: address(utils), + action: Diamond.Action.Add, + isFreezable: true, + selectors: Utils.getUtilsFacetSelectors() + }); Diamond.DiamondCutData memory diamondCutData = Diamond.DiamondCutData({ facetCuts: facetCuts, @@ -222,6 +207,7 @@ contract ExecutorTest is Test { getters = GettersFacet(address(diamondProxy)); mailbox = MailboxFacet(address(diamondProxy)); admin = AdminFacet(address(diamondProxy)); + utils = UtilsFacet(address(diamondProxy)); // Initiate the token multiplier to enable L1 -> L2 transactions. vm.prank(address(stateTransitionManager)); diff --git a/l1-contracts/test/foundry/unit/concrete/Utils/Utils.sol b/l1-contracts/test/foundry/unit/concrete/Utils/Utils.sol index b52d1e122..7efb79073 100644 --- a/l1-contracts/test/foundry/unit/concrete/Utils/Utils.sol +++ b/l1-contracts/test/foundry/unit/concrete/Utils/Utils.sol @@ -210,7 +210,7 @@ library Utils { } function getGettersSelectors() public pure returns (bytes4[] memory) { - bytes4[] memory selectors = new bytes4[](29); + bytes4[] memory selectors = new bytes4[](30); selectors[0] = GettersFacet.getVerifier.selector; selectors[1] = GettersFacet.getAdmin.selector; selectors[2] = GettersFacet.getPendingAdmin.selector; @@ -240,6 +240,7 @@ library Utils { selectors[26] = GettersFacet.getTotalBatchesVerified.selector; selectors[27] = GettersFacet.getTotalBatchesExecuted.selector; selectors[28] = GettersFacet.getL2SystemContractsUpgradeTxHash.selector; + selectors[29] = GettersFacet.getL2SystemContractsUpgradeBatchNumber.selector; return selectors; } @@ -256,7 +257,7 @@ library Utils { } function getUtilsFacetSelectors() public pure returns (bytes4[] memory) { - bytes4[] memory selectors = new bytes4[](38); + bytes4[] memory selectors = new bytes4[](41); selectors[0] = UtilsFacet.util_setChainId.selector; selectors[1] = UtilsFacet.util_getChainId.selector; selectors[2] = UtilsFacet.util_setBridgehub.selector; @@ -295,6 +296,9 @@ library Utils { selectors[35] = UtilsFacet.util_getIsFrozen.selector; selectors[36] = UtilsFacet.util_setTransactionFilterer.selector; selectors[37] = UtilsFacet.util_setBaseTokenGasPriceMultiplierDenominator.selector; + selectors[38] = UtilsFacet.util_setL2SystemContractsUpgradeTxHash.selector; + selectors[39] = UtilsFacet.util_setTotalBatchesCommitted.selector; + selectors[40] = UtilsFacet.util_setL2SystemContractsUpgradeBatchNumber.selector; return selectors; } diff --git a/l1-contracts/test/foundry/unit/concrete/Utils/UtilsFacet.sol b/l1-contracts/test/foundry/unit/concrete/Utils/UtilsFacet.sol index 01864697d..10a54ad48 100644 --- a/l1-contracts/test/foundry/unit/concrete/Utils/UtilsFacet.sol +++ b/l1-contracts/test/foundry/unit/concrete/Utils/UtilsFacet.sol @@ -162,6 +162,18 @@ contract UtilsFacet is ZkSyncHyperchainBase { return s.isFrozen; } + function util_setL2SystemContractsUpgradeTxHash(bytes32 _l2SystemContractsUpgradeTxHash) external { + s.l2SystemContractsUpgradeTxHash = _l2SystemContractsUpgradeTxHash; + } + + function util_setTotalBatchesCommitted(uint256 _totalBatchesCommitted) external { + s.totalBatchesCommitted = _totalBatchesCommitted; + } + + function util_setL2SystemContractsUpgradeBatchNumber(uint256 _l2SystemContractsUpgradeBatchNumber) external { + s.l2SystemContractsUpgradeBatchNumber = _l2SystemContractsUpgradeBatchNumber; + } + // add this to be excluded from coverage report function test() internal virtual {} }