diff --git a/l1-contracts/src/core/Rollup.sol b/l1-contracts/src/core/Rollup.sol index 773c2fc67593..fce48d8119d1 100644 --- a/l1-contracts/src/core/Rollup.sol +++ b/l1-contracts/src/core/Rollup.sol @@ -612,6 +612,16 @@ contract Rollup is Leonidas, IRollup, ITestRollup { revert Errors.Rollup__InvalidTimestamp(timestamp, _header.globalVariables.timestamp); } + if (timestamp > block.timestamp) { + // @note If you are hitting this error, it is likely because the chain you use have a blocktime that differs + // from the value that we have in the constants. + // When you are encountering this, it will likely be as the sequencer expects to be able to include + // an Aztec block in the "next" ethereum block based on a timestamp that is 12 seconds in the future + // from the last block. However, if the actual will only be 1 second in the future, you will end up + // expecting this value to be in the future. + revert Errors.Rollup__TimestampInFuture(block.timestamp, timestamp); + } + // Check if the data is available using availability oracle (change availability oracle if you want a different DA layer) if (!AVAILABILITY_ORACLE.isAvailable(_header.contentCommitment.txsEffectsHash)) { revert Errors.Rollup__UnavailableTxs(_header.contentCommitment.txsEffectsHash); diff --git a/l1-contracts/src/core/libraries/Errors.sol b/l1-contracts/src/core/libraries/Errors.sol index f66a393e7bbc..80ec1e1836c0 100644 --- a/l1-contracts/src/core/libraries/Errors.sol +++ b/l1-contracts/src/core/libraries/Errors.sol @@ -55,7 +55,7 @@ library Errors { error Rollup__InvalidChainId(uint256 expected, uint256 actual); // 0x37b5bc12 error Rollup__InvalidVersion(uint256 expected, uint256 actual); // 0x9ef30794 error Rollup__InvalidTimestamp(uint256 expected, uint256 actual); // 0x3132e895 - error Rollup__TimestampInFuture(); // 0xbc1ce916 + error Rollup__TimestampInFuture(uint256 max, uint256 actual); // 0x89f30690 error Rollup__TimestampTooOld(); // 0x72ed9c81 error Rollup__UnavailableTxs(bytes32 txsHash); // 0x414906c3 error Rollup__NothingToPrune(); // 0x850defd3 diff --git a/l1-contracts/test/Rollup.t.sol b/l1-contracts/test/Rollup.t.sol index cd7de61110e7..07c67385a809 100644 --- a/l1-contracts/test/Rollup.t.sol +++ b/l1-contracts/test/Rollup.t.sol @@ -78,6 +78,19 @@ contract RollupTest is DecoderBase { _; } + function testTimestamp() public setUpFor("mixed_block_1") { + // Ensure that the timestamp of the current slot is never in the future. + for (uint256 i = 0; i < 100; i++) { + uint256 slot = rollup.getCurrentSlot(); + uint256 ts = rollup.getTimestampForSlot(slot); + + assertLe(ts, block.timestamp, "Invalid timestamp"); + + vm.warp(block.timestamp + 12); + vm.roll(block.number + 1); + } + } + function testRevertPrune() public setUpFor("mixed_block_1") { if (rollup.isDevNet()) { vm.expectRevert(abi.encodeWithSelector(Errors.DevNet__NoPruningAllowed.selector)); @@ -182,6 +195,9 @@ contract RollupTest is DecoderBase { uint256 portalBalance = portalERC20.balanceOf(address(feeJuicePortal)); + // We jump to the time of the block. (unless it is in the past) + vm.warp(max(block.timestamp, data.decodedHeader.globalVariables.timestamp)); + vm.expectRevert( abi.encodeWithSelector( IERC20Errors.ERC20InsufficientBalance.selector,