diff --git a/l1-contracts/src/core/Rollup.sol b/l1-contracts/src/core/Rollup.sol index d1c0210f2cd8..391af51b1df0 100644 --- a/l1-contracts/src/core/Rollup.sol +++ b/l1-contracts/src/core/Rollup.sol @@ -28,6 +28,9 @@ contract Rollup is IRollup { bytes32 public rollupStateHash; uint256 public lastBlockTs; + // Tracks the last time time was warped on L2 ("warp" is the testing cheatocde). + // See https://github.com/AztecProtocol/aztec-packages/issues/1614 + uint256 public lastWarpedBlockTs; constructor(IRegistry _registry) { VERIFIER = new MockVerifier(); diff --git a/yarn-project/aztec.js/src/utils/cheat_codes.ts b/yarn-project/aztec.js/src/utils/cheat_codes.ts index e8fd8780dfc7..d94b73b28e3f 100644 --- a/yarn-project/aztec.js/src/utils/cheat_codes.ts +++ b/yarn-project/aztec.js/src/utils/cheat_codes.ts @@ -266,6 +266,8 @@ export class AztecCheatCodes { // also store this time on the rollup contract (slot 1 tracks `lastBlockTs`). // This is because when the sequencer executes public functions, it uses the timestamp stored in the rollup contract. await this.eth.store(rollupContract, 1n, BigInt(to)); + // also store this on slot 2 of the rollup contract (`lastWarpedBlockTs`) which tracks the last time warp was used. + await this.eth.store(rollupContract, 2n, BigInt(to)); } /** diff --git a/yarn-project/end-to-end/src/e2e_cheat_codes.test.ts b/yarn-project/end-to-end/src/e2e_cheat_codes.test.ts index acae936aa18c..d7ec7962ee47 100644 --- a/yarn-project/end-to-end/src/e2e_cheat_codes.test.ts +++ b/yarn-project/end-to-end/src/e2e_cheat_codes.test.ts @@ -156,16 +156,19 @@ describe('e2e_cheat_codes', () => { // ensure rollup contract is correctly updated const rollup = getContract({ address: getAddress(rollupAddress.toString()), abi: RollupAbi, publicClient }); expect(Number(await rollup.read.lastBlockTs())).toEqual(newTimestamp); + expect(Number(await rollup.read.lastWarpedBlockTs())).toEqual(newTimestamp); const txIsTimeEqual = contract.methods.isTimeEqual(newTimestamp).send({ origin: recipient }); - await txIsTimeEqual.isMined({ interval: 0.1 }); - const isTimeEqualReceipt = await txIsTimeEqual.getReceipt(); + const isTimeEqualReceipt = await txIsTimeEqual.wait({ interval: 0.1 }); expect(isTimeEqualReceipt.status).toBe(TxStatus.MINED); - const txTimeNotEqual = contract.methods.isTimeEqual(0).send({ origin: recipient }); - await txTimeNotEqual.isMined({ interval: 0.1 }); - const isTimeNotEqualReceipt = await txTimeNotEqual.getReceipt(); - expect(isTimeNotEqualReceipt.status).toBe(TxStatus.DROPPED); + // Since last rollup block was warped, txs for this rollup will have time incremented by 1 + // See https://github.com/AztecProtocol/aztec-packages/issues/1614 for details + const txTimeNotEqual = contract.methods.isTimeEqual(newTimestamp + 1).send({ origin: recipient }); + const isTimeNotEqualReceipt = await txTimeNotEqual.wait({ interval: 0.1 }); + expect(isTimeNotEqualReceipt.status).toBe(TxStatus.MINED); + // block is published at t >= newTimestamp + 1. + expect(Number(await rollup.read.lastBlockTs())).toBeGreaterThanOrEqual(newTimestamp + 1); }, 50_000); it('should throw if setting L2 block time to a past timestamp', async () => { diff --git a/yarn-project/sequencer-client/src/global_variable_builder/global_builder.ts b/yarn-project/sequencer-client/src/global_variable_builder/global_builder.ts index 4b878107284b..1347c1eb69bc 100644 --- a/yarn-project/sequencer-client/src/global_variable_builder/global_builder.ts +++ b/yarn-project/sequencer-client/src/global_variable_builder/global_builder.ts @@ -20,6 +20,18 @@ export interface L1GlobalReader { * @returns The chain id. */ getChainId(): Promise; + + /** + * Gets the current L1 time. + * @returns The current L1 time. + */ + getL1CurrentTime(): Promise; + + /** + * Gets the last time L2 was warped as tracked by the rollup contract. + * @returns The warped time. + */ + getLastWarpedBlockTs(): Promise; } /** @@ -35,10 +47,11 @@ export interface GlobalVariableBuilder { } /** - * Simple implementation of a builder that uses the minimum time possible for the global variables. + * Simple test implementation of a builder that uses the minimum time possible for the global variables. + * Also uses a "hack" to make use of the warp cheatcode that manipulates time on Aztec. */ -export class SimpleGlobalVariableBuilder implements GlobalVariableBuilder { - private log = createDebugLogger('aztec:sequencer:simple_global_variable_builder'); +export class SimpleTestGlobalVariableBuilder implements GlobalVariableBuilder { + private log = createDebugLogger('aztec:sequencer:simple_test_global_variable_builder'); constructor(private readonly reader: L1GlobalReader) {} /** @@ -47,10 +60,23 @@ export class SimpleGlobalVariableBuilder implements GlobalVariableBuilder { * @returns The global variables for the given block number. */ public async buildGlobalVariables(blockNumber: Fr): Promise { - const lastTimestamp = new Fr(await this.reader.getLastTimestamp()); + let lastTimestamp = new Fr(await this.reader.getLastTimestamp()); const version = new Fr(await this.reader.getVersion()); const chainId = new Fr(await this.reader.getChainId()); + // TODO(rahul) - fix #1614. By using the cheatcode warp to modify L2 time, + // txs in the next rollup would have same time as the txs in the current rollup (i.e. the rollup that was warped). + // So, for now you check if L2 time was warped and if so, serve warpedTime + 1 to txs in the new rollup. + // Check if L2 time was warped in the last rollup by checking if current L1 time is same as the warpedTime (stored on the rollup contract). + // more details at https://github.com/AztecProtocol/aztec-packages/issues/1614 + + const currTimestamp = await this.reader.getL1CurrentTime(); + const rollupWarpTime = await this.reader.getLastWarpedBlockTs(); + const isLastBlockWarped = rollupWarpTime === currTimestamp; + if (isLastBlockWarped) { + lastTimestamp = new Fr(lastTimestamp.value + 1n); + } + this.log( `Built global variables for block ${blockNumber}: (${chainId}, ${version}, ${blockNumber}, ${lastTimestamp})`, ); diff --git a/yarn-project/sequencer-client/src/global_variable_builder/index.ts b/yarn-project/sequencer-client/src/global_variable_builder/index.ts index b3b666b75139..8de0248afcc2 100644 --- a/yarn-project/sequencer-client/src/global_variable_builder/index.ts +++ b/yarn-project/sequencer-client/src/global_variable_builder/index.ts @@ -1,8 +1,8 @@ import { GlobalReaderConfig } from './config.js'; -import { GlobalVariableBuilder, SimpleGlobalVariableBuilder } from './global_builder.js'; +import { GlobalVariableBuilder, SimpleTestGlobalVariableBuilder } from './global_builder.js'; import { ViemReader } from './viem-reader.js'; -export { SimpleGlobalVariableBuilder } from './global_builder.js'; +export { SimpleTestGlobalVariableBuilder as SimpleGlobalVariableBuilder } from './global_builder.js'; export { GlobalReaderConfig } from './config.js'; /** @@ -11,5 +11,5 @@ export { GlobalReaderConfig } from './config.js'; * @returns A new instance of the global variable builder. */ export function getGlobalVariableBuilder(config: GlobalReaderConfig): GlobalVariableBuilder { - return new SimpleGlobalVariableBuilder(new ViemReader(config)); + return new SimpleTestGlobalVariableBuilder(new ViemReader(config)); } diff --git a/yarn-project/sequencer-client/src/global_variable_builder/viem-reader.ts b/yarn-project/sequencer-client/src/global_variable_builder/viem-reader.ts index 54328f78c3a0..e351db0c09de 100644 --- a/yarn-project/sequencer-client/src/global_variable_builder/viem-reader.ts +++ b/yarn-project/sequencer-client/src/global_variable_builder/viem-reader.ts @@ -50,4 +50,12 @@ export class ViemReader implements L1GlobalReader { public async getChainId(): Promise { return await Promise.resolve(BigInt(this.publicClient.chain.id)); } + + public async getL1CurrentTime(): Promise { + return await Promise.resolve((await this.publicClient.getBlock()).timestamp); + } + + public async getLastWarpedBlockTs(): Promise { + return BigInt(await this.rollupContract.read.lastWarpedBlockTs()); + } }