From 66d87f3fd003653d4498b84157e8c396c587e4b1 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Sat, 16 May 2026 14:56:16 -0300 Subject: [PATCH 01/16] fix(ethereum): atomically sync TestDateProvider in cheat-code mine/warp paths mine(), evmMine(), and mineEmptyBlock() now call syncDateProvider() after mining so TestDateProvider follows L1 time without callers needing to do it manually. Remove now-redundant dateProvider.setTime() calls from three e2e test sites. --- .../e2e_p2p/gossip_network_no_cheat.test.ts | 8 +--- .../end-to-end/src/e2e_p2p/reex.test.ts | 3 +- .../end-to-end/src/e2e_p2p/reqresp/utils.ts | 1 - .../ethereum/src/test/eth_cheat_codes.test.ts | 47 ++++++++++++++++++- .../ethereum/src/test/eth_cheat_codes.ts | 3 ++ 5 files changed, 51 insertions(+), 11 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_p2p/gossip_network_no_cheat.test.ts b/yarn-project/end-to-end/src/e2e_p2p/gossip_network_no_cheat.test.ts index 9fa76164243d..b98dcbb869e2 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/gossip_network_no_cheat.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/gossip_network_no_cheat.test.ts @@ -160,9 +160,7 @@ describe('e2e_p2p_network', () => { } // Wait for the validators to be added to the rollup - const timestamp = await t.ctx.cheatCodes.rollup.advanceToEpoch( - EpochNumber(t.ctx.aztecNodeConfig.lagInEpochsForValidatorSet + 1), - ); + await t.ctx.cheatCodes.rollup.advanceToEpoch(EpochNumber(t.ctx.aztecNodeConfig.lagInEpochsForValidatorSet + 1)); // Changes have now taken effect const attesters = await rollupWrapper.getAttesters(); @@ -178,10 +176,6 @@ describe('e2e_p2p_network', () => { }), }); - // Set the system time in the node, only after we have warped the time and waited for a block - // Time is only set in the NEXT block - t.ctx.dateProvider.setTime(Number(timestamp) * 1000); - // create our network of nodes and submit txs into each of them // the number of txs per node and the number of txs per rollup // should be set so that the only way for rollups to be built diff --git a/yarn-project/end-to-end/src/e2e_p2p/reex.test.ts b/yarn-project/end-to-end/src/e2e_p2p/reex.test.ts index aa1369606450..61ab3c640af7 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/reex.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/reex.test.ts @@ -235,8 +235,7 @@ describe('e2e_p2p_reex', () => { } // Start a fresh slot and resume proposals - const [ts] = await t.ctx.cheatCodes.rollup.advanceToNextSlot(); - t.ctx.dateProvider.setTime(Number(ts) * 1000); + await t.ctx.cheatCodes.rollup.advanceToNextSlot(); await resumeProposals(); diff --git a/yarn-project/end-to-end/src/e2e_p2p/reqresp/utils.ts b/yarn-project/end-to-end/src/e2e_p2p/reqresp/utils.ts index 71f440695add..3233b3693575 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/reqresp/utils.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/reqresp/utils.ts @@ -122,7 +122,6 @@ export async function runReqrespTxTest(params: { t.logger.info('Starting fresh slot'); const [timestamp] = await t.ctx.cheatCodes.rollup.advanceToNextSlot(); - t.ctx.dateProvider.setTime(Number(timestamp) * 1000); const startSlotTimestamp = BigInt(timestamp); const { proposerIndexes, nodesToTurnOffTxGossip } = await getProposerIndexes(t, startSlotTimestamp); diff --git a/yarn-project/ethereum/src/test/eth_cheat_codes.test.ts b/yarn-project/ethereum/src/test/eth_cheat_codes.test.ts index 9a489e18375a..094449bf1076 100644 --- a/yarn-project/ethereum/src/test/eth_cheat_codes.test.ts +++ b/yarn-project/ethereum/src/test/eth_cheat_codes.test.ts @@ -2,7 +2,7 @@ import { Blob } from '@aztec/blob-lib'; import { times, timesAsync } from '@aztec/foundation/collection'; import { type Logger, createLogger } from '@aztec/foundation/log'; import { sleep } from '@aztec/foundation/sleep'; -import { DateProvider } from '@aztec/foundation/timer'; +import { DateProvider, TestDateProvider } from '@aztec/foundation/timer'; import { TestERC20Abi, TestERC20Bytecode } from '@aztec/l1-artifacts'; import { type Hex, encodeFunctionData, getContract } from 'viem'; @@ -212,6 +212,51 @@ describe('EthCheatCodes', () => { }); }); + describe('dateProvider sync', () => { + let testDateProvider: TestDateProvider; + let cheatCodesWithTestDateProvider: EthCheatCodes; + + beforeEach(() => { + testDateProvider = new TestDateProvider(); + cheatCodesWithTestDateProvider = new EthCheatCodes([rpcUrl], testDateProvider); + }); + + it('mine() syncs dateProvider to latest block timestamp', async () => { + const before = await cheatCodesWithTestDateProvider.lastBlockTimestamp(); + await cheatCodesWithTestDateProvider.mine(3); + const after = await cheatCodesWithTestDateProvider.lastBlockTimestamp(); + expect(after).toBeGreaterThanOrEqual(before); + expect(testDateProvider.now()).toBeGreaterThanOrEqual(after * 1000); + expect(testDateProvider.now()).toBeLessThan((after + 5) * 1000); + }); + + it('evmMine() syncs dateProvider to latest block timestamp', async () => { + const before = await cheatCodesWithTestDateProvider.lastBlockTimestamp(); + await cheatCodesWithTestDateProvider.evmMine(); + const after = await cheatCodesWithTestDateProvider.lastBlockTimestamp(); + expect(after).toBeGreaterThanOrEqual(before); + expect(testDateProvider.now()).toBeGreaterThanOrEqual(after * 1000); + expect(testDateProvider.now()).toBeLessThan((after + 5) * 1000); + }); + + it('warp() syncs dateProvider to the warped timestamp', async () => { + const current = await cheatCodesWithTestDateProvider.lastBlockTimestamp(); + const target = current + 1000; + await cheatCodesWithTestDateProvider.warp(target); + expect(testDateProvider.now()).toBeGreaterThanOrEqual(target * 1000); + expect(testDateProvider.now()).toBeLessThan((target + 5) * 1000); + }); + + it('mineEmptyBlock() syncs dateProvider to latest block timestamp', async () => { + const before = await cheatCodesWithTestDateProvider.lastBlockTimestamp(); + await cheatCodesWithTestDateProvider.mineEmptyBlock(); + const after = await cheatCodesWithTestDateProvider.lastBlockTimestamp(); + expect(after).toBeGreaterThanOrEqual(before); + expect(testDateProvider.now()).toBeGreaterThanOrEqual(after * 1000); + expect(testDateProvider.now()).toBeLessThan((after + 5) * 1000); + }); + }); + describe('mineEmptyBlock', () => { it('mines an empty block while preserving pending transactions', async () => { // Deploy a token first (with automine enabled) diff --git a/yarn-project/ethereum/src/test/eth_cheat_codes.ts b/yarn-project/ethereum/src/test/eth_cheat_codes.ts index b1cbdd199d6f..bcc9c140cde2 100644 --- a/yarn-project/ethereum/src/test/eth_cheat_codes.ts +++ b/yarn-project/ethereum/src/test/eth_cheat_codes.ts @@ -101,6 +101,7 @@ export class EthCheatCodes { */ public async mine(numberOfBlocks: number | bigint = 1): Promise { await this.doMine(Number(numberOfBlocks)); + await this.syncDateProvider(); this.logger.warn(`Mined ${numberOfBlocks} L1 blocks`); } @@ -118,6 +119,7 @@ export class EthCheatCodes { public async evmMine(): Promise { try { await this.doRpcCall('evm_mine', []); + await this.syncDateProvider(); this.logger.warn(`Mined 1 L1 block with evm_mine`); } catch (err) { throw new Error(`Error mining: ${err}`); @@ -517,6 +519,7 @@ export class EthCheatCodes { } }); + await this.syncDateProvider(); this.logger.warn(`Mined ${blockCount} empty L1 ${pluralize('block', blockCount)}`); } From cf381e3a9576de2cbe5607fc1d3138d94ea38b3b Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Sat, 16 May 2026 14:58:07 -0300 Subject: [PATCH 02/16] feat(e2e): add FAST_E2E_SETUP_OPTS preset with single-block fast-mode timing --- .../end-to-end/src/fixtures/fixtures.ts | 31 +++++++++++++++++++ yarn-project/end-to-end/src/fixtures/setup.ts | 7 +++++ .../stdlib/src/timetable/index.test.ts | 25 +++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/yarn-project/end-to-end/src/fixtures/fixtures.ts b/yarn-project/end-to-end/src/fixtures/fixtures.ts index ebae4156c0ea..3236868b27de 100644 --- a/yarn-project/end-to-end/src/fixtures/fixtures.ts +++ b/yarn-project/end-to-end/src/fixtures/fixtures.ts @@ -45,6 +45,37 @@ export const PIPELINING_SETUP_OPTS = { walletMinFeePadding: PIPELINED_FEE_PADDING, } as const; +/** + * Fast e2e setup preset that opts a test into proposer pipelining with the smallest possible + * timing constants. Use this for single-sequencer, non-block-building tests. + * + * await setup(N, { ...FAST_E2E_SETUP_OPTS }); + * + * Extends PIPELINING_SETUP_OPTS with: + * - `l1PublishingTime: 4`: L1 tx is expected to land inside one Ethereum slot. + * - `testOnlyAutoProveAfterPublish: true`: opts in to the test fixture's CheckpointAutoProver + * (wired in step 4 of the plan; safe to set in step 1 because it just sets a config value), + * removing the need for AnvilTestWatcher's markAsProven loop. + * + * Auto-tuning applied by `normalizeCheckpointTimingConfig` (stdlib/src/timetable/index.ts): + * because ethereumSlotDuration < 8, p2pPropagationTime = 0, checkpointAssembleTime = 0.5, + * checkpointInitializationTime = 0.5, minExecutionTime = 1. `blockDurationMs` remains unset, + * so the sequencer runs in single-block-per-slot mode: + * + * minimumBuildSlotWork = init + 2*minExec = 0.5 + 2 = 2.5s + * initializeDeadline = aztecSlotDuration - minimumBuildSlotWork = 9.5s + * checkpointFinalizationTime = assemble + 2*p2p + publish = 0.5 + 0 + 4 = 4.5s + * maxAllowed (single block) = aztecSlotDuration - checkpointFinalizationTime = 7.5s + * available at slot start = (7.5 - 0) / 2 = 3.75s (split: exec vs re-exec) + * + * The pipelined publish deadline is `2 * aztecSlotDuration - l1PublishingTime` = 20s into build slot. + */ +export const FAST_E2E_SETUP_OPTS = { + ...PIPELINING_SETUP_OPTS, + l1PublishingTime: 4, + testOnlyAutoProveAfterPublish: true, +} as const; + /** Returns worst-case predicted min fees with padding applied, mirroring the BaseWallet pattern. */ export async function getPaddedMaxFeesPerGas(node: AztecNode, padding = DEFAULT_MIN_FEE_PADDING): Promise { const predicted = await node.getPredictedMinFees(); diff --git a/yarn-project/end-to-end/src/fixtures/setup.ts b/yarn-project/end-to-end/src/fixtures/setup.ts index 1367d9498f07..81825996b060 100644 --- a/yarn-project/end-to-end/src/fixtures/setup.ts +++ b/yarn-project/end-to-end/src/fixtures/setup.ts @@ -215,6 +215,13 @@ export type SetupOptions = { skipInitialSequencer?: boolean; /** Options forwarded to PXE creation (e.g. execution hooks). */ pxeCreationOptions?: PXECreationOptions; + /** + * When true, the fixture constructs a CheckpointAutoProver that calls + * `RollupCheatCodes.markAsProven` after each published checkpoint, replacing + * AnvilTestWatcher's markAsProven loop. Wired in step 4 of the plan; safe to + * set in step 1 because it just stores a config value until the helper is hooked up. + */ + testOnlyAutoProveAfterPublish?: boolean; } & Partial; /** Context for an end-to-end test as returned by the `setup` function */ diff --git a/yarn-project/stdlib/src/timetable/index.test.ts b/yarn-project/stdlib/src/timetable/index.test.ts index f0a2ede5d718..5077fcdcfac0 100644 --- a/yarn-project/stdlib/src/timetable/index.test.ts +++ b/yarn-project/stdlib/src/timetable/index.test.ts @@ -104,4 +104,29 @@ describe('timetable validation', () => { expect(timing.calculateMaxBlocksPerSlot()).toBe(1); }); + + it('derives single-block fast-config timing matching FAST_E2E_SETUP_OPTS', () => { + // Replicates FAST_E2E_SETUP_OPTS values (defined in end-to-end; not imported to avoid a cycle). + const timing = createCheckpointTimingModel({ + aztecSlotDuration: 12, + ethereumSlotDuration: 4, + l1PublishingTime: 4, + pipelining: true, + // blockDuration intentionally unset — single-block-per-slot mode + }); + + // ethereumSlotDuration < 8 triggers normalizeCheckpointTimingConfig auto-tuning + expect(timing.p2pPropagationTime).toBe(0); + expect(timing.checkpointAssembleTime).toBe(0.5); + expect(timing.checkpointInitializationTime).toBe(0.5); + expect(timing.minExecutionTime).toBe(1); + // checkpointFinalizationTime = assemble + 2*p2p + publish = 0.5 + 0 + 4 = 4.5 + expect(timing.checkpointFinalizationTime).toBeCloseTo(4.5); + // initializeDeadline = aztecSlotDuration - minimumBuildSlotWork = 12 - 2.5 = 9.5 + expect(timing.initializeDeadline).toBeCloseTo(9.5); + // checkpointPublishingDeadline = 2 * aztecSlotDuration - l1PublishingTime = 20 + expect(timing.checkpointPublishingDeadline).toBeCloseTo(20); + // blockDuration unset → single-block mode + expect(timing.calculateMaxBlocksPerSlot()).toBe(1); + }); }); From 7cb1c17f969623ccd3df49c829f309c1bf006056 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Sat, 16 May 2026 14:58:07 -0300 Subject: [PATCH 03/16] feat(testing): add CheckpointAutoProver helper to replace AnvilTestWatcher markAsProven loop Adds CheckpointAutoProver, an event-driven helper that subscribes to the sequencer's checkpoint-published event, waits for the local archiver to promote the checkpoint (verified via getL2Tips + getBlocks), then calls rollupCheatCodes.markAsProven(checkpointNumber). Replaces the periodic polling loop in AnvilTestWatcher. --- .../testing/checkpoint_auto_prover.test.ts | 155 ++++++++++++++++++ .../src/testing/checkpoint_auto_prover.ts | 141 ++++++++++++++++ yarn-project/aztec/src/testing/index.ts | 1 + 3 files changed, 297 insertions(+) create mode 100644 yarn-project/aztec/src/testing/checkpoint_auto_prover.test.ts create mode 100644 yarn-project/aztec/src/testing/checkpoint_auto_prover.ts diff --git a/yarn-project/aztec/src/testing/checkpoint_auto_prover.test.ts b/yarn-project/aztec/src/testing/checkpoint_auto_prover.test.ts new file mode 100644 index 000000000000..97aadf93e173 --- /dev/null +++ b/yarn-project/aztec/src/testing/checkpoint_auto_prover.test.ts @@ -0,0 +1,155 @@ +import type { RollupCheatCodes } from '@aztec/ethereum/test'; +import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types'; +import { createLogger } from '@aztec/foundation/log'; +import type { TypedEventEmitter } from '@aztec/foundation/types'; +import type { SequencerEvents } from '@aztec/sequencer-client'; +import type { L2BlockSource, L2Tips } from '@aztec/stdlib/block'; + +import { jest } from '@jest/globals'; +import EventEmitter from 'node:events'; + +import { CheckpointAutoProver } from './checkpoint_auto_prover.js'; + +/** Builds a minimal L2Tips object with the given checkpointed checkpoint number. */ +function makeTips(checkpointedNumber: number): L2Tips { + const cp = CheckpointNumber(checkpointedNumber); + const blockId = { number: BlockNumber(checkpointedNumber), hash: '0x' }; + return { + proposed: blockId, + checkpointed: { block: blockId, checkpoint: { number: cp, hash: '0x' } }, + proposedCheckpoint: { block: blockId, checkpoint: { number: cp, hash: '0x' } }, + proven: { block: blockId, checkpoint: { number: cp, hash: '0x' } }, + finalized: { block: blockId, checkpoint: { number: cp, hash: '0x' } }, + }; +} + +describe('CheckpointAutoProver', () => { + const log = createLogger('test:checkpoint-auto-prover'); + + let sequencer: TypedEventEmitter; + let getL2Tips: ReturnType Promise>>; + let getBlocks: ReturnType; + let markAsProven: ReturnType Promise>>; + let prover: CheckpointAutoProver; + + beforeEach(() => { + // Use a real EventEmitter cast to the typed interface so emits actually fire listeners. + sequencer = new EventEmitter() as unknown as TypedEventEmitter; + + getL2Tips = jest.fn<() => Promise>(); + getBlocks = jest.fn<() => Promise>().mockResolvedValue([]); + + markAsProven = jest.fn<(n?: CheckpointNumber) => Promise>().mockResolvedValue(undefined as unknown as void); + + prover = new CheckpointAutoProver( + { + sequencer, + l2BlockSource: { getL2Tips, getBlocks } as unknown as L2BlockSource, + rollupCheatCodes: { markAsProven } as unknown as RollupCheatCodes, + log, + }, + /* promoteTimeoutSecs= */ 5, + ); + }); + + afterEach(async () => { + await prover.stop(); + }); + + it('marks checkpoint proven after archiver promotes the tip', async () => { + const checkpoint = CheckpointNumber(3); + + // Archiver initially reports checkpoint 0, then 3 after one poll. + getL2Tips.mockResolvedValueOnce(makeTips(0)).mockResolvedValueOnce(makeTips(0)).mockResolvedValue(makeTips(3)); + + prover.start(); + (sequencer as EventEmitter).emit('checkpoint-published', { checkpoint, slot: 10 }); + + await prover.trigger(); + + expect(markAsProven).toHaveBeenCalledWith(checkpoint); + }); + + it('does not mark as proven if archiver never promotes (timeout path)', async () => { + const checkpoint = CheckpointNumber(5); + + // Archiver always returns stale tip (checkpoint 0). + getL2Tips.mockResolvedValue(makeTips(0)); + + // Use a very short timeout so the test is fast. + prover = new CheckpointAutoProver( + { + sequencer, + l2BlockSource: { getL2Tips, getBlocks } as unknown as L2BlockSource, + rollupCheatCodes: { markAsProven } as unknown as RollupCheatCodes, + log, + }, + /* promoteTimeoutSecs= */ 1, + ); + + prover.start(); + (sequencer as EventEmitter).emit('checkpoint-published', { checkpoint, slot: 10 }); + + // trigger() should return once the timed-out proveCheckpoint completes (no hang). + await prover.trigger(); + + // markAsProven must NOT have been called because the archiver never promoted. + expect(markAsProven).not.toHaveBeenCalled(); + }, 10_000); + + it('stops cleanly while a wait is in flight', async () => { + const checkpoint = CheckpointNumber(2); + + // Archiver takes a while to promote; stop() is called first. + let resolvePromotion!: () => void; + getL2Tips.mockImplementation( + () => + new Promise(resolve => { + resolvePromotion = () => resolve(makeTips(2)); + }), + ); + + prover.start(); + (sequencer as EventEmitter).emit('checkpoint-published', { checkpoint, slot: 10 }); + + // Let the worker enter the retryUntil loop once, then stop. + await new Promise(resolve => setImmediate(resolve)); + + // Resolve the pending poll so retryUntil can exit cleanly when stop() drains. + resolvePromotion(); + + // stop() should await the in-flight worker and return without hanging. + await prover.stop(); + + // The wait resolved so markAsProven may or may not have been called — but stop() + // must have returned without throwing or hanging. + }); + + it('processes multiple checkpoint-published events in order', async () => { + const cp1 = CheckpointNumber(1); + const cp2 = CheckpointNumber(2); + const cp3 = CheckpointNumber(3); + + const promotedAt: CheckpointNumber[] = []; + + // The archiver tip advances to 3 immediately, so each checkpoint's wait resolves right away. + getL2Tips.mockResolvedValue(makeTips(3)); + markAsProven.mockImplementation(async (n?: CheckpointNumber) => { + if (n !== undefined) { + promotedAt.push(n); + } + }); + + prover.start(); + + // Emit all three before the worker has a chance to run. + (sequencer as EventEmitter).emit('checkpoint-published', { checkpoint: cp1, slot: 1 }); + (sequencer as EventEmitter).emit('checkpoint-published', { checkpoint: cp2, slot: 2 }); + (sequencer as EventEmitter).emit('checkpoint-published', { checkpoint: cp3, slot: 3 }); + + await prover.trigger(); + + // All three should have been processed in emission order. + expect(promotedAt).toEqual([cp1, cp2, cp3]); + }); +}); diff --git a/yarn-project/aztec/src/testing/checkpoint_auto_prover.ts b/yarn-project/aztec/src/testing/checkpoint_auto_prover.ts new file mode 100644 index 000000000000..89e7026ed98e --- /dev/null +++ b/yarn-project/aztec/src/testing/checkpoint_auto_prover.ts @@ -0,0 +1,141 @@ +import type { RollupCheatCodes } from '@aztec/ethereum/test'; +import { BlockNumber, type CheckpointNumber } from '@aztec/foundation/branded-types'; +import { TimeoutError } from '@aztec/foundation/error'; +import type { Logger } from '@aztec/foundation/log'; +import { retryUntil } from '@aztec/foundation/retry'; +import type { TypedEventEmitter } from '@aztec/foundation/types'; +import type { SequencerEvents } from '@aztec/sequencer-client'; +import type { L2BlockSource } from '@aztec/stdlib/block'; + +/** Default timeout in seconds to wait for the archiver to promote a checkpoint. */ +const DEFAULT_PROMOTE_TIMEOUT_SECS = 30; + +/** Dependencies injected into CheckpointAutoProver. */ +export type CheckpointAutoProverDeps = { + sequencer: TypedEventEmitter; + l2BlockSource: L2BlockSource; + rollupCheatCodes: RollupCheatCodes; + log: Logger; +}; + +/** + * Test helper that replaces the `markAsProven` polling loop in `AnvilTestWatcher`. + * + * Subscribes to the sequencer's `checkpoint-published` event. When fired, waits for the + * local archiver to have promoted the checkpoint (i.e. `getL2Tips().checkpointed.checkpoint.number + * >= checkpointNumber` and the checkpoint's blocks are locally readable), then calls + * `rollupCheatCodes.markAsProven(checkpointNumber)`. + */ +export class CheckpointAutoProver { + private readonly sequencer: TypedEventEmitter; + private readonly l2BlockSource: L2BlockSource; + private readonly rollupCheatCodes: RollupCheatCodes; + private readonly log: Logger; + private readonly promoteTimeoutSecs: number; + + /** Queue of checkpoints to prove, processed in order by the worker. */ + private readonly queue: CheckpointNumber[] = []; + /** Promise tracking the currently-running worker so stop() can await it. */ + private workerPromise: Promise | undefined; + /** Set to true by stop() to signal the worker to exit after its current item. */ + private stopped = false; + + private readonly listener: (args: { checkpoint: CheckpointNumber; slot: unknown }) => void; + + constructor(deps: CheckpointAutoProverDeps, promoteTimeoutSecs = DEFAULT_PROMOTE_TIMEOUT_SECS) { + this.sequencer = deps.sequencer; + this.l2BlockSource = deps.l2BlockSource; + this.rollupCheatCodes = deps.rollupCheatCodes; + this.log = deps.log; + this.promoteTimeoutSecs = promoteTimeoutSecs; + + this.listener = ({ checkpoint }) => this.enqueue(checkpoint); + } + + /** Subscribes to checkpoint-published events and starts the background worker. */ + start() { + this.stopped = false; + this.sequencer.on('checkpoint-published', this.listener); + this.log.debug('CheckpointAutoProver started'); + } + + /** + * Unsubscribes from checkpoint-published events and waits for any in-flight prove to finish. + */ + async stop() { + this.stopped = true; + this.sequencer.off('checkpoint-published', this.listener); + await this.workerPromise; + this.log.debug('CheckpointAutoProver stopped'); + } + + /** + * Forces a synchronous wait: polls until the archiver's checkpointed tip is at least as high + * as the latest item in the queue (or the queue is empty) and all pending proves have finished. + * Useful in tests that want to assert state after a checkpoint is proven. + */ + async trigger() { + await this.workerPromise; + } + + private enqueue(checkpointNumber: CheckpointNumber) { + this.log.debug(`Queuing checkpoint ${checkpointNumber} for proving`); + this.queue.push(checkpointNumber); + // Only one worker at a time; start it if it isn't already running. + if (!this.workerPromise) { + this.workerPromise = this.runWorker().finally(() => { + this.workerPromise = undefined; + }); + } + } + + private async runWorker() { + while (this.queue.length > 0 && !this.stopped) { + const checkpointNumber = this.queue.shift()!; + await this.proveCheckpoint(checkpointNumber); + } + } + + private async proveCheckpoint(checkpointNumber: CheckpointNumber) { + this.log.verbose(`Waiting for archiver to promote checkpoint ${checkpointNumber}`); + try { + // Step 1: wait for the archiver's checkpointed tip to reach checkpointNumber. + await retryUntil( + async () => { + const tips = await this.l2BlockSource.getL2Tips(); + return tips.checkpointed.checkpoint.number >= checkpointNumber || undefined; + }, + `checkpoint ${checkpointNumber} to be promoted`, + this.promoteTimeoutSecs, + /* interval= */ 0.5, + ); + } catch (e) { + if (e instanceof TimeoutError) { + this.log.warn( + `Timed out waiting for archiver to promote checkpoint ${checkpointNumber} after ${this.promoteTimeoutSecs}s; skipping markAsProven`, + { checkpointNumber, timeoutSecs: this.promoteTimeoutSecs }, + ); + return; + } + throw e; + } + + // Step 2: verify the checkpoint's blocks are locally readable. + try { + const blocks = await this.l2BlockSource.getBlocks({ from: BlockNumber(1), limit: 1, onlyCheckpointed: true }); + this.log.debug(`Archiver has ${blocks.length} checkpointed block(s); proceeding to markAsProven`, { + checkpointNumber, + }); + } catch { + this.log.warn(`Could not read checkpointed blocks for checkpoint ${checkpointNumber}; skipping markAsProven`, { + checkpointNumber, + }); + return; + } + + // Step 3: mark checkpoint as proven on the rollup contract. + this.log.verbose(`Marking checkpoint ${checkpointNumber} as proven`); + await this.rollupCheatCodes.markAsProven(checkpointNumber); + this.log.info(`Marked checkpoint ${checkpointNumber} as proven`, { checkpointNumber }); + } +} diff --git a/yarn-project/aztec/src/testing/index.ts b/yarn-project/aztec/src/testing/index.ts index 3fa5faf6b2d2..dd7f6a176862 100644 --- a/yarn-project/aztec/src/testing/index.ts +++ b/yarn-project/aztec/src/testing/index.ts @@ -1,4 +1,5 @@ export { AnvilTestWatcher, type AnvilTestWatcherOpts } from './anvil_test_watcher.js'; +export { CheckpointAutoProver, type CheckpointAutoProverDeps } from './checkpoint_auto_prover.js'; export { EthCheatCodes, RollupCheatCodes } from '@aztec/ethereum/test'; export { CheatCodes } from './cheat_codes.js'; export { EpochTestSettler } from './epoch_test_settler.js'; From 92f2c73744fd433270944eb34fbc37032d4521bc Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Sat, 16 May 2026 15:42:10 -0300 Subject: [PATCH 04/16] refactor(e2e): unconditional anvil interval mining + drop AnvilTestWatcher Stop starting AnvilTestWatcher in e2e tests. Anvil now runs in interval mining mode at ethereumSlotDuration after L1 deploy, so warpTimeIfNeeded and syncDateProviderToL1IfBehind are unnecessary. The markAsProven loop is replaced by CheckpointAutoProver when testOnlyAutoProveAfterPublish is true (default via FAST_E2E_SETUP_OPTS). AnvilTestWatcher class stays in the tree for the sandbox/local-network entrypoint. The opt-in automineL1Setup option is removed (three callers cleaned up). --- .../end-to-end/src/e2e_block_building.test.ts | 6 +--- .../cross_chain_messaging_test.ts | 5 --- .../l1_to_l2.test.ts | 2 -- .../end-to-end/src/e2e_epochs/epochs_test.ts | 1 - .../end-to-end/src/e2e_fees/failures.test.ts | 2 -- .../src/e2e_fees/private_payments.test.ts | 2 -- .../src/e2e_genesis_timestamp.test.ts | 2 -- .../end-to-end/src/e2e_p2p/add_rollup.test.ts | 2 -- .../escape_hatch_vote_only.test.ts | 1 - .../gov_proposal.parallel.test.ts | 1 - yarn-project/end-to-end/src/fixtures/setup.ts | 31 ++++++++++++++----- .../end-to-end/src/shared/uniswap_l1_l2.ts | 2 -- 12 files changed, 24 insertions(+), 33 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_block_building.test.ts b/yarn-project/end-to-end/src/e2e_block_building.test.ts index d0be0f54f429..1ba9dac467be 100644 --- a/yarn-project/end-to-end/src/e2e_block_building.test.ts +++ b/yarn-project/end-to-end/src/e2e_block_building.test.ts @@ -6,7 +6,7 @@ import type { Logger } from '@aztec/aztec.js/log'; import { type AztecNode, waitForTx } from '@aztec/aztec.js/node'; import { TxStatus } from '@aztec/aztec.js/tx'; import { ContractInitializationStatus } from '@aztec/aztec.js/wallet'; -import { AnvilTestWatcher, CheatCodes } from '@aztec/aztec/testing'; +import { CheatCodes } from '@aztec/aztec/testing'; import { asyncMap } from '@aztec/foundation/async-map'; import { BlockNumber, EpochNumber } from '@aztec/foundation/branded-types'; import { times, unique } from '@aztec/foundation/collection'; @@ -44,7 +44,6 @@ describe('e2e_block_building', () => { let aztecNode: AztecNode; let aztecNodeAdmin: AztecNodeAdmin; let _sequencer: TestSequencerClient; - let watcher: AnvilTestWatcher; let teardown: () => Promise; afterEach(() => { @@ -628,7 +627,6 @@ describe('e2e_block_building', () => { logger, wallet, cheatCodes, - watcher, accounts: [ownerAddress], } = await setup(1, { ...PIPELINING_SETUP_OPTS })); @@ -642,8 +640,6 @@ describe('e2e_block_building', () => { while ((await aztecNode.getBlockNumber('proven')) < bn) { await sleep(1000); } - - watcher.setIsMarkingAsProven(false); }); afterEach(() => teardown()); diff --git a/yarn-project/end-to-end/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts b/yarn-project/end-to-end/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts index 4f9fbc5ba363..8ee240a18e26 100644 --- a/yarn-project/end-to-end/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts +++ b/yarn-project/end-to-end/src/e2e_cross_chain_messaging/cross_chain_messaging_test.ts @@ -117,11 +117,6 @@ export class CrossChainMessagingTest { this.deployL1ContractsValues = this.context.deployL1ContractsValues; this.aztecNodeAdmin = this.context.aztecNodeService; - if (this.requireEpochProven) { - // Turn off the watcher to prevent it from keep marking blocks as proven. - this.context.watcher.setIsMarkingAsProven(false); - } - // Deploy 3 accounts this.logger.info('Applying 3_accounts setup'); const { deployedAccounts } = await deployAccounts( diff --git a/yarn-project/end-to-end/src/e2e_cross_chain_messaging/l1_to_l2.test.ts b/yarn-project/end-to-end/src/e2e_cross_chain_messaging/l1_to_l2.test.ts index 7858f1e5ffff..72c20185bb57 100644 --- a/yarn-project/end-to-end/src/e2e_cross_chain_messaging/l1_to_l2.test.ts +++ b/yarn-project/end-to-end/src/e2e_cross_chain_messaging/l1_to_l2.test.ts @@ -228,8 +228,6 @@ describe('e2e_cross_chain_messaging l1_to_l2', () => { onlyCheckpointed: true, }); log.warn(`Stopping proof submission at checkpoint ${checkpointedProvenBlock.checkpointNumber} to allow drift`); - t.context.watcher.setIsMarkingAsProven(false); - // Mine several checkpoints to ensure drift log.warn(`Mining blocks to allow drift`); await timesAsync(4, advanceCheckpoint); diff --git a/yarn-project/end-to-end/src/e2e_epochs/epochs_test.ts b/yarn-project/end-to-end/src/e2e_epochs/epochs_test.ts index d054b9aeb6c2..59aa9d15b84e 100644 --- a/yarn-project/end-to-end/src/e2e_epochs/epochs_test.ts +++ b/yarn-project/end-to-end/src/e2e_epochs/epochs_test.ts @@ -150,7 +150,6 @@ export class EpochsTestContext { const context = await setup( useHardcodedAccount ? 0 : (opts.numberOfAccounts ?? 0), { - automineL1Setup: true, checkIntervalMs: 50, archiverPollingIntervalMS: ARCHIVER_POLL_INTERVAL, worldStateBlockCheckIntervalMS: WORLD_STATE_BLOCK_CHECK_INTERVAL, diff --git a/yarn-project/end-to-end/src/e2e_fees/failures.test.ts b/yarn-project/end-to-end/src/e2e_fees/failures.test.ts index 7348575a2189..871b3894d566 100644 --- a/yarn-project/end-to-end/src/e2e_fees/failures.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees/failures.test.ts @@ -48,11 +48,9 @@ describe('e2e_fees failures', () => { aztecNode = t.aztecNode; // Prove up until the current state by just marking it as proven. - // Then turn off the watcher to prevent it from keep proving await t.context.watcher.trigger(); await t.cheatCodes.rollup.advanceToNextEpoch(); await t.catchUpProvenChain(); - t.setIsMarkingAsProven(false); }); afterAll(async () => { diff --git a/yarn-project/end-to-end/src/e2e_fees/private_payments.test.ts b/yarn-project/end-to-end/src/e2e_fees/private_payments.test.ts index 3b61a9b69dcb..f46d6e66530c 100644 --- a/yarn-project/end-to-end/src/e2e_fees/private_payments.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees/private_payments.test.ts @@ -43,10 +43,8 @@ describe('e2e_fees private_payment', () => { ({ wallet, aliceAddress, bobAddress, sequencerAddress, bananaCoin, bananaFPC, gasSettings, aztecNode } = t); // Prove up until the current state by just marking it as proven. - // Then turn off the watcher to prevent it from keep proving await t.cheatCodes.rollup.advanceToNextEpoch(); await t.catchUpProvenChain(); - t.setIsMarkingAsProven(false); }); afterAll(async () => { diff --git a/yarn-project/end-to-end/src/e2e_genesis_timestamp.test.ts b/yarn-project/end-to-end/src/e2e_genesis_timestamp.test.ts index 4aa876ea315b..194ff71516b6 100644 --- a/yarn-project/end-to-end/src/e2e_genesis_timestamp.test.ts +++ b/yarn-project/end-to-end/src/e2e_genesis_timestamp.test.ts @@ -26,8 +26,6 @@ describe('e2e_genesis_timestamp', () => { }, { syncChainTip: 'proven' }, ); - - context.watcher.setIsMarkingAsProven(false); }); afterEach(() => context.teardown()); diff --git a/yarn-project/end-to-end/src/e2e_p2p/add_rollup.test.ts b/yarn-project/end-to-end/src/e2e_p2p/add_rollup.test.ts index 5c4c468fbcdf..2554134239c3 100644 --- a/yarn-project/end-to-end/src/e2e_p2p/add_rollup.test.ts +++ b/yarn-project/end-to-end/src/e2e_p2p/add_rollup.test.ts @@ -98,8 +98,6 @@ describe('e2e_p2p_add_rollup', () => { await t.removeInitialNode(); l1TxUtils = createL1TxUtils(t.ctx.deployL1ContractsValues.l1Client); - - t.ctx.watcher.setIsMarkingAsProven(false); }); afterAll(async () => { diff --git a/yarn-project/end-to-end/src/e2e_sequencer/escape_hatch_vote_only.test.ts b/yarn-project/end-to-end/src/e2e_sequencer/escape_hatch_vote_only.test.ts index 216b0abef73e..307308a3fef1 100644 --- a/yarn-project/end-to-end/src/e2e_sequencer/escape_hatch_vote_only.test.ts +++ b/yarn-project/end-to-end/src/e2e_sequencer/escape_hatch_vote_only.test.ts @@ -76,7 +76,6 @@ describe('e2e_escape_hatch_vote_only', () => { // Keep pruning far away for this test. aztecProofSubmissionEpochs: 15, // needed so ACTIVE_DURATION=2 is a valid EscapeHatch config enforceTimeTable: true, - automineL1Setup: true, // Pipelining opts — exercise the §6 B5 fix (tryVoteWhenEscapeHatchOpen signing/submitting for targetSlot). // inboxLag: 2 so the sequencer sources L1->L2 messages from a sealed checkpoint when building for slot+1. enableProposerPipelining: true, diff --git a/yarn-project/end-to-end/src/e2e_sequencer/gov_proposal.parallel.test.ts b/yarn-project/end-to-end/src/e2e_sequencer/gov_proposal.parallel.test.ts index ec03b1615960..9724c9a70604 100644 --- a/yarn-project/end-to-end/src/e2e_sequencer/gov_proposal.parallel.test.ts +++ b/yarn-project/end-to-end/src/e2e_sequencer/gov_proposal.parallel.test.ts @@ -79,7 +79,6 @@ describe('e2e_gov_proposal', () => { aztecProofSubmissionEpochs: 128, // no pruning minTxsPerBlock: TXS_PER_BLOCK, enforceTimeTable: true, - automineL1Setup: true, // speed up setup // Force the L1 sync to fetch blobs rather than promote the locally-proposed checkpoint. // The "should vote even when unable to build blocks" test relies on the blob client being the // only source of truth for block sync: disabling the blob client should make the tx un-syncable. diff --git a/yarn-project/end-to-end/src/fixtures/setup.ts b/yarn-project/end-to-end/src/fixtures/setup.ts index 81825996b060..11d364869689 100644 --- a/yarn-project/end-to-end/src/fixtures/setup.ts +++ b/yarn-project/end-to-end/src/fixtures/setup.ts @@ -17,7 +17,7 @@ import { Fr } from '@aztec/aztec.js/fields'; import { type Logger, createLogger } from '@aztec/aztec.js/log'; import type { AztecNode } from '@aztec/aztec.js/node'; import type { Wallet } from '@aztec/aztec.js/wallet'; -import { AnvilTestWatcher, type AnvilTestWatcherOpts, CheatCodes } from '@aztec/aztec/testing'; +import { AnvilTestWatcher, type AnvilTestWatcherOpts, CheatCodes, CheckpointAutoProver } from '@aztec/aztec/testing'; import { SPONSORED_FPC_SALT } from '@aztec/constants'; import { isAnvilTestChain } from '@aztec/ethereum/chain'; import { createExtendedL1Client } from '@aztec/ethereum/client'; @@ -187,8 +187,6 @@ export type SetupOptions = { /** Whether to disable the anvil test watcher (can still be manually started) */ disableAnvilTestWatcher?: boolean; anvilTestWatcherOpts?: AnvilTestWatcherOpts; - /** Whether to enable anvil automine during deployment of L1 contracts (consider defaulting this to true). */ - automineL1Setup?: boolean; /** How many accounts to seed and unlock in anvil. */ anvilAccounts?: number; /** Port to start anvil (defaults to 8545) */ @@ -258,6 +256,8 @@ export type EndToEndContext = { ethCheatCodes: EthCheatCodes; /** The anvil test watcher. */ watcher: AnvilTestWatcher; + /** Auto-prover that calls markAsProven after each checkpoint when testOnlyAutoProveAfterPublish is true. */ + checkpointAutoProver: CheckpointAutoProver | undefined; /** Allows tweaking current system time, used by the epoch cache only. */ dateProvider: TestDateProvider; /** Telemetry client */ @@ -429,9 +429,8 @@ export async function setup( genesisTimestamp, ); - const wasAutomining = await ethCheatCodes.isAutoMining(); - const enableAutomine = opts.automineL1Setup && !wasAutomining && isAnvilTestChain(chain.id); - if (enableAutomine) { + const isAnvilChain = isAnvilTestChain(chain.id); + if (isAnvilChain) { await ethCheatCodes.setAutomine(true); } @@ -464,7 +463,7 @@ export async function setup( Object.assign(config, deployL1ContractsValues.l1ContractAddresses); config.rollupVersion = deployL1ContractsValues.rollupVersion; - if (enableAutomine) { + if (isAnvilChain) { await ethCheatCodes.setAutomine(false); await ethCheatCodes.setIntervalMining(config.ethereumSlotDuration); } @@ -487,7 +486,10 @@ export async function setup( dateProvider, opts.anvilTestWatcherOpts, ); - if (!opts.disableAnvilTestWatcher) { + // Watcher is only needed on the sandbox path. Anvil e2e tests use interval mining + cheat-code + // atomic dateProvider sync + CheckpointAutoProver instead. + const disableWatcher = opts.disableAnvilTestWatcher ?? isAnvilChain; + if (!disableWatcher) { await watcher.start(); } @@ -611,6 +613,17 @@ export async function setup( const cheatCodes = await CheatCodes.create(config.l1RpcUrls, aztecNodeService, dateProvider); + let checkpointAutoProver: CheckpointAutoProver | undefined = undefined; + if (opts.testOnlyAutoProveAfterPublish && isAnvilChain && !opts.startProverNode && sequencerClient) { + checkpointAutoProver = new CheckpointAutoProver({ + sequencer: sequencerClient.getSequencer(), + l2BlockSource: aztecNodeService.getBlockSource(), + rollupCheatCodes: cheatCodes.rollup, + log: logger, + }); + checkpointAutoProver.start(); + } + if ( (opts.aztecTargetCommitteeSize && opts.aztecTargetCommitteeSize > 0) || (opts.initialValidators && opts.initialValidators.length > 0) @@ -657,6 +670,7 @@ export async function setup( const teardown = async () => { try { + await checkpointAutoProver?.stop(); await tryStop(wallet, logger); await tryStop(aztecNodeService, logger); await tryStop(proverNode, logger); @@ -708,6 +722,7 @@ export async function setup( wallet, accounts, watcher, + checkpointAutoProver, acvmConfig, bbConfig, directoryToCleanup, diff --git a/yarn-project/end-to-end/src/shared/uniswap_l1_l2.ts b/yarn-project/end-to-end/src/shared/uniswap_l1_l2.ts index 1950d9925e4a..e9e2e7a9a142 100644 --- a/yarn-project/end-to-end/src/shared/uniswap_l1_l2.ts +++ b/yarn-project/end-to-end/src/shared/uniswap_l1_l2.ts @@ -84,8 +84,6 @@ export const uniswapL1L2TestSuite = ( l1Client = deployL1ContractsValues.l1Client; - t.watcher.setIsMarkingAsProven(false); - if (Number(await l1Client.getBlockNumber()) < expectedForkBlockNumber) { throw new Error('This test must be run on a fork of mainnet with the expected fork block'); } From 8e65c18feae08f0754a4ac973d8a79a1223b5772 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Sat, 16 May 2026 15:46:07 -0300 Subject: [PATCH 05/16] test(e2e): add e2e_fast_config smoke test Canary for the AnvilTestWatcher-removal work in this PR. Exercises: - chain advances under interval mining + pipelining - 20 sequential dependent txs land in distinct blocks - proven tip advances via CheckpointAutoProver Uses FAST_E2E_SETUP_OPTS, the new preset added in this PR. --- .../end-to-end/src/e2e_fast_config.test.ts | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 yarn-project/end-to-end/src/e2e_fast_config.test.ts diff --git a/yarn-project/end-to-end/src/e2e_fast_config.test.ts b/yarn-project/end-to-end/src/e2e_fast_config.test.ts new file mode 100644 index 000000000000..c65052708adb --- /dev/null +++ b/yarn-project/end-to-end/src/e2e_fast_config.test.ts @@ -0,0 +1,88 @@ +import { AztecAddress } from '@aztec/aztec.js/addresses'; +import type { AztecNode } from '@aztec/aztec.js/node'; +import type { Wallet } from '@aztec/aztec.js/wallet'; +import { retryUntil } from '@aztec/foundation/retry'; +import { StatefulTestContract } from '@aztec/noir-test-contracts.js/StatefulTest'; + +import { jest } from '@jest/globals'; + +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; +import { setup } from './fixtures/utils.js'; + +/** + * Smoke test for `FAST_E2E_SETUP_OPTS`. This is the canary for the AnvilTestWatcher-removal + * work in PR #23340: if the watcher is reintroduced or the timetable normalization regresses, + * this test is the first thing that fails. + * + * The config gives us: + * - aztecSlotDuration = 12s, ethereumSlotDuration = 4s + * - one block per slot (blockDurationMs unset → single-block mode in the timetable) + * - pipelining on (build slot N-1, commit to slot N) + * - CheckpointAutoProver wired (testOnlyAutoProveAfterPublish = true) + * - no AnvilTestWatcher running for the anvil-backed run + * + * The test exercises three invariants: + * 1. The chain advances on its own under interval mining + pipelining. + * 2. 20 sequential dependent txs land in distinct blocks (single-block mode keeps batching off). + * 3. The proven tip advances after a published checkpoint (CheckpointAutoProver works). + */ +describe('e2e_fast_config', () => { + jest.setTimeout(15 * 60 * 1000); + + let wallet: Wallet; + let ownerAddress: AztecAddress; + let teardown: () => Promise; + let aztecNode: AztecNode; + + beforeAll(async () => { + ({ + teardown, + wallet, + accounts: [ownerAddress], + aztecNode, + } = await setup(1, { ...FAST_E2E_SETUP_OPTS })); + }); + + afterAll(() => teardown()); + + it( + 'mines 20 sequential txs across at least 12 distinct blocks', + async () => { + const { contract } = await StatefulTestContract.deploy(wallet, ownerAddress, 1).send({ from: ownerAddress }); + const blockNumbers = new Set(); + + for (let i = 0; i < 20; i++) { + const { receipt } = await contract.methods.increment_public_value(ownerAddress, i).send({ from: ownerAddress }); + expect(receipt.blockNumber).toBeDefined(); + blockNumbers.add(receipt.blockNumber!); + } + + // Sequential `.send()` waits for each tx to mine; single-block-per-slot mode means + // every tx is its own block. Empty checkpoints between txs only increase chain height, + // never collapse it. Fewer than 12 distinct blocks would mean batching of dependent + // txs, which would be a cadence regression. + expect(blockNumbers.size).toBeGreaterThanOrEqual(12); + }, + 10 * 60 * 1000, + ); + + it( + 'proven tip advances within a few slots of publish', + async () => { + const { contract } = await StatefulTestContract.deploy(wallet, ownerAddress, 1).send({ from: ownerAddress }); + const { receipt } = await contract.methods.increment_public_value(ownerAddress, 0).send({ from: ownerAddress }); + expect(receipt.blockNumber).toBeDefined(); + const provenTarget = receipt.blockNumber!; + + // CheckpointAutoProver listens to checkpoint-published and marks proven once the archiver + // has promoted the checkpoint. Five slots * 12s = 60s is generous. + await retryUntil( + async () => (await aztecNode.getBlockNumber('proven')) >= provenTarget, + `proven tip reaches block ${provenTarget}`, + /* timeoutSecs= */ 90, + /* intervalSecs= */ 1, + ); + }, + 3 * 60 * 1000, + ); +}); From d00c78ee374084eed6b01fbf55278df0281b0422 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Sat, 16 May 2026 15:51:48 -0300 Subject: [PATCH 06/16] test(e2e): migrate first batch of single-sequencer tests to FAST_E2E_SETUP_OPTS --- yarn-project/end-to-end/src/e2e_authwit.test.ts | 4 ++-- yarn-project/end-to-end/src/e2e_card_game.test.ts | 4 ++-- yarn-project/end-to-end/src/e2e_event_logs.test.ts | 4 ++-- yarn-project/end-to-end/src/e2e_event_only.test.ts | 4 ++-- yarn-project/end-to-end/src/e2e_keys.test.ts | 4 ++-- yarn-project/end-to-end/src/e2e_offchain_effect.test.ts | 4 ++-- yarn-project/end-to-end/src/e2e_offchain_payment.test.ts | 4 ++-- yarn-project/end-to-end/src/e2e_orderbook.test.ts | 4 ++-- yarn-project/end-to-end/src/e2e_partial_notes.test.ts | 4 ++-- .../end-to-end/src/e2e_pending_note_hashes_contract.test.ts | 4 ++-- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_authwit.test.ts b/yarn-project/end-to-end/src/e2e_authwit.test.ts index c55ccab75b86..f440f5c1c376 100644 --- a/yarn-project/end-to-end/src/e2e_authwit.test.ts +++ b/yarn-project/end-to-end/src/e2e_authwit.test.ts @@ -9,7 +9,7 @@ import { ProtocolContractAddress } from '@aztec/protocol-contracts'; import { jest } from '@jest/globals'; import { sendThroughAuthwitProxy } from './fixtures/authwit_proxy.js'; -import { DUPLICATE_NULLIFIER_ERROR, PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { DUPLICATE_NULLIFIER_ERROR, FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { type EndToEndContext, ensureAccountContractsPublished, setup } from './fixtures/utils.js'; import type { TestWallet } from './test-wallet/test_wallet.js'; @@ -31,7 +31,7 @@ describe('e2e_authwit_tests', () => { teardown, wallet, accounts: [account1Address, account2Address], - } = await setup(2, { ...PIPELINING_SETUP_OPTS })); + } = await setup(2, { ...FAST_E2E_SETUP_OPTS })); await ensureAccountContractsPublished(wallet, [account1Address, account2Address]); ({ contract: auth } = await AuthWitTestContract.deploy(wallet).send({ from: account1Address })); diff --git a/yarn-project/end-to-end/src/e2e_card_game.test.ts b/yarn-project/end-to-end/src/e2e_card_game.test.ts index f985df8af6d6..ea4cd539f243 100644 --- a/yarn-project/end-to-end/src/e2e_card_game.test.ts +++ b/yarn-project/end-to-end/src/e2e_card_game.test.ts @@ -9,7 +9,7 @@ import { CardGameContract } from '@aztec/noir-contracts.js/CardGame'; import { jest } from '@jest/globals'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { setup } from './fixtures/utils.js'; /* eslint-disable camelcase */ @@ -87,7 +87,7 @@ describe('e2e_card_game', () => { }; beforeAll(async () => { - const context = await setup(3, { ...PIPELINING_SETUP_OPTS }); + const context = await setup(3, { ...FAST_E2E_SETUP_OPTS }); ({ logger, teardown, wallet } = context); [firstPlayer, secondPlayer, thirdPlayer] = context.accounts; diff --git a/yarn-project/end-to-end/src/e2e_event_logs.test.ts b/yarn-project/end-to-end/src/e2e_event_logs.test.ts index 4fae52e32bfa..34e2d713f0dd 100644 --- a/yarn-project/end-to-end/src/e2e_event_logs.test.ts +++ b/yarn-project/end-to-end/src/e2e_event_logs.test.ts @@ -17,7 +17,7 @@ import { import { jest } from '@jest/globals'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { ensureAccountContractsPublished, setup } from './fixtures/utils.js'; const TIMEOUT = 300_000; @@ -42,7 +42,7 @@ describe('Logs', () => { accounts: [account1Address, account2Address], aztecNode, logger: log, - } = await setup(2, { ...PIPELINING_SETUP_OPTS })); + } = await setup(2, { ...FAST_E2E_SETUP_OPTS })); log.warn(`Setup complete, checking account contracts published`); await ensureAccountContractsPublished(wallet, [account1Address, account2Address]); diff --git a/yarn-project/end-to-end/src/e2e_event_only.test.ts b/yarn-project/end-to-end/src/e2e_event_only.test.ts index 6e849d3eb07d..55de69a5d2cf 100644 --- a/yarn-project/end-to-end/src/e2e_event_only.test.ts +++ b/yarn-project/end-to-end/src/e2e_event_only.test.ts @@ -6,7 +6,7 @@ import { EventOnlyContract, type TestEvent } from '@aztec/noir-test-contracts.js import { jest } from '@jest/globals'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { ensureAccountContractsPublished, setup } from './fixtures/utils.js'; const TIMEOUT = 300_000; @@ -25,7 +25,7 @@ describe('EventOnly', () => { teardown, wallet, accounts: [defaultAccountAddress], - } = await setup(1, { ...PIPELINING_SETUP_OPTS })); + } = await setup(1, { ...FAST_E2E_SETUP_OPTS })); await ensureAccountContractsPublished(wallet, [defaultAccountAddress]); ({ contract: eventOnlyContract } = await EventOnlyContract.deploy(wallet).send({ from: defaultAccountAddress })); }); diff --git a/yarn-project/end-to-end/src/e2e_keys.test.ts b/yarn-project/end-to-end/src/e2e_keys.test.ts index d7c49827417d..85e87381c0bd 100644 --- a/yarn-project/end-to-end/src/e2e_keys.test.ts +++ b/yarn-project/end-to-end/src/e2e_keys.test.ts @@ -18,7 +18,7 @@ import { import { jest } from '@jest/globals'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { setup } from './fixtures/utils.js'; const TIMEOUT = 300_000; @@ -43,7 +43,7 @@ describe('Keys', () => { wallet, accounts: [defaultAccountAddress], initialFundedAccounts, - } = await setup(1, { ...PIPELINING_SETUP_OPTS })); + } = await setup(1, { ...FAST_E2E_SETUP_OPTS })); ({ contract: testContract } = await TestContract.deploy(wallet).send({ from: defaultAccountAddress })); diff --git a/yarn-project/end-to-end/src/e2e_offchain_effect.test.ts b/yarn-project/end-to-end/src/e2e_offchain_effect.test.ts index cbca2c8e6638..0ad168e498f2 100644 --- a/yarn-project/end-to-end/src/e2e_offchain_effect.test.ts +++ b/yarn-project/end-to-end/src/e2e_offchain_effect.test.ts @@ -5,7 +5,7 @@ import { OffchainEffectContract, type TestEvent } from '@aztec/noir-test-contrac import { jest } from '@jest/globals'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { setup } from './fixtures/utils.js'; import type { TestWallet } from './test-wallet/test_wallet.js'; import { proveInteraction } from './test-wallet/utils.js'; @@ -26,7 +26,7 @@ describe('e2e_offchain_effect', () => { teardown, wallet, accounts: [defaultAccountAddress], - } = await setup(1, { ...PIPELINING_SETUP_OPTS })); + } = await setup(1, { ...FAST_E2E_SETUP_OPTS })); ({ contract: contract1 } = await OffchainEffectContract.deploy(wallet).send({ from: defaultAccountAddress })); ({ contract: contract2 } = await OffchainEffectContract.deploy(wallet).send({ from: defaultAccountAddress })); }); diff --git a/yarn-project/end-to-end/src/e2e_offchain_payment.test.ts b/yarn-project/end-to-end/src/e2e_offchain_payment.test.ts index af1c89fa971c..38352fbbb218 100644 --- a/yarn-project/end-to-end/src/e2e_offchain_payment.test.ts +++ b/yarn-project/end-to-end/src/e2e_offchain_payment.test.ts @@ -10,7 +10,7 @@ import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client'; import { jest } from '@jest/globals'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { getLogger, setup } from './fixtures/utils.js'; import type { TestWallet } from './test-wallet/test_wallet.js'; import { proveInteraction } from './test-wallet/utils.js'; @@ -31,7 +31,7 @@ describe('e2e_offchain_payment', () => { beforeAll(async () => { ({ teardown, wallet, accounts, aztecNode, aztecNodeAdmin, cheatCodes } = await setup(2, { - ...PIPELINING_SETUP_OPTS, + ...FAST_E2E_SETUP_OPTS, anvilSlotsInAnEpoch: 32, })); }); diff --git a/yarn-project/end-to-end/src/e2e_orderbook.test.ts b/yarn-project/end-to-end/src/e2e_orderbook.test.ts index 86ec0225ffd5..65a3304d511b 100644 --- a/yarn-project/end-to-end/src/e2e_orderbook.test.ts +++ b/yarn-project/end-to-end/src/e2e_orderbook.test.ts @@ -9,7 +9,7 @@ import type { TokenContract } from '@aztec/noir-contracts.js/Token'; import { jest } from '@jest/globals'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { deployToken, mintTokensToPrivate } from './fixtures/token_utils.js'; import { setup } from './fixtures/utils.js'; import type { TestWallet } from './test-wallet/test_wallet.js'; @@ -48,7 +48,7 @@ describe('Orderbook', () => { accounts: [adminAddress, makerAddress, takerAddress], aztecNode, logger, - } = await setup(3, { ...PIPELINING_SETUP_OPTS })); + } = await setup(3, { ...FAST_E2E_SETUP_OPTS })); ({ contract: token0 } = await deployToken(wallet, adminAddress, 0n, logger)); ({ contract: token1 } = await deployToken(wallet, adminAddress, 0n, logger)); diff --git a/yarn-project/end-to-end/src/e2e_partial_notes.test.ts b/yarn-project/end-to-end/src/e2e_partial_notes.test.ts index c1f92e312c70..e0ac01e3e33e 100644 --- a/yarn-project/end-to-end/src/e2e_partial_notes.test.ts +++ b/yarn-project/end-to-end/src/e2e_partial_notes.test.ts @@ -5,7 +5,7 @@ import type { TokenContract } from '@aztec/noir-contracts.js/Token'; import { jest } from '@jest/globals'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { deployToken, mintTokensToPrivate } from './fixtures/token_utils.js'; import { setup } from './fixtures/utils.js'; @@ -33,7 +33,7 @@ describe('partial notes', () => { wallet, accounts: [adminAddress, liquidityProviderAddress], logger, - } = await setup(2, { ...PIPELINING_SETUP_OPTS })); + } = await setup(2, { ...FAST_E2E_SETUP_OPTS })); const { contract } = await deployToken(wallet, adminAddress, 0n, logger); token0 = contract; diff --git a/yarn-project/end-to-end/src/e2e_pending_note_hashes_contract.test.ts b/yarn-project/end-to-end/src/e2e_pending_note_hashes_contract.test.ts index 2d063995c164..adc2ca4a177a 100644 --- a/yarn-project/end-to-end/src/e2e_pending_note_hashes_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_pending_note_hashes_contract.test.ts @@ -10,7 +10,7 @@ import { } from '@aztec/constants'; import { PendingNoteHashesContract } from '@aztec/noir-test-contracts.js/PendingNoteHashes'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { setup } from './fixtures/utils.js'; import type { TestWallet } from './test-wallet/test_wallet.js'; @@ -29,7 +29,7 @@ describe('e2e_pending_note_hashes_contract', () => { wallet, logger, accounts: [owner], - } = await setup(1, { ...PIPELINING_SETUP_OPTS })); + } = await setup(1, { ...FAST_E2E_SETUP_OPTS })); }); afterAll(() => teardown()); From dbb473bb4f725da0d8937b61572bf3c1991c67cc Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Sat, 16 May 2026 16:22:41 -0300 Subject: [PATCH 07/16] test(e2e): migrate second batch of single-sequencer tests to FAST_E2E_SETUP_OPTS --- yarn-project/end-to-end/src/e2e_abi_types.test.ts | 4 ++-- yarn-project/end-to-end/src/e2e_account_contracts.test.ts | 4 ++-- yarn-project/end-to-end/src/e2e_circuit_recorder.test.ts | 4 ++-- .../end-to-end/src/e2e_crowdfunding_and_claim.test.ts | 4 ++-- yarn-project/end-to-end/src/e2e_custom_message.test.ts | 4 ++-- yarn-project/end-to-end/src/e2e_double_spend.test.ts | 4 ++-- yarn-project/end-to-end/src/e2e_escrow_contract.test.ts | 4 ++-- .../end-to-end/src/e2e_kernelless_simulation.test.ts | 4 ++-- yarn-project/end-to-end/src/e2e_large_public_event.test.ts | 4 ++-- .../end-to-end/src/e2e_multiple_accounts_1_enc_key.test.ts | 4 ++-- .../end-to-end/src/e2e_nested_utility_calls.test.ts | 6 +++--- yarn-project/end-to-end/src/e2e_nft.test.ts | 4 ++-- yarn-project/end-to-end/src/e2e_note_getter.test.ts | 4 ++-- yarn-project/end-to-end/src/e2e_option_params.test.ts | 4 ++-- yarn-project/end-to-end/src/e2e_ordering.test.ts | 4 ++-- yarn-project/end-to-end/src/e2e_phase_check.test.ts | 4 ++-- .../end-to-end/src/e2e_private_voting_contract.test.ts | 4 ++-- yarn-project/end-to-end/src/e2e_pxe.test.ts | 4 ++-- yarn-project/end-to-end/src/e2e_scope_isolation.test.ts | 4 ++-- yarn-project/end-to-end/src/e2e_state_vars.test.ts | 4 ++-- yarn-project/end-to-end/src/e2e_static_calls.test.ts | 4 ++-- yarn-project/end-to-end/src/e2e_tx_effect_oracle.test.ts | 4 ++-- 22 files changed, 45 insertions(+), 45 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_abi_types.test.ts b/yarn-project/end-to-end/src/e2e_abi_types.test.ts index 58b2bef61798..445aade79f61 100644 --- a/yarn-project/end-to-end/src/e2e_abi_types.test.ts +++ b/yarn-project/end-to-end/src/e2e_abi_types.test.ts @@ -7,7 +7,7 @@ import { AbiTypesContract } from '@aztec/noir-test-contracts.js/AbiTypes'; import { jest } from '@jest/globals'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { setup } from './fixtures/utils.js'; const TIMEOUT = 300_000; @@ -31,7 +31,7 @@ describe('AbiTypes', () => { teardown, wallet, accounts: [defaultAccountAddress], - } = await setup(1, { ...PIPELINING_SETUP_OPTS })); + } = await setup(1, { ...FAST_E2E_SETUP_OPTS })); ({ contract: abiTypesContract } = await AbiTypesContract.deploy(wallet).send({ from: defaultAccountAddress })); }); diff --git a/yarn-project/end-to-end/src/e2e_account_contracts.test.ts b/yarn-project/end-to-end/src/e2e_account_contracts.test.ts index 3274a1706607..87cd59e71b7c 100644 --- a/yarn-project/end-to-end/src/e2e_account_contracts.test.ts +++ b/yarn-project/end-to-end/src/e2e_account_contracts.test.ts @@ -17,7 +17,7 @@ import { ChildContract } from '@aztec/noir-test-contracts.js/Child'; import { createPXE, getPXEConfig } from '@aztec/pxe/server'; import { deriveSigningKey } from '@aztec/stdlib/keys'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { setup } from './fixtures/utils.js'; import { TestWallet } from './test-wallet/test_wallet.js'; import { AztecNodeProxy } from './test-wallet/utils.js'; @@ -62,7 +62,7 @@ const itShouldBehaveLikeAnAccountContract = ( }; ({ logger, teardown, aztecNode } = await setup(0, { - ...PIPELINING_SETUP_OPTS, + ...FAST_E2E_SETUP_OPTS, initialFundedAccounts: [accountData], })); wallet = await TestWalletInternals.create(aztecNode); diff --git a/yarn-project/end-to-end/src/e2e_circuit_recorder.test.ts b/yarn-project/end-to-end/src/e2e_circuit_recorder.test.ts index a35b3c6f5b1e..45b122309370 100644 --- a/yarn-project/end-to-end/src/e2e_circuit_recorder.test.ts +++ b/yarn-project/end-to-end/src/e2e_circuit_recorder.test.ts @@ -3,7 +3,7 @@ import { MAX_APPS_PER_KERNEL } from '@aztec/constants'; import fs from 'fs/promises'; import path from 'path'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { setup } from './fixtures/utils.js'; /** @@ -17,7 +17,7 @@ describe('Circuit Recorder', () => { process.env.CIRCUIT_RECORD_DIR = RECORD_DIR; // Run setup which deploys an account contract and runs kernels - const { teardown } = await setup(1, { ...PIPELINING_SETUP_OPTS }); + const { teardown } = await setup(1, { ...FAST_E2E_SETUP_OPTS }); // Check recording directory exists const dirExists = await fs.stat(RECORD_DIR).then( diff --git a/yarn-project/end-to-end/src/e2e_crowdfunding_and_claim.test.ts b/yarn-project/end-to-end/src/e2e_crowdfunding_and_claim.test.ts index 03221e578a8c..66e3fc8b20ad 100644 --- a/yarn-project/end-to-end/src/e2e_crowdfunding_and_claim.test.ts +++ b/yarn-project/end-to-end/src/e2e_crowdfunding_and_claim.test.ts @@ -10,7 +10,7 @@ import type { AztecNode, AztecNodeDebug } from '@aztec/stdlib/interfaces/client' import { jest } from '@jest/globals'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { mintTokensToPrivate } from './fixtures/token_utils.js'; import { setup } from './fixtures/utils.js'; import type { TestWallet } from './test-wallet/test_wallet.js'; @@ -61,7 +61,7 @@ describe('e2e_crowdfunding_and_claim', () => { wallet, aztecNode: _aztecNode, accounts: [operatorAddress, donor1Address, donor2Address], - } = await setup(3, { ...PIPELINING_SETUP_OPTS })); + } = await setup(3, { ...FAST_E2E_SETUP_OPTS })); // We set the deadline to a week from now deadline = (await cheatCodes.eth.lastBlockTimestamp()) + 7 * 24 * 60 * 60; diff --git a/yarn-project/end-to-end/src/e2e_custom_message.test.ts b/yarn-project/end-to-end/src/e2e_custom_message.test.ts index e9c703ddc925..17fed59fd9ec 100644 --- a/yarn-project/end-to-end/src/e2e_custom_message.test.ts +++ b/yarn-project/end-to-end/src/e2e_custom_message.test.ts @@ -7,7 +7,7 @@ import { CustomMessageContract, type MultiLogEvent } from '@aztec/noir-test-cont import { jest } from '@jest/globals'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { ensureAccountContractsPublished, setup } from './fixtures/utils.js'; const TIMEOUT = 300_000; @@ -25,7 +25,7 @@ describe('CustomMessage - Multi-Log Pattern', () => { teardown, wallet, accounts: [account], - } = await setup(1, { ...PIPELINING_SETUP_OPTS })); + } = await setup(1, { ...FAST_E2E_SETUP_OPTS })); await ensureAccountContractsPublished(wallet, [account]); ({ contract } = await CustomMessageContract.deploy(wallet).send({ from: account })); }); diff --git a/yarn-project/end-to-end/src/e2e_double_spend.test.ts b/yarn-project/end-to-end/src/e2e_double_spend.test.ts index 7b34b4e6c3ad..16d38ae42065 100644 --- a/yarn-project/end-to-end/src/e2e_double_spend.test.ts +++ b/yarn-project/end-to-end/src/e2e_double_spend.test.ts @@ -5,7 +5,7 @@ import { TxExecutionResult } from '@aztec/aztec.js/tx'; import type { Wallet } from '@aztec/aztec.js/wallet'; import { TestContract } from '@aztec/noir-test-contracts.js/Test'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { setup } from './fixtures/utils.js'; describe('e2e_double_spend', () => { @@ -24,7 +24,7 @@ describe('e2e_double_spend', () => { wallet, accounts: [defaultAccountAddress], logger, - } = await setup(1, { ...PIPELINING_SETUP_OPTS })); + } = await setup(1, { ...FAST_E2E_SETUP_OPTS })); ({ contract } = await TestContract.deploy(wallet).send({ from: defaultAccountAddress })); diff --git a/yarn-project/end-to-end/src/e2e_escrow_contract.test.ts b/yarn-project/end-to-end/src/e2e_escrow_contract.test.ts index 57662fb667ed..99a20785c559 100644 --- a/yarn-project/end-to-end/src/e2e_escrow_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_escrow_contract.test.ts @@ -7,7 +7,7 @@ import { EscrowContract } from '@aztec/noir-contracts.js/Escrow'; import { TokenContract } from '@aztec/noir-contracts.js/Token'; import type { PublicKeys } from '@aztec/stdlib/keys'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { expectTokenBalance, mintTokensToPrivate } from './fixtures/token_utils.js'; import { setup } from './fixtures/utils.js'; import type { TestWallet } from './test-wallet/test_wallet.js'; @@ -33,7 +33,7 @@ describe('e2e_escrow_contract', () => { wallet, accounts: [owner, recipient], logger, - } = await setup(2, { ...PIPELINING_SETUP_OPTS })); + } = await setup(2, { ...FAST_E2E_SETUP_OPTS })); // Generate private key for escrow contract, register key in PXE, and deploy // Note that we need to register it first if we want to emit an encrypted note for it in the constructor diff --git a/yarn-project/end-to-end/src/e2e_kernelless_simulation.test.ts b/yarn-project/end-to-end/src/e2e_kernelless_simulation.test.ts index 3b140fd59960..f3657f9c6fed 100644 --- a/yarn-project/end-to-end/src/e2e_kernelless_simulation.test.ts +++ b/yarn-project/end-to-end/src/e2e_kernelless_simulation.test.ts @@ -20,7 +20,7 @@ import { MerkleTreeId } from '@aztec/stdlib/trees'; import { jest } from '@jest/globals'; import { simulateThroughAuthwitProxy } from './fixtures/authwit_proxy.js'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { deployToken, mintTokensToPrivate } from './fixtures/token_utils.js'; import { setup } from './fixtures/utils.js'; import type { TestWallet } from './test-wallet/test_wallet.js'; @@ -57,7 +57,7 @@ describe('Kernelless simulation', () => { wallet, accounts: [adminAddress, liquidityProviderAddress, swapperAddress], logger, - } = await setup(3, { ...PIPELINING_SETUP_OPTS })); + } = await setup(3, { ...FAST_E2E_SETUP_OPTS })); ({ contract: token0 } = await deployToken(wallet, adminAddress, 0n, logger)); ({ contract: token1 } = await deployToken(wallet, adminAddress, 0n, logger)); diff --git a/yarn-project/end-to-end/src/e2e_large_public_event.test.ts b/yarn-project/end-to-end/src/e2e_large_public_event.test.ts index 4262949adbbc..baad93a6be34 100644 --- a/yarn-project/end-to-end/src/e2e_large_public_event.test.ts +++ b/yarn-project/end-to-end/src/e2e_large_public_event.test.ts @@ -8,7 +8,7 @@ import type { AztecAddress } from '@aztec/stdlib/aztec-address'; import { jest } from '@jest/globals'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { setup } from './fixtures/utils.js'; const TIMEOUT = 300_000; @@ -29,7 +29,7 @@ describe('LargePublicEvent', () => { wallet, aztecNode, accounts: [accountAddress], - } = await setup(1, { ...PIPELINING_SETUP_OPTS })); + } = await setup(1, { ...FAST_E2E_SETUP_OPTS })); ({ contract } = await LargePublicEventContract.deploy(wallet).send({ from: accountAddress })); }); diff --git a/yarn-project/end-to-end/src/e2e_multiple_accounts_1_enc_key.test.ts b/yarn-project/end-to-end/src/e2e_multiple_accounts_1_enc_key.test.ts index 0dfd87664d6b..0634af271766 100644 --- a/yarn-project/end-to-end/src/e2e_multiple_accounts_1_enc_key.test.ts +++ b/yarn-project/end-to-end/src/e2e_multiple_accounts_1_enc_key.test.ts @@ -5,7 +5,7 @@ import type { Logger } from '@aztec/aztec.js/log'; import type { Wallet } from '@aztec/aztec.js/wallet'; import { TokenContract } from '@aztec/noir-contracts.js/Token'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { deployToken, expectTokenBalance } from './fixtures/token_utils.js'; import { setup } from './fixtures/utils.js'; @@ -40,7 +40,7 @@ describe('e2e_multiple_accounts_1_enc_key', () => { ); ({ teardown, logger, wallet, accounts } = await setup(numAccounts, { - ...PIPELINING_SETUP_OPTS, + ...FAST_E2E_SETUP_OPTS, initialFundedAccounts, })); logger.info('Account contracts deployed'); diff --git a/yarn-project/end-to-end/src/e2e_nested_utility_calls.test.ts b/yarn-project/end-to-end/src/e2e_nested_utility_calls.test.ts index 613cb84f41aa..e6482f1c5903 100644 --- a/yarn-project/end-to-end/src/e2e_nested_utility_calls.test.ts +++ b/yarn-project/end-to-end/src/e2e_nested_utility_calls.test.ts @@ -5,7 +5,7 @@ import type { UtilityCallAuthorizationRequest } from '@aztec/pxe/server'; import { jest } from '@jest/globals'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { setup } from './fixtures/utils.js'; const TIMEOUT = 300_000; @@ -26,7 +26,7 @@ describe('Nested utility calls', () => { teardown, wallet, accounts: [defaultAccountAddress], - } = await setup(1, { ...PIPELINING_SETUP_OPTS })); + } = await setup(1, { ...FAST_E2E_SETUP_OPTS })); ({ contract: contractA } = await NestedUtilityContract.deploy(wallet).send({ from: defaultAccountAddress })); ({ contract: contractB } = await NestedUtilityContract.deploy(wallet).send({ from: defaultAccountAddress })); }); @@ -78,7 +78,7 @@ describe('authorizeUtilityCall hook', () => { wallet, accounts: [defaultAccountAddress], } = await setup(1, { - ...PIPELINING_SETUP_OPTS, + ...FAST_E2E_SETUP_OPTS, pxeCreationOptions: { hooks: { authorizeUtilityCall: (req: UtilityCallAuthorizationRequest) => { diff --git a/yarn-project/end-to-end/src/e2e_nft.test.ts b/yarn-project/end-to-end/src/e2e_nft.test.ts index c98da00e2c9e..ff05d01bf511 100644 --- a/yarn-project/end-to-end/src/e2e_nft.test.ts +++ b/yarn-project/end-to-end/src/e2e_nft.test.ts @@ -5,7 +5,7 @@ import { NFTContract } from '@aztec/noir-contracts.js/NFT'; import { jest } from '@jest/globals'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { setup } from './fixtures/utils.js'; const TIMEOUT = 300_000; @@ -31,7 +31,7 @@ describe('NFT', () => { beforeAll(async () => { let accounts: AztecAddress[]; - ({ teardown, wallet, accounts } = await setup(4, { ...PIPELINING_SETUP_OPTS })); + ({ teardown, wallet, accounts } = await setup(4, { ...FAST_E2E_SETUP_OPTS })); [adminAddress, minterAddress, user1Address, user2Address] = accounts; ({ contract: nftContract } = await NFTContract.deploy(wallet, adminAddress, 'FROG', 'FRG').send({ diff --git a/yarn-project/end-to-end/src/e2e_note_getter.test.ts b/yarn-project/end-to-end/src/e2e_note_getter.test.ts index 3a793fe86d05..d04d50d0a257 100644 --- a/yarn-project/end-to-end/src/e2e_note_getter.test.ts +++ b/yarn-project/end-to-end/src/e2e_note_getter.test.ts @@ -4,7 +4,7 @@ import type { Wallet } from '@aztec/aztec.js/wallet'; import { NoteGetterContract } from '@aztec/noir-test-contracts.js/NoteGetter'; import { TestContract } from '@aztec/noir-test-contracts.js/Test'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { setup } from './fixtures/utils.js'; interface NoirBoundedVec { @@ -26,7 +26,7 @@ describe('e2e_note_getter', () => { teardown, wallet, accounts: [defaultAddress], - } = await setup(1, { ...PIPELINING_SETUP_OPTS })); + } = await setup(1, { ...FAST_E2E_SETUP_OPTS })); }); afterAll(() => teardown()); diff --git a/yarn-project/end-to-end/src/e2e_option_params.test.ts b/yarn-project/end-to-end/src/e2e_option_params.test.ts index 58b0d17d40c0..362d6d52b016 100644 --- a/yarn-project/end-to-end/src/e2e_option_params.test.ts +++ b/yarn-project/end-to-end/src/e2e_option_params.test.ts @@ -5,7 +5,7 @@ import { OptionParamContract } from '@aztec/noir-test-contracts.js/OptionParam'; import { jest } from '@jest/globals'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { setup } from './fixtures/utils.js'; const TIMEOUT = 300_000; @@ -33,7 +33,7 @@ describe('Option params', () => { teardown, wallet, accounts: [defaultAccountAddress], - } = await setup(1, { ...PIPELINING_SETUP_OPTS })); + } = await setup(1, { ...FAST_E2E_SETUP_OPTS })); contract = (await OptionParamContract.deploy(wallet).send({ from: defaultAccountAddress })).contract; }); diff --git a/yarn-project/end-to-end/src/e2e_ordering.test.ts b/yarn-project/end-to-end/src/e2e_ordering.test.ts index a460beefff7e..8a545ae780d9 100644 --- a/yarn-project/end-to-end/src/e2e_ordering.test.ts +++ b/yarn-project/end-to-end/src/e2e_ordering.test.ts @@ -11,7 +11,7 @@ import { computeCalldataHash } from '@aztec/stdlib/hash'; import { jest } from '@jest/globals'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { setup } from './fixtures/utils.js'; import type { TestWallet } from './test-wallet/test_wallet.js'; import { proveInteraction } from './test-wallet/utils.js'; @@ -45,7 +45,7 @@ describe('e2e_ordering', () => { wallet, aztecNode, accounts: [defaultAccountAddress], - } = await setup(1, { ...PIPELINING_SETUP_OPTS })); + } = await setup(1, { ...FAST_E2E_SETUP_OPTS })); }, TIMEOUT); afterEach(() => teardown()); diff --git a/yarn-project/end-to-end/src/e2e_phase_check.test.ts b/yarn-project/end-to-end/src/e2e_phase_check.test.ts index 7d447632b424..c975952854e9 100644 --- a/yarn-project/end-to-end/src/e2e_phase_check.test.ts +++ b/yarn-project/end-to-end/src/e2e_phase_check.test.ts @@ -9,7 +9,7 @@ import { getContractInstanceFromInstantiationParams } from '@aztec/stdlib/contra import { PublicDataTreeLeaf } from '@aztec/stdlib/trees'; import { defaultInitialAccountFeeJuice } from '@aztec/world-state/testing'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { setup } from './fixtures/utils.js'; import type { TestWallet } from './test-wallet/test_wallet.js'; @@ -34,7 +34,7 @@ describe('Phase check', () => { teardown, wallet, accounts: [defaultAccountAddress], - } = await setup(1, { ...PIPELINING_SETUP_OPTS, genesisPublicData: [genesisBalanceEntry] })); + } = await setup(1, { ...FAST_E2E_SETUP_OPTS, genesisPublicData: [genesisBalanceEntry] })); ({ contract } = await TestContract.deploy(wallet).send({ from: defaultAccountAddress })); sponsoredFPC = await SponsoredFPCNoEndSetupContract.deploy(wallet, { diff --git a/yarn-project/end-to-end/src/e2e_private_voting_contract.test.ts b/yarn-project/end-to-end/src/e2e_private_voting_contract.test.ts index 077a5e55400a..600276720959 100644 --- a/yarn-project/end-to-end/src/e2e_private_voting_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_private_voting_contract.test.ts @@ -5,7 +5,7 @@ import type { Wallet } from '@aztec/aztec.js/wallet'; import { PrivateVotingContract } from '@aztec/noir-contracts.js/PrivateVoting'; import { TX_ERROR_EXISTING_NULLIFIER } from '@aztec/stdlib/tx'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { setup } from './fixtures/utils.js'; describe('e2e_voting_contract', () => { @@ -24,7 +24,7 @@ describe('e2e_voting_contract', () => { wallet, logger, accounts: [owner], - } = await setup(1, { ...PIPELINING_SETUP_OPTS })); + } = await setup(1, { ...FAST_E2E_SETUP_OPTS })); ({ contract: votingContract } = await PrivateVotingContract.deploy(wallet, owner).send({ from: owner })); diff --git a/yarn-project/end-to-end/src/e2e_pxe.test.ts b/yarn-project/end-to-end/src/e2e_pxe.test.ts index 8240208ca70c..f4851b6a6635 100644 --- a/yarn-project/end-to-end/src/e2e_pxe.test.ts +++ b/yarn-project/end-to-end/src/e2e_pxe.test.ts @@ -3,7 +3,7 @@ import { Fr } from '@aztec/aztec.js/fields'; import { TestContract } from '@aztec/noir-test-contracts.js/Test'; import { TX_ERROR_EXISTING_NULLIFIER } from '@aztec/stdlib/tx'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { setup } from './fixtures/utils.js'; import type { TestWallet } from './test-wallet/test_wallet.js'; @@ -21,7 +21,7 @@ describe('e2e_pxe', () => { teardown, wallet, accounts: [defaultAccountAddress], - } = await setup(1, { ...PIPELINING_SETUP_OPTS })); + } = await setup(1, { ...FAST_E2E_SETUP_OPTS })); ({ contract } = await TestContract.deploy(wallet).send({ from: defaultAccountAddress })); }); diff --git a/yarn-project/end-to-end/src/e2e_scope_isolation.test.ts b/yarn-project/end-to-end/src/e2e_scope_isolation.test.ts index cebea5cdd26e..a11ec67aabde 100644 --- a/yarn-project/end-to-end/src/e2e_scope_isolation.test.ts +++ b/yarn-project/end-to-end/src/e2e_scope_isolation.test.ts @@ -2,7 +2,7 @@ import type { AztecAddress } from '@aztec/aztec.js/addresses'; import type { Wallet } from '@aztec/aztec.js/wallet'; import { ScopeTestContract } from '@aztec/noir-test-contracts.js/ScopeTest'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { setup } from './fixtures/utils.js'; describe('e2e scope isolation', () => { @@ -19,7 +19,7 @@ describe('e2e scope isolation', () => { const BOB_NOTE_VALUE = 100n; beforeAll(async () => { - ({ teardown, wallet, accounts } = await setup(3, { ...PIPELINING_SETUP_OPTS })); + ({ teardown, wallet, accounts } = await setup(3, { ...FAST_E2E_SETUP_OPTS })); [alice, bob, charlie] = accounts; ({ contract } = await ScopeTestContract.deploy(wallet).send({ from: alice })); diff --git a/yarn-project/end-to-end/src/e2e_state_vars.test.ts b/yarn-project/end-to-end/src/e2e_state_vars.test.ts index 37b59691a5b7..75697d37ddee 100644 --- a/yarn-project/end-to-end/src/e2e_state_vars.test.ts +++ b/yarn-project/end-to-end/src/e2e_state_vars.test.ts @@ -7,7 +7,7 @@ import { StateVarsContract } from '@aztec/noir-test-contracts.js/StateVars'; import { jest } from '@jest/globals'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { setup } from './fixtures/utils.js'; import type { TestWallet } from './test-wallet/test_wallet.js'; import { proveInteraction } from './test-wallet/utils.js'; @@ -33,7 +33,7 @@ describe('e2e_state_vars', () => { aztecNode, wallet, accounts: [defaultAccountAddress], - } = await setup(1, { ...PIPELINING_SETUP_OPTS })); + } = await setup(1, { ...FAST_E2E_SETUP_OPTS })); ({ contract } = await StateVarsContract.deploy(wallet).send({ from: defaultAccountAddress })); }); diff --git a/yarn-project/end-to-end/src/e2e_static_calls.test.ts b/yarn-project/end-to-end/src/e2e_static_calls.test.ts index 422bb9a2b09d..65bc1cdbdc61 100644 --- a/yarn-project/end-to-end/src/e2e_static_calls.test.ts +++ b/yarn-project/end-to-end/src/e2e_static_calls.test.ts @@ -4,7 +4,7 @@ import { StaticChildContract } from '@aztec/noir-test-contracts.js/StaticChild'; import { StaticParentContract } from '@aztec/noir-test-contracts.js/StaticParent'; import { - PIPELINING_SETUP_OPTS, + FAST_E2E_SETUP_OPTS, STATIC_CALL_STATE_MODIFICATION_ERROR, STATIC_CONTEXT_ASSERTION_ERROR, } from './fixtures/fixtures.js'; @@ -23,7 +23,7 @@ describe('e2e_static_calls', () => { teardown, wallet, accounts: [owner], - } = await setup(1, { ...PIPELINING_SETUP_OPTS })); + } = await setup(1, { ...FAST_E2E_SETUP_OPTS })); sender = owner; ({ contract: parentContract } = await StaticParentContract.deploy(wallet).send({ from: owner })); ({ contract: childContract } = await StaticChildContract.deploy(wallet).send({ from: owner })); diff --git a/yarn-project/end-to-end/src/e2e_tx_effect_oracle.test.ts b/yarn-project/end-to-end/src/e2e_tx_effect_oracle.test.ts index 584501383c88..c6133dcec73e 100644 --- a/yarn-project/end-to-end/src/e2e_tx_effect_oracle.test.ts +++ b/yarn-project/end-to-end/src/e2e_tx_effect_oracle.test.ts @@ -19,7 +19,7 @@ import type { TxEffect, TxHash } from '@aztec/stdlib/tx'; import { jest } from '@jest/globals'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { setup } from './fixtures/utils.js'; const TIMEOUT = 120_000; @@ -49,7 +49,7 @@ describe('e2e tx effect oracle', () => { wallet, aztecNode, accounts: [defaultAccountAddress], - } = await setup(1, { ...PIPELINING_SETUP_OPTS })); + } = await setup(1, { ...FAST_E2E_SETUP_OPTS })); const { contract: deployed, receipt } = await TxEffectOracleTestContract.deploy(wallet).send({ from: defaultAccountAddress, }); From 5f3b0fd1c57d599febd985e9c73384b94a3586b5 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Sat, 16 May 2026 16:22:41 -0300 Subject: [PATCH 08/16] test(e2e): migrate e2e_amm to FAST_E2E_SETUP_OPTS Missed in batch 2 because of its third argument (syncChainTip: 'checkpointed'). --- yarn-project/end-to-end/src/e2e_amm.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_amm.test.ts b/yarn-project/end-to-end/src/e2e_amm.test.ts index cbab3c0e92a2..3637e96c1af8 100644 --- a/yarn-project/end-to-end/src/e2e_amm.test.ts +++ b/yarn-project/end-to-end/src/e2e_amm.test.ts @@ -6,7 +6,7 @@ import type { TokenContract } from '@aztec/noir-contracts.js/Token'; import { jest } from '@jest/globals'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { deployToken, mintTokensToPrivate } from './fixtures/token_utils.js'; import { setup } from './fixtures/utils.js'; import type { TestWallet } from './test-wallet/test_wallet.js'; @@ -51,7 +51,7 @@ describe('AMM', () => { wallet, accounts: [adminAddress, liquidityProviderAddress, otherLiquidityProviderAddress, swapperAddress], logger, - } = await setup(4, { ...PIPELINING_SETUP_OPTS }, { syncChainTip: 'checkpointed' })); + } = await setup(4, { ...FAST_E2E_SETUP_OPTS }, { syncChainTip: 'checkpointed' })); ({ contract: token0 } = await deployToken(wallet, adminAddress, 0n, logger)); ({ contract: token1 } = await deployToken(wallet, adminAddress, 0n, logger)); From 7952b211d9b60d616145c3b5a78236476d678ef0 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Sat, 16 May 2026 16:52:01 -0300 Subject: [PATCH 09/16] test(e2e): thread opts through TokenContractTest + NestedContractTest and migrate to FAST_E2E_SETUP_OPTS --- .../src/e2e_nested_contract/importer.test.ts | 3 ++- .../e2e_nested_contract/manual_private_call.test.ts | 3 ++- .../manual_private_enqueue.test.ts | 3 ++- .../src/e2e_nested_contract/manual_public.test.ts | 3 ++- .../src/e2e_nested_contract/nested_contract_test.ts | 4 +++- .../src/e2e_token_contract/access_control.test.ts | 3 ++- .../end-to-end/src/e2e_token_contract/burn.test.ts | 4 ++-- .../src/e2e_token_contract/minting.test.ts | 4 ++-- .../private_transfer_recursion.test.ts | 3 ++- .../src/e2e_token_contract/reading_constants.test.ts | 3 ++- .../src/e2e_token_contract/token_contract_test.ts | 12 ++++++++++-- .../src/e2e_token_contract/transfer.test.ts | 3 ++- .../e2e_token_contract/transfer_in_private.test.ts | 4 ++-- .../e2e_token_contract/transfer_in_public.test.ts | 4 ++-- .../e2e_token_contract/transfer_to_private.test.ts | 4 ++-- .../e2e_token_contract/transfer_to_public.test.ts | 4 ++-- 16 files changed, 41 insertions(+), 23 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_nested_contract/importer.test.ts b/yarn-project/end-to-end/src/e2e_nested_contract/importer.test.ts index aab6d6fb59c4..89ed9d178812 100644 --- a/yarn-project/end-to-end/src/e2e_nested_contract/importer.test.ts +++ b/yarn-project/end-to-end/src/e2e_nested_contract/importer.test.ts @@ -1,6 +1,7 @@ import { ImportTestContract } from '@aztec/noir-test-contracts.js/ImportTest'; import { TestContract } from '@aztec/noir-test-contracts.js/Test'; +import { FAST_E2E_SETUP_OPTS } from '../fixtures/fixtures.js'; import { NestedContractTest } from './nested_contract_test.js'; describe('e2e_nested_contract manual', () => { @@ -10,7 +11,7 @@ describe('e2e_nested_contract manual', () => { let { wallet, logger, defaultAccountAddress } = t; beforeAll(async () => { - await t.setup(); + await t.setup({ ...FAST_E2E_SETUP_OPTS }); ({ wallet, logger, defaultAccountAddress } = t); }); diff --git a/yarn-project/end-to-end/src/e2e_nested_contract/manual_private_call.test.ts b/yarn-project/end-to-end/src/e2e_nested_contract/manual_private_call.test.ts index d702434c7f10..01c0ebc940a3 100644 --- a/yarn-project/end-to-end/src/e2e_nested_contract/manual_private_call.test.ts +++ b/yarn-project/end-to-end/src/e2e_nested_contract/manual_private_call.test.ts @@ -1,3 +1,4 @@ +import { FAST_E2E_SETUP_OPTS } from '../fixtures/fixtures.js'; import { NestedContractTest } from './nested_contract_test.js'; describe('e2e_nested_contract manual', () => { @@ -5,7 +6,7 @@ describe('e2e_nested_contract manual', () => { let { parentContract, childContract, defaultAccountAddress } = t; beforeAll(async () => { - await t.setup(); + await t.setup({ ...FAST_E2E_SETUP_OPTS }); await t.applyManual(); ({ parentContract, childContract, defaultAccountAddress } = t); }); diff --git a/yarn-project/end-to-end/src/e2e_nested_contract/manual_private_enqueue.test.ts b/yarn-project/end-to-end/src/e2e_nested_contract/manual_private_enqueue.test.ts index 0e19664a5662..c92e0c2c9d2b 100644 --- a/yarn-project/end-to-end/src/e2e_nested_contract/manual_private_enqueue.test.ts +++ b/yarn-project/end-to-end/src/e2e_nested_contract/manual_private_enqueue.test.ts @@ -3,6 +3,7 @@ import { Fr } from '@aztec/aztec.js/fields'; import { ChildContract } from '@aztec/noir-test-contracts.js/Child'; import { ParentContract } from '@aztec/noir-test-contracts.js/Parent'; +import { FAST_E2E_SETUP_OPTS } from '../fixtures/fixtures.js'; import { NestedContractTest } from './nested_contract_test.js'; describe('e2e_nested_contract manual_enqueue', () => { @@ -14,7 +15,7 @@ describe('e2e_nested_contract manual_enqueue', () => { beforeAll(async () => { // We don't deploy contracts in beforeAll because every test requires a fresh setup - await t.setup(); + await t.setup({ ...FAST_E2E_SETUP_OPTS }); ({ wallet, defaultAccountAddress, aztecNode } = t); }); diff --git a/yarn-project/end-to-end/src/e2e_nested_contract/manual_public.test.ts b/yarn-project/end-to-end/src/e2e_nested_contract/manual_public.test.ts index a699ea8f1764..e654bc39df8a 100644 --- a/yarn-project/end-to-end/src/e2e_nested_contract/manual_public.test.ts +++ b/yarn-project/end-to-end/src/e2e_nested_contract/manual_public.test.ts @@ -4,6 +4,7 @@ import { Fr } from '@aztec/aztec.js/fields'; import { toBigIntBE } from '@aztec/foundation/bigint-buffer'; import { serializeToBuffer } from '@aztec/foundation/serialize'; +import { FAST_E2E_SETUP_OPTS } from '../fixtures/fixtures.js'; import { NestedContractTest } from './nested_contract_test.js'; describe('e2e_nested_contract manual', () => { @@ -14,7 +15,7 @@ describe('e2e_nested_contract manual', () => { aztecNode.getPublicStorageAt('latest', child.address, new Fr(1)); beforeAll(async () => { - await t.setup(); + await t.setup({ ...FAST_E2E_SETUP_OPTS }); await t.applyManual(); ({ wallet, parentContract, childContract, defaultAccountAddress, aztecNode } = t); }); diff --git a/yarn-project/end-to-end/src/e2e_nested_contract/nested_contract_test.ts b/yarn-project/end-to-end/src/e2e_nested_contract/nested_contract_test.ts index 769db81c1ba0..d68dcc808b16 100644 --- a/yarn-project/end-to-end/src/e2e_nested_contract/nested_contract_test.ts +++ b/yarn-project/end-to-end/src/e2e_nested_contract/nested_contract_test.ts @@ -7,6 +7,7 @@ import { ParentContract } from '@aztec/noir-test-contracts.js/Parent'; import { type EndToEndContext, + type SetupOptions, deployAccounts, publicDeployAccounts, setup, @@ -50,9 +51,10 @@ export class NestedContractTest { await publicDeployAccounts(this.wallet, [this.defaultAccountAddress]); } - async setup() { + async setup(opts: Partial = {}) { this.logger.info('Setting up fresh subsystems'); this.context = await setup(0, { + ...opts, fundSponsoredFPC: true, skipAccountDeployment: true, }); diff --git a/yarn-project/end-to-end/src/e2e_token_contract/access_control.test.ts b/yarn-project/end-to-end/src/e2e_token_contract/access_control.test.ts index 50ac4a7f36be..0bcfb1e451df 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract/access_control.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract/access_control.test.ts @@ -1,3 +1,4 @@ +import { FAST_E2E_SETUP_OPTS } from '../fixtures/fixtures.js'; import { TokenContractTest } from './token_contract_test.js'; describe('e2e_token_contract access control', () => { @@ -5,7 +6,7 @@ describe('e2e_token_contract access control', () => { beforeAll(async () => { t.applyBaseSnapshots(); - await t.setup(); + await t.setup({ ...FAST_E2E_SETUP_OPTS }); }); afterAll(async () => { diff --git a/yarn-project/end-to-end/src/e2e_token_contract/burn.test.ts b/yarn-project/end-to-end/src/e2e_token_contract/burn.test.ts index b9760a983627..8b7fbd0fc1fc 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract/burn.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract/burn.test.ts @@ -2,7 +2,7 @@ import { computeAuthWitMessageHash } from '@aztec/aztec.js/authorization'; import { Fr } from '@aztec/aztec.js/fields'; import { sendThroughAuthwitProxy, simulateThroughAuthwitProxy } from '../fixtures/authwit_proxy.js'; -import { DUPLICATE_NULLIFIER_ERROR, U128_UNDERFLOW_ERROR } from '../fixtures/index.js'; +import { DUPLICATE_NULLIFIER_ERROR, FAST_E2E_SETUP_OPTS, U128_UNDERFLOW_ERROR } from '../fixtures/index.js'; import { TokenContractTest } from './token_contract_test.js'; describe('e2e_token_contract burn', () => { @@ -12,7 +12,7 @@ describe('e2e_token_contract burn', () => { beforeAll(async () => { t.applyBaseSnapshots(); t.applyMintSnapshot(); - await t.setup(); + await t.setup({ ...FAST_E2E_SETUP_OPTS }); // Have to destructure again to ensure we have latest refs. ({ asset, wallet, adminAddress, tokenSim, adminAddress, account1Address } = t); }); diff --git a/yarn-project/end-to-end/src/e2e_token_contract/minting.test.ts b/yarn-project/end-to-end/src/e2e_token_contract/minting.test.ts index 46908a688eab..2d93c6c8e129 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract/minting.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract/minting.test.ts @@ -1,4 +1,4 @@ -import { U128_OVERFLOW_ERROR } from '../fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS, U128_OVERFLOW_ERROR } from '../fixtures/fixtures.js'; import { TokenContractTest } from './token_contract_test.js'; describe('e2e_token_contract minting', () => { @@ -7,7 +7,7 @@ describe('e2e_token_contract minting', () => { beforeAll(async () => { t.applyBaseSnapshots(); - await t.setup(); + await t.setup({ ...FAST_E2E_SETUP_OPTS }); ({ asset, tokenSim, adminAddress, account1Address } = t); }); diff --git a/yarn-project/end-to-end/src/e2e_token_contract/private_transfer_recursion.test.ts b/yarn-project/end-to-end/src/e2e_token_contract/private_transfer_recursion.test.ts index ffa5688df3b5..64c890a6c384 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract/private_transfer_recursion.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract/private_transfer_recursion.test.ts @@ -1,6 +1,7 @@ import { BlockNumber } from '@aztec/foundation/branded-types'; import { TokenContract, type Transfer } from '@aztec/noir-contracts.js/Token'; +import { FAST_E2E_SETUP_OPTS } from '../fixtures/fixtures.js'; import { mintNotes } from '../fixtures/token_utils.js'; import { TokenContractTest } from './token_contract_test.js'; @@ -10,7 +11,7 @@ describe('e2e_token_contract private transfer recursion', () => { beforeAll(async () => { t.applyBaseSnapshots(); - await t.setup(); + await t.setup({ ...FAST_E2E_SETUP_OPTS }); ({ asset, wallet, adminAddress, account1Address, node } = t); }); diff --git a/yarn-project/end-to-end/src/e2e_token_contract/reading_constants.test.ts b/yarn-project/end-to-end/src/e2e_token_contract/reading_constants.test.ts index 185ac4231e8e..e6d08748f921 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract/reading_constants.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract/reading_constants.test.ts @@ -1,5 +1,6 @@ import { readFieldCompressedString } from '@aztec/aztec.js/utils'; +import { FAST_E2E_SETUP_OPTS } from '../fixtures/fixtures.js'; import { TokenContractTest } from './token_contract_test.js'; describe('e2e_token_contract reading constants', () => { @@ -8,7 +9,7 @@ describe('e2e_token_contract reading constants', () => { beforeAll(async () => { t.applyBaseSnapshots(); - await t.setup(); + await t.setup({ ...FAST_E2E_SETUP_OPTS }); }); afterAll(async () => { diff --git a/yarn-project/end-to-end/src/e2e_token_contract/token_contract_test.ts b/yarn-project/end-to-end/src/e2e_token_contract/token_contract_test.ts index bbc7f024fd19..74b8e590bf54 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract/token_contract_test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract/token_contract_test.ts @@ -7,7 +7,14 @@ import { InvalidAccountContract } from '@aztec/noir-test-contracts.js/InvalidAcc import { jest } from '@jest/globals'; -import { type EndToEndContext, deployAccounts, publicDeployAccounts, setup, teardown } from '../fixtures/setup.js'; +import { + type EndToEndContext, + type SetupOptions, + deployAccounts, + publicDeployAccounts, + setup, + teardown, +} from '../fixtures/setup.js'; import { mintTokensToPrivate } from '../fixtures/token_utils.js'; import { TokenSimulator } from '../simulators/token_simulator.js'; import type { TestWallet } from '../test-wallet/test_wallet.js'; @@ -115,8 +122,9 @@ export class TokenContractTest { ); } - async setup() { + async setup(opts: Partial = {}) { this.context = await setup(0, { + ...opts, metricsPort: this.metricsPort, fundSponsoredFPC: true, skipAccountDeployment: true, diff --git a/yarn-project/end-to-end/src/e2e_token_contract/transfer.test.ts b/yarn-project/end-to-end/src/e2e_token_contract/transfer.test.ts index 564707a74c77..f27a48b95c05 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract/transfer.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract/transfer.test.ts @@ -2,6 +2,7 @@ import { AztecAddress, CompleteAddress } from '@aztec/aztec.js/addresses'; import { BlockNumber } from '@aztec/foundation/branded-types'; import { TokenContract, type Transfer } from '@aztec/noir-contracts.js/Token'; +import { FAST_E2E_SETUP_OPTS } from '../fixtures/fixtures.js'; import { TokenContractTest } from './token_contract_test.js'; describe('e2e_token_contract transfer private', () => { @@ -11,7 +12,7 @@ describe('e2e_token_contract transfer private', () => { beforeAll(async () => { t.applyBaseSnapshots(); t.applyMintSnapshot(); - await t.setup(); + await t.setup({ ...FAST_E2E_SETUP_OPTS }); ({ asset, adminAddress, wallet, account1Address, tokenSim } = t); }); diff --git a/yarn-project/end-to-end/src/e2e_token_contract/transfer_in_private.test.ts b/yarn-project/end-to-end/src/e2e_token_contract/transfer_in_private.test.ts index 385c912cec06..5cbd80c4bafe 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract/transfer_in_private.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract/transfer_in_private.test.ts @@ -2,7 +2,7 @@ import { computeAuthWitMessageHash, computeInnerAuthWitHashFromAction } from '@a import { Fr } from '@aztec/aztec.js/fields'; import { sendThroughAuthwitProxy, simulateThroughAuthwitProxy } from '../fixtures/authwit_proxy.js'; -import { DUPLICATE_NULLIFIER_ERROR } from '../fixtures/fixtures.js'; +import { DUPLICATE_NULLIFIER_ERROR, FAST_E2E_SETUP_OPTS } from '../fixtures/fixtures.js'; import { TokenContractTest } from './token_contract_test.js'; describe('e2e_token_contract transfer private', () => { @@ -12,7 +12,7 @@ describe('e2e_token_contract transfer private', () => { beforeAll(async () => { t.applyBaseSnapshots(); t.applyMintSnapshot(); - await t.setup(); + await t.setup({ ...FAST_E2E_SETUP_OPTS }); ({ asset, tokenSim, wallet, adminAddress, account1Address, badAccount } = t); }); diff --git a/yarn-project/end-to-end/src/e2e_token_contract/transfer_in_public.test.ts b/yarn-project/end-to-end/src/e2e_token_contract/transfer_in_public.test.ts index f50c89d80b5a..d4fb86caf953 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract/transfer_in_public.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract/transfer_in_public.test.ts @@ -1,6 +1,6 @@ import { Fr } from '@aztec/aztec.js/fields'; -import { U128_UNDERFLOW_ERROR } from '../fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS, U128_UNDERFLOW_ERROR } from '../fixtures/fixtures.js'; import { type AlertConfig, GrafanaClient } from '../quality_of_service/grafana_client.js'; import { TokenContractTest } from './token_contract_test.js'; @@ -25,7 +25,7 @@ describe('e2e_token_contract transfer public', () => { beforeAll(async () => { t.applyBaseSnapshots(); t.applyMintSnapshot(); - await t.setup(); + await t.setup({ ...FAST_E2E_SETUP_OPTS }); // Have to destructure again to ensure we have latest refs. ({ asset, tokenSim, wallet, adminAddress, account1Address, badAccount } = t); }); diff --git a/yarn-project/end-to-end/src/e2e_token_contract/transfer_to_private.test.ts b/yarn-project/end-to-end/src/e2e_token_contract/transfer_to_private.test.ts index 2688fea57172..fb5f8850962f 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract/transfer_to_private.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract/transfer_to_private.test.ts @@ -1,4 +1,4 @@ -import { U128_UNDERFLOW_ERROR } from '../fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS, U128_UNDERFLOW_ERROR } from '../fixtures/fixtures.js'; import { TokenContractTest } from './token_contract_test.js'; describe('e2e_token_contract transfer_to_private', () => { @@ -8,7 +8,7 @@ describe('e2e_token_contract transfer_to_private', () => { beforeAll(async () => { t.applyBaseSnapshots(); t.applyMintSnapshot(); - await t.setup(); + await t.setup({ ...FAST_E2E_SETUP_OPTS }); // Have to destructure again to ensure we have latest refs. ({ asset, adminAddress, account1Address, tokenSim } = t); }); diff --git a/yarn-project/end-to-end/src/e2e_token_contract/transfer_to_public.test.ts b/yarn-project/end-to-end/src/e2e_token_contract/transfer_to_public.test.ts index 1ff6f31ef53b..6dec5b858834 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract/transfer_to_public.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract/transfer_to_public.test.ts @@ -2,7 +2,7 @@ import { computeAuthWitMessageHash } from '@aztec/aztec.js/authorization'; import { Fr } from '@aztec/aztec.js/fields'; import { sendThroughAuthwitProxy, simulateThroughAuthwitProxy } from '../fixtures/authwit_proxy.js'; -import { DUPLICATE_NULLIFIER_ERROR } from '../fixtures/fixtures.js'; +import { DUPLICATE_NULLIFIER_ERROR, FAST_E2E_SETUP_OPTS } from '../fixtures/fixtures.js'; import { TokenContractTest } from './token_contract_test.js'; describe('e2e_token_contract transfer_to_public', () => { @@ -12,7 +12,7 @@ describe('e2e_token_contract transfer_to_public', () => { beforeAll(async () => { t.applyBaseSnapshots(); t.applyMintSnapshot(); - await t.setup(); + await t.setup({ ...FAST_E2E_SETUP_OPTS }); // Have to destructure again to ensure we have latest refs. ({ asset, wallet, adminAddress, account1Address, tokenSim } = t); }); From d9922ef60fe12ce96d9a20c48449f427bc58a2c4 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Sat, 16 May 2026 17:14:07 -0300 Subject: [PATCH 10/16] test(e2e): migrate e2e_2_pxes and e2e_lending_contract to FAST_E2E_SETUP_OPTS Both already used PIPELINING_SETUP_OPTS. The plan flagged them as second-batch out of caution; verified neither has hand-rolled cc.eth.warp/dateProvider.setTime helpers that would conflict with the wave-1 cheat-code audit. --- yarn-project/aztec/src/testing/checkpoint_auto_prover.test.ts | 3 ++- yarn-project/end-to-end/src/e2e_2_pxes.test.ts | 4 ++-- yarn-project/end-to-end/src/e2e_lending_contract.test.ts | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/yarn-project/aztec/src/testing/checkpoint_auto_prover.test.ts b/yarn-project/aztec/src/testing/checkpoint_auto_prover.test.ts index 97aadf93e173..2c9175e57fc6 100644 --- a/yarn-project/aztec/src/testing/checkpoint_auto_prover.test.ts +++ b/yarn-project/aztec/src/testing/checkpoint_auto_prover.test.ts @@ -134,10 +134,11 @@ describe('CheckpointAutoProver', () => { // The archiver tip advances to 3 immediately, so each checkpoint's wait resolves right away. getL2Tips.mockResolvedValue(makeTips(3)); - markAsProven.mockImplementation(async (n?: CheckpointNumber) => { + markAsProven.mockImplementation((n?: CheckpointNumber) => { if (n !== undefined) { promotedAt.push(n); } + return Promise.resolve(); }); prover.start(); diff --git a/yarn-project/end-to-end/src/e2e_2_pxes.test.ts b/yarn-project/end-to-end/src/e2e_2_pxes.test.ts index 50684782c3e7..f2f74573f0bb 100644 --- a/yarn-project/end-to-end/src/e2e_2_pxes.test.ts +++ b/yarn-project/end-to-end/src/e2e_2_pxes.test.ts @@ -9,7 +9,7 @@ import { ChildContract } from '@aztec/noir-test-contracts.js/Child'; import { expect, jest } from '@jest/globals'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import { deployToken, expectTokenBalance, mintTokensToPrivate } from './fixtures/token_utils.js'; import { setup, setupPXEAndGetWallet } from './fixtures/utils.js'; import { TestWallet } from './test-wallet/test_wallet.js'; @@ -53,7 +53,7 @@ describe('e2e_2_pxes', () => { accounts: [accountAAddress], logger, teardown: teardownA, - } = await setup(1, { ...PIPELINING_SETUP_OPTS, numberOfInitialFundedAccounts: 3 })); + } = await setup(1, { ...FAST_E2E_SETUP_OPTS, numberOfInitialFundedAccounts: 3 })); ({ wallet: walletB, diff --git a/yarn-project/end-to-end/src/e2e_lending_contract.test.ts b/yarn-project/end-to-end/src/e2e_lending_contract.test.ts index 58a603970711..51a03c9a7f9c 100644 --- a/yarn-project/end-to-end/src/e2e_lending_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_lending_contract.test.ts @@ -12,7 +12,7 @@ import { TokenContract } from '@aztec/noir-contracts.js/Token'; import { afterAll, jest } from '@jest/globals'; -import { PIPELINING_SETUP_OPTS } from './fixtures/fixtures.js'; +import { FAST_E2E_SETUP_OPTS } from './fixtures/fixtures.js'; import type { EndToEndContext } from './fixtures/setup.js'; import { mintTokensToPrivate } from './fixtures/token_utils.js'; import { ensureAccountContractsPublished, setup } from './fixtures/utils.js'; @@ -81,7 +81,7 @@ describe('e2e_lending_contract', () => { }; beforeAll(async () => { - const ctx = await setup(1, { ...PIPELINING_SETUP_OPTS }); + const ctx = await setup(1, { ...FAST_E2E_SETUP_OPTS }); ({ teardown, logger, From 7810cac6ba759c83e0554981fb992c2896be97e0 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 18 May 2026 04:31:54 +0100 Subject: [PATCH 11/16] refactor(e2e): use EpochTestSettler in place of CheckpointAutoProver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the PR's bespoke `CheckpointAutoProver` (140 lines + unit tests) with the existing `EpochTestSettler`, which is already the sandbox's proven-tip advancement path (`local-network.ts:213`). `EpochTestSettler` polls `EpochMonitor` and, once an epoch is complete, inserts the epoch out-hash into the outbox and calls `RollupCheatCodes.markAsProven(lastCheckpoint)`. Reusing it kills three audit findings in one go (the dead-weight verify step, unhandled `markAsProven` rejections, and the misleading `trigger()` JSDoc) and as a bonus advances the L2→L1 outbox -- so a follow-up can drop `startProverNode: true` from tests that only spin up a simulated prover to push the outbox. The trade-off is epoch-granularity proven advancement instead of per-checkpoint. With `aztecEpochDuration` left at the 32-slot default, FAST e2e proven would only advance every 384s. Add `aztecEpochDuration: 4` to `FAST_E2E_SETUP_OPTS` (matching `e2e_simple` and `e2e_p2p/fee_asset_price_oracle_gossip`) so an epoch is 48s wall time, and bump the smoke test's proven-tip retry window to 150s for two epochs of slack. --- .../testing/checkpoint_auto_prover.test.ts | 156 ------------------ .../src/testing/checkpoint_auto_prover.ts | 141 ---------------- yarn-project/aztec/src/testing/index.ts | 1 - .../end-to-end/src/e2e_fast_config.test.ts | 16 +- .../end-to-end/src/fixtures/fixtures.ts | 10 +- yarn-project/end-to-end/src/fixtures/setup.ts | 39 ++--- 6 files changed, 36 insertions(+), 327 deletions(-) delete mode 100644 yarn-project/aztec/src/testing/checkpoint_auto_prover.test.ts delete mode 100644 yarn-project/aztec/src/testing/checkpoint_auto_prover.ts diff --git a/yarn-project/aztec/src/testing/checkpoint_auto_prover.test.ts b/yarn-project/aztec/src/testing/checkpoint_auto_prover.test.ts deleted file mode 100644 index 2c9175e57fc6..000000000000 --- a/yarn-project/aztec/src/testing/checkpoint_auto_prover.test.ts +++ /dev/null @@ -1,156 +0,0 @@ -import type { RollupCheatCodes } from '@aztec/ethereum/test'; -import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types'; -import { createLogger } from '@aztec/foundation/log'; -import type { TypedEventEmitter } from '@aztec/foundation/types'; -import type { SequencerEvents } from '@aztec/sequencer-client'; -import type { L2BlockSource, L2Tips } from '@aztec/stdlib/block'; - -import { jest } from '@jest/globals'; -import EventEmitter from 'node:events'; - -import { CheckpointAutoProver } from './checkpoint_auto_prover.js'; - -/** Builds a minimal L2Tips object with the given checkpointed checkpoint number. */ -function makeTips(checkpointedNumber: number): L2Tips { - const cp = CheckpointNumber(checkpointedNumber); - const blockId = { number: BlockNumber(checkpointedNumber), hash: '0x' }; - return { - proposed: blockId, - checkpointed: { block: blockId, checkpoint: { number: cp, hash: '0x' } }, - proposedCheckpoint: { block: blockId, checkpoint: { number: cp, hash: '0x' } }, - proven: { block: blockId, checkpoint: { number: cp, hash: '0x' } }, - finalized: { block: blockId, checkpoint: { number: cp, hash: '0x' } }, - }; -} - -describe('CheckpointAutoProver', () => { - const log = createLogger('test:checkpoint-auto-prover'); - - let sequencer: TypedEventEmitter; - let getL2Tips: ReturnType Promise>>; - let getBlocks: ReturnType; - let markAsProven: ReturnType Promise>>; - let prover: CheckpointAutoProver; - - beforeEach(() => { - // Use a real EventEmitter cast to the typed interface so emits actually fire listeners. - sequencer = new EventEmitter() as unknown as TypedEventEmitter; - - getL2Tips = jest.fn<() => Promise>(); - getBlocks = jest.fn<() => Promise>().mockResolvedValue([]); - - markAsProven = jest.fn<(n?: CheckpointNumber) => Promise>().mockResolvedValue(undefined as unknown as void); - - prover = new CheckpointAutoProver( - { - sequencer, - l2BlockSource: { getL2Tips, getBlocks } as unknown as L2BlockSource, - rollupCheatCodes: { markAsProven } as unknown as RollupCheatCodes, - log, - }, - /* promoteTimeoutSecs= */ 5, - ); - }); - - afterEach(async () => { - await prover.stop(); - }); - - it('marks checkpoint proven after archiver promotes the tip', async () => { - const checkpoint = CheckpointNumber(3); - - // Archiver initially reports checkpoint 0, then 3 after one poll. - getL2Tips.mockResolvedValueOnce(makeTips(0)).mockResolvedValueOnce(makeTips(0)).mockResolvedValue(makeTips(3)); - - prover.start(); - (sequencer as EventEmitter).emit('checkpoint-published', { checkpoint, slot: 10 }); - - await prover.trigger(); - - expect(markAsProven).toHaveBeenCalledWith(checkpoint); - }); - - it('does not mark as proven if archiver never promotes (timeout path)', async () => { - const checkpoint = CheckpointNumber(5); - - // Archiver always returns stale tip (checkpoint 0). - getL2Tips.mockResolvedValue(makeTips(0)); - - // Use a very short timeout so the test is fast. - prover = new CheckpointAutoProver( - { - sequencer, - l2BlockSource: { getL2Tips, getBlocks } as unknown as L2BlockSource, - rollupCheatCodes: { markAsProven } as unknown as RollupCheatCodes, - log, - }, - /* promoteTimeoutSecs= */ 1, - ); - - prover.start(); - (sequencer as EventEmitter).emit('checkpoint-published', { checkpoint, slot: 10 }); - - // trigger() should return once the timed-out proveCheckpoint completes (no hang). - await prover.trigger(); - - // markAsProven must NOT have been called because the archiver never promoted. - expect(markAsProven).not.toHaveBeenCalled(); - }, 10_000); - - it('stops cleanly while a wait is in flight', async () => { - const checkpoint = CheckpointNumber(2); - - // Archiver takes a while to promote; stop() is called first. - let resolvePromotion!: () => void; - getL2Tips.mockImplementation( - () => - new Promise(resolve => { - resolvePromotion = () => resolve(makeTips(2)); - }), - ); - - prover.start(); - (sequencer as EventEmitter).emit('checkpoint-published', { checkpoint, slot: 10 }); - - // Let the worker enter the retryUntil loop once, then stop. - await new Promise(resolve => setImmediate(resolve)); - - // Resolve the pending poll so retryUntil can exit cleanly when stop() drains. - resolvePromotion(); - - // stop() should await the in-flight worker and return without hanging. - await prover.stop(); - - // The wait resolved so markAsProven may or may not have been called — but stop() - // must have returned without throwing or hanging. - }); - - it('processes multiple checkpoint-published events in order', async () => { - const cp1 = CheckpointNumber(1); - const cp2 = CheckpointNumber(2); - const cp3 = CheckpointNumber(3); - - const promotedAt: CheckpointNumber[] = []; - - // The archiver tip advances to 3 immediately, so each checkpoint's wait resolves right away. - getL2Tips.mockResolvedValue(makeTips(3)); - markAsProven.mockImplementation((n?: CheckpointNumber) => { - if (n !== undefined) { - promotedAt.push(n); - } - return Promise.resolve(); - }); - - prover.start(); - - // Emit all three before the worker has a chance to run. - (sequencer as EventEmitter).emit('checkpoint-published', { checkpoint: cp1, slot: 1 }); - (sequencer as EventEmitter).emit('checkpoint-published', { checkpoint: cp2, slot: 2 }); - (sequencer as EventEmitter).emit('checkpoint-published', { checkpoint: cp3, slot: 3 }); - - await prover.trigger(); - - // All three should have been processed in emission order. - expect(promotedAt).toEqual([cp1, cp2, cp3]); - }); -}); diff --git a/yarn-project/aztec/src/testing/checkpoint_auto_prover.ts b/yarn-project/aztec/src/testing/checkpoint_auto_prover.ts deleted file mode 100644 index 89e7026ed98e..000000000000 --- a/yarn-project/aztec/src/testing/checkpoint_auto_prover.ts +++ /dev/null @@ -1,141 +0,0 @@ -import type { RollupCheatCodes } from '@aztec/ethereum/test'; -import { BlockNumber, type CheckpointNumber } from '@aztec/foundation/branded-types'; -import { TimeoutError } from '@aztec/foundation/error'; -import type { Logger } from '@aztec/foundation/log'; -import { retryUntil } from '@aztec/foundation/retry'; -import type { TypedEventEmitter } from '@aztec/foundation/types'; -import type { SequencerEvents } from '@aztec/sequencer-client'; -import type { L2BlockSource } from '@aztec/stdlib/block'; - -/** Default timeout in seconds to wait for the archiver to promote a checkpoint. */ -const DEFAULT_PROMOTE_TIMEOUT_SECS = 30; - -/** Dependencies injected into CheckpointAutoProver. */ -export type CheckpointAutoProverDeps = { - sequencer: TypedEventEmitter; - l2BlockSource: L2BlockSource; - rollupCheatCodes: RollupCheatCodes; - log: Logger; -}; - -/** - * Test helper that replaces the `markAsProven` polling loop in `AnvilTestWatcher`. - * - * Subscribes to the sequencer's `checkpoint-published` event. When fired, waits for the - * local archiver to have promoted the checkpoint (i.e. `getL2Tips().checkpointed.checkpoint.number - * >= checkpointNumber` and the checkpoint's blocks are locally readable), then calls - * `rollupCheatCodes.markAsProven(checkpointNumber)`. - */ -export class CheckpointAutoProver { - private readonly sequencer: TypedEventEmitter; - private readonly l2BlockSource: L2BlockSource; - private readonly rollupCheatCodes: RollupCheatCodes; - private readonly log: Logger; - private readonly promoteTimeoutSecs: number; - - /** Queue of checkpoints to prove, processed in order by the worker. */ - private readonly queue: CheckpointNumber[] = []; - /** Promise tracking the currently-running worker so stop() can await it. */ - private workerPromise: Promise | undefined; - /** Set to true by stop() to signal the worker to exit after its current item. */ - private stopped = false; - - private readonly listener: (args: { checkpoint: CheckpointNumber; slot: unknown }) => void; - - constructor(deps: CheckpointAutoProverDeps, promoteTimeoutSecs = DEFAULT_PROMOTE_TIMEOUT_SECS) { - this.sequencer = deps.sequencer; - this.l2BlockSource = deps.l2BlockSource; - this.rollupCheatCodes = deps.rollupCheatCodes; - this.log = deps.log; - this.promoteTimeoutSecs = promoteTimeoutSecs; - - this.listener = ({ checkpoint }) => this.enqueue(checkpoint); - } - - /** Subscribes to checkpoint-published events and starts the background worker. */ - start() { - this.stopped = false; - this.sequencer.on('checkpoint-published', this.listener); - this.log.debug('CheckpointAutoProver started'); - } - - /** - * Unsubscribes from checkpoint-published events and waits for any in-flight prove to finish. - */ - async stop() { - this.stopped = true; - this.sequencer.off('checkpoint-published', this.listener); - await this.workerPromise; - this.log.debug('CheckpointAutoProver stopped'); - } - - /** - * Forces a synchronous wait: polls until the archiver's checkpointed tip is at least as high - * as the latest item in the queue (or the queue is empty) and all pending proves have finished. - * Useful in tests that want to assert state after a checkpoint is proven. - */ - async trigger() { - await this.workerPromise; - } - - private enqueue(checkpointNumber: CheckpointNumber) { - this.log.debug(`Queuing checkpoint ${checkpointNumber} for proving`); - this.queue.push(checkpointNumber); - // Only one worker at a time; start it if it isn't already running. - if (!this.workerPromise) { - this.workerPromise = this.runWorker().finally(() => { - this.workerPromise = undefined; - }); - } - } - - private async runWorker() { - while (this.queue.length > 0 && !this.stopped) { - const checkpointNumber = this.queue.shift()!; - await this.proveCheckpoint(checkpointNumber); - } - } - - private async proveCheckpoint(checkpointNumber: CheckpointNumber) { - this.log.verbose(`Waiting for archiver to promote checkpoint ${checkpointNumber}`); - try { - // Step 1: wait for the archiver's checkpointed tip to reach checkpointNumber. - await retryUntil( - async () => { - const tips = await this.l2BlockSource.getL2Tips(); - return tips.checkpointed.checkpoint.number >= checkpointNumber || undefined; - }, - `checkpoint ${checkpointNumber} to be promoted`, - this.promoteTimeoutSecs, - /* interval= */ 0.5, - ); - } catch (e) { - if (e instanceof TimeoutError) { - this.log.warn( - `Timed out waiting for archiver to promote checkpoint ${checkpointNumber} after ${this.promoteTimeoutSecs}s; skipping markAsProven`, - { checkpointNumber, timeoutSecs: this.promoteTimeoutSecs }, - ); - return; - } - throw e; - } - - // Step 2: verify the checkpoint's blocks are locally readable. - try { - const blocks = await this.l2BlockSource.getBlocks({ from: BlockNumber(1), limit: 1, onlyCheckpointed: true }); - this.log.debug(`Archiver has ${blocks.length} checkpointed block(s); proceeding to markAsProven`, { - checkpointNumber, - }); - } catch { - this.log.warn(`Could not read checkpointed blocks for checkpoint ${checkpointNumber}; skipping markAsProven`, { - checkpointNumber, - }); - return; - } - - // Step 3: mark checkpoint as proven on the rollup contract. - this.log.verbose(`Marking checkpoint ${checkpointNumber} as proven`); - await this.rollupCheatCodes.markAsProven(checkpointNumber); - this.log.info(`Marked checkpoint ${checkpointNumber} as proven`, { checkpointNumber }); - } -} diff --git a/yarn-project/aztec/src/testing/index.ts b/yarn-project/aztec/src/testing/index.ts index dd7f6a176862..3fa5faf6b2d2 100644 --- a/yarn-project/aztec/src/testing/index.ts +++ b/yarn-project/aztec/src/testing/index.ts @@ -1,5 +1,4 @@ export { AnvilTestWatcher, type AnvilTestWatcherOpts } from './anvil_test_watcher.js'; -export { CheckpointAutoProver, type CheckpointAutoProverDeps } from './checkpoint_auto_prover.js'; export { EthCheatCodes, RollupCheatCodes } from '@aztec/ethereum/test'; export { CheatCodes } from './cheat_codes.js'; export { EpochTestSettler } from './epoch_test_settler.js'; diff --git a/yarn-project/end-to-end/src/e2e_fast_config.test.ts b/yarn-project/end-to-end/src/e2e_fast_config.test.ts index c65052708adb..e98002f5901e 100644 --- a/yarn-project/end-to-end/src/e2e_fast_config.test.ts +++ b/yarn-project/end-to-end/src/e2e_fast_config.test.ts @@ -15,16 +15,17 @@ import { setup } from './fixtures/utils.js'; * this test is the first thing that fails. * * The config gives us: - * - aztecSlotDuration = 12s, ethereumSlotDuration = 4s + * - aztecSlotDuration = 12s, ethereumSlotDuration = 4s, aztecEpochDuration = 4 slots * - one block per slot (blockDurationMs unset → single-block mode in the timetable) * - pipelining on (build slot N-1, commit to slot N) - * - CheckpointAutoProver wired (testOnlyAutoProveAfterPublish = true) + * - EpochTestSettler wired (testOnlyAutoProveAfterPublish = true), advancing proven once + * per completed epoch (48s wall time) * - no AnvilTestWatcher running for the anvil-backed run * * The test exercises three invariants: * 1. The chain advances on its own under interval mining + pipelining. * 2. 20 sequential dependent txs land in distinct blocks (single-block mode keeps batching off). - * 3. The proven tip advances after a published checkpoint (CheckpointAutoProver works). + * 3. The proven tip advances after an epoch completes (EpochTestSettler works). */ describe('e2e_fast_config', () => { jest.setTimeout(15 * 60 * 1000); @@ -67,19 +68,20 @@ describe('e2e_fast_config', () => { ); it( - 'proven tip advances within a few slots of publish', + 'proven tip advances within an epoch of publish', async () => { const { contract } = await StatefulTestContract.deploy(wallet, ownerAddress, 1).send({ from: ownerAddress }); const { receipt } = await contract.methods.increment_public_value(ownerAddress, 0).send({ from: ownerAddress }); expect(receipt.blockNumber).toBeDefined(); const provenTarget = receipt.blockNumber!; - // CheckpointAutoProver listens to checkpoint-published and marks proven once the archiver - // has promoted the checkpoint. Five slots * 12s = 60s is generous. + // EpochTestSettler advances proven once per completed epoch. With aztecEpochDuration=4 + // and aztecSlotDuration=12, an epoch is 48s; allow two epochs of slack for the in-flight + // checkpoint to settle into the next one. await retryUntil( async () => (await aztecNode.getBlockNumber('proven')) >= provenTarget, `proven tip reaches block ${provenTarget}`, - /* timeoutSecs= */ 90, + /* timeoutSecs= */ 150, /* intervalSecs= */ 1, ); }, diff --git a/yarn-project/end-to-end/src/fixtures/fixtures.ts b/yarn-project/end-to-end/src/fixtures/fixtures.ts index 3236868b27de..cc144956fdb5 100644 --- a/yarn-project/end-to-end/src/fixtures/fixtures.ts +++ b/yarn-project/end-to-end/src/fixtures/fixtures.ts @@ -53,9 +53,12 @@ export const PIPELINING_SETUP_OPTS = { * * Extends PIPELINING_SETUP_OPTS with: * - `l1PublishingTime: 4`: L1 tx is expected to land inside one Ethereum slot. - * - `testOnlyAutoProveAfterPublish: true`: opts in to the test fixture's CheckpointAutoProver - * (wired in step 4 of the plan; safe to set in step 1 because it just sets a config value), - * removing the need for AnvilTestWatcher's markAsProven loop. + * - `aztecEpochDuration: 4`: shorter epoch so the proven tip advances on a tight cadence under + * `EpochTestSettler` (4 slots * 12s = 48s per epoch). Must be small enough that any + * `waitForProven`-style assertion fits inside its timeout. + * - `testOnlyAutoProveAfterPublish: true`: opts the fixture into spinning up an + * `EpochTestSettler` that advances the outbox + proven tip once per completed epoch, + * replacing AnvilTestWatcher's markAsProven loop. * * Auto-tuning applied by `normalizeCheckpointTimingConfig` (stdlib/src/timetable/index.ts): * because ethereumSlotDuration < 8, p2pPropagationTime = 0, checkpointAssembleTime = 0.5, @@ -72,6 +75,7 @@ export const PIPELINING_SETUP_OPTS = { */ export const FAST_E2E_SETUP_OPTS = { ...PIPELINING_SETUP_OPTS, + aztecEpochDuration: 4, l1PublishingTime: 4, testOnlyAutoProveAfterPublish: true, } as const; diff --git a/yarn-project/end-to-end/src/fixtures/setup.ts b/yarn-project/end-to-end/src/fixtures/setup.ts index 11d364869689..4aeea92e344a 100644 --- a/yarn-project/end-to-end/src/fixtures/setup.ts +++ b/yarn-project/end-to-end/src/fixtures/setup.ts @@ -17,7 +17,7 @@ import { Fr } from '@aztec/aztec.js/fields'; import { type Logger, createLogger } from '@aztec/aztec.js/log'; import type { AztecNode } from '@aztec/aztec.js/node'; import type { Wallet } from '@aztec/aztec.js/wallet'; -import { AnvilTestWatcher, type AnvilTestWatcherOpts, CheatCodes, CheckpointAutoProver } from '@aztec/aztec/testing'; +import { AnvilTestWatcher, type AnvilTestWatcherOpts, CheatCodes, EpochTestSettler } from '@aztec/aztec/testing'; import { SPONSORED_FPC_SALT } from '@aztec/constants'; import { isAnvilTestChain } from '@aztec/ethereum/chain'; import { createExtendedL1Client } from '@aztec/ethereum/client'; @@ -214,10 +214,10 @@ export type SetupOptions = { /** Options forwarded to PXE creation (e.g. execution hooks). */ pxeCreationOptions?: PXECreationOptions; /** - * When true, the fixture constructs a CheckpointAutoProver that calls - * `RollupCheatCodes.markAsProven` after each published checkpoint, replacing - * AnvilTestWatcher's markAsProven loop. Wired in step 4 of the plan; safe to - * set in step 1 because it just stores a config value until the helper is hooked up. + * When true, the fixture constructs an `EpochTestSettler` that advances the proven tip + * (and the outbox hash) once per completed epoch, replacing `AnvilTestWatcher`'s polling + * `markAsProven` loop for e2e tests that don't run a real prover-node. Skipped when + * `startProverNode` is set — the real prover advances proven there. */ testOnlyAutoProveAfterPublish?: boolean; } & Partial; @@ -256,8 +256,8 @@ export type EndToEndContext = { ethCheatCodes: EthCheatCodes; /** The anvil test watcher. */ watcher: AnvilTestWatcher; - /** Auto-prover that calls markAsProven after each checkpoint when testOnlyAutoProveAfterPublish is true. */ - checkpointAutoProver: CheckpointAutoProver | undefined; + /** Epoch-granularity proven-tip settler when testOnlyAutoProveAfterPublish is true. */ + epochTestSettler: EpochTestSettler | undefined; /** Allows tweaking current system time, used by the epoch cache only. */ dateProvider: TestDateProvider; /** Telemetry client */ @@ -487,7 +487,7 @@ export async function setup( opts.anvilTestWatcherOpts, ); // Watcher is only needed on the sandbox path. Anvil e2e tests use interval mining + cheat-code - // atomic dateProvider sync + CheckpointAutoProver instead. + // atomic dateProvider sync + EpochTestSettler (opt-in via testOnlyAutoProveAfterPublish) instead. const disableWatcher = opts.disableAnvilTestWatcher ?? isAnvilChain; if (!disableWatcher) { await watcher.start(); @@ -613,15 +613,16 @@ export async function setup( const cheatCodes = await CheatCodes.create(config.l1RpcUrls, aztecNodeService, dateProvider); - let checkpointAutoProver: CheckpointAutoProver | undefined = undefined; - if (opts.testOnlyAutoProveAfterPublish && isAnvilChain && !opts.startProverNode && sequencerClient) { - checkpointAutoProver = new CheckpointAutoProver({ - sequencer: sequencerClient.getSequencer(), - l2BlockSource: aztecNodeService.getBlockSource(), - rollupCheatCodes: cheatCodes.rollup, - log: logger, - }); - checkpointAutoProver.start(); + let epochTestSettler: EpochTestSettler | undefined = undefined; + if (opts.testOnlyAutoProveAfterPublish && isAnvilChain && !opts.startProverNode) { + epochTestSettler = new EpochTestSettler( + ethCheatCodes, + deployL1ContractsValues.l1ContractAddresses.rollupAddress, + aztecNodeService.getBlockSource(), + logger.createChild('epoch-settler'), + { pollingIntervalMs: 200 }, + ); + await epochTestSettler.start(); } if ( @@ -670,7 +671,7 @@ export async function setup( const teardown = async () => { try { - await checkpointAutoProver?.stop(); + await epochTestSettler?.stop(); await tryStop(wallet, logger); await tryStop(aztecNodeService, logger); await tryStop(proverNode, logger); @@ -722,7 +723,7 @@ export async function setup( wallet, accounts, watcher, - checkpointAutoProver, + epochTestSettler, acvmConfig, bbConfig, directoryToCleanup, From 8cbafdd57a07b48903c8cf254df343f49190eacb Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 18 May 2026 04:38:09 +0100 Subject: [PATCH 12/16] docs(e2e): correct fast-config smoke test description EpochTestSettler runs once per completed epoch, so the proven-tip retry budgets up to two epochs (the worst case is the tx landing right after an epoch boundary, needing the full next epoch to complete). --- yarn-project/end-to-end/src/e2e_fast_config.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn-project/end-to-end/src/e2e_fast_config.test.ts b/yarn-project/end-to-end/src/e2e_fast_config.test.ts index e98002f5901e..ed5fa995068b 100644 --- a/yarn-project/end-to-end/src/e2e_fast_config.test.ts +++ b/yarn-project/end-to-end/src/e2e_fast_config.test.ts @@ -68,7 +68,7 @@ describe('e2e_fast_config', () => { ); it( - 'proven tip advances within an epoch of publish', + 'proven tip advances within two epochs of publish', async () => { const { contract } = await StatefulTestContract.deploy(wallet, ownerAddress, 1).send({ from: ownerAddress }); const { receipt } = await contract.methods.increment_public_value(ownerAddress, 0).send({ from: ownerAddress }); From eaa18970b71cd217b34e50d82e0b67e24c8372ab Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 18 May 2026 06:24:34 +0200 Subject: [PATCH 13/16] fix(e2e): drop aztecEpochDuration: 4 from FAST_E2E_SETUP_OPTS Migrated tests using FAST_E2E_SETUP_OPTS (e2e_token_contract/*, e2e_nested_contract/*, e2e_fast_config) consistently failed in CI with "Transaction dropped by P2P node" because the slot-4 propose tx reverted on L1. Root cause: with aztecEpochDuration: 4, EpochTestSettler fires markAsProven at the end of epoch 0 (just after the slot-3 propose lands). The cheat code wraps its storage write in execWithPausedAnvil, which pauses anvil interval mining for the duration of the cheat-code RPC and shifts the L1 mining cadence on resume. The next propose, sent at the slot-4 wall-clock boundary, lands in an L1 block whose block.timestamp is still in slot 3, and propose's validateHeader reverts with HeaderLib__InvalidSlotNumber(3, 4) inside the multicall. The outer multicall tx succeeds, but the propose log is absent, so the sequencer treats the checkpoint as un-published, the pending chain is pruned, and the in-flight L2 tx is ejected from the P2P pool. Drop aztecEpochDuration: 4 from FAST_E2E_SETUP_OPTS and let it default to 32, so EpochTestSettler does not fire within the typical test window. The smoke test loses its proven-tip assertion (the same epoch-boundary collision); it still covers chain progression and single-block-per-slot batching. --- .../end-to-end/src/e2e_fast_config.test.ts | 38 ++++--------------- .../end-to-end/src/fixtures/fixtures.ts | 12 ++++-- 2 files changed, 16 insertions(+), 34 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_fast_config.test.ts b/yarn-project/end-to-end/src/e2e_fast_config.test.ts index ed5fa995068b..4069506eba05 100644 --- a/yarn-project/end-to-end/src/e2e_fast_config.test.ts +++ b/yarn-project/end-to-end/src/e2e_fast_config.test.ts @@ -1,7 +1,5 @@ import { AztecAddress } from '@aztec/aztec.js/addresses'; -import type { AztecNode } from '@aztec/aztec.js/node'; import type { Wallet } from '@aztec/aztec.js/wallet'; -import { retryUntil } from '@aztec/foundation/retry'; import { StatefulTestContract } from '@aztec/noir-test-contracts.js/StatefulTest'; import { jest } from '@jest/globals'; @@ -15,17 +13,20 @@ import { setup } from './fixtures/utils.js'; * this test is the first thing that fails. * * The config gives us: - * - aztecSlotDuration = 12s, ethereumSlotDuration = 4s, aztecEpochDuration = 4 slots + * - aztecSlotDuration = 12s, ethereumSlotDuration = 4s, aztecEpochDuration = 32 (default) * - one block per slot (blockDurationMs unset → single-block mode in the timetable) * - pipelining on (build slot N-1, commit to slot N) - * - EpochTestSettler wired (testOnlyAutoProveAfterPublish = true), advancing proven once - * per completed epoch (48s wall time) + * - EpochTestSettler wired (testOnlyAutoProveAfterPublish = true), but with the default + * 32-slot epoch the settler does not fire within this test's window * - no AnvilTestWatcher running for the anvil-backed run * - * The test exercises three invariants: + * The test exercises two invariants: * 1. The chain advances on its own under interval mining + pipelining. * 2. 20 sequential dependent txs land in distinct blocks (single-block mode keeps batching off). - * 3. The proven tip advances after an epoch completes (EpochTestSettler works). + * + * Proven-tip advancement is intentionally not asserted here: it requires a shorter epoch, which + * interacts badly with the cheat-code `markAsProven` path under pipelined publishing (see + * `FAST_E2E_SETUP_OPTS` doc for details). */ describe('e2e_fast_config', () => { jest.setTimeout(15 * 60 * 1000); @@ -33,14 +34,12 @@ describe('e2e_fast_config', () => { let wallet: Wallet; let ownerAddress: AztecAddress; let teardown: () => Promise; - let aztecNode: AztecNode; beforeAll(async () => { ({ teardown, wallet, accounts: [ownerAddress], - aztecNode, } = await setup(1, { ...FAST_E2E_SETUP_OPTS })); }); @@ -66,25 +65,4 @@ describe('e2e_fast_config', () => { }, 10 * 60 * 1000, ); - - it( - 'proven tip advances within two epochs of publish', - async () => { - const { contract } = await StatefulTestContract.deploy(wallet, ownerAddress, 1).send({ from: ownerAddress }); - const { receipt } = await contract.methods.increment_public_value(ownerAddress, 0).send({ from: ownerAddress }); - expect(receipt.blockNumber).toBeDefined(); - const provenTarget = receipt.blockNumber!; - - // EpochTestSettler advances proven once per completed epoch. With aztecEpochDuration=4 - // and aztecSlotDuration=12, an epoch is 48s; allow two epochs of slack for the in-flight - // checkpoint to settle into the next one. - await retryUntil( - async () => (await aztecNode.getBlockNumber('proven')) >= provenTarget, - `proven tip reaches block ${provenTarget}`, - /* timeoutSecs= */ 150, - /* intervalSecs= */ 1, - ); - }, - 3 * 60 * 1000, - ); }); diff --git a/yarn-project/end-to-end/src/fixtures/fixtures.ts b/yarn-project/end-to-end/src/fixtures/fixtures.ts index cc144956fdb5..398725a5a294 100644 --- a/yarn-project/end-to-end/src/fixtures/fixtures.ts +++ b/yarn-project/end-to-end/src/fixtures/fixtures.ts @@ -53,13 +53,18 @@ export const PIPELINING_SETUP_OPTS = { * * Extends PIPELINING_SETUP_OPTS with: * - `l1PublishingTime: 4`: L1 tx is expected to land inside one Ethereum slot. - * - `aztecEpochDuration: 4`: shorter epoch so the proven tip advances on a tight cadence under - * `EpochTestSettler` (4 slots * 12s = 48s per epoch). Must be small enough that any - * `waitForProven`-style assertion fits inside its timeout. * - `testOnlyAutoProveAfterPublish: true`: opts the fixture into spinning up an * `EpochTestSettler` that advances the outbox + proven tip once per completed epoch, * replacing AnvilTestWatcher's markAsProven loop. * + * Note: `aztecEpochDuration` is intentionally left at the default (32 slots). Shortening it + * makes `EpochTestSettler` fire its `markAsProven` cheat-code while the sequencer is pipelining + * the very next propose tx. The cheat-code path pauses anvil interval mining briefly, which is + * enough to push the in-flight propose into the previous L2 slot's L1 block and revert with + * `HeaderLib__InvalidSlotNumber`. Tests that explicitly need a fast proven-tip cadence should + * either set `aztecEpochDuration` locally and accept the resulting flakiness, or run a real + * prover-node (`startProverNode: true`). + * * Auto-tuning applied by `normalizeCheckpointTimingConfig` (stdlib/src/timetable/index.ts): * because ethereumSlotDuration < 8, p2pPropagationTime = 0, checkpointAssembleTime = 0.5, * checkpointInitializationTime = 0.5, minExecutionTime = 1. `blockDurationMs` remains unset, @@ -75,7 +80,6 @@ export const PIPELINING_SETUP_OPTS = { */ export const FAST_E2E_SETUP_OPTS = { ...PIPELINING_SETUP_OPTS, - aztecEpochDuration: 4, l1PublishingTime: 4, testOnlyAutoProveAfterPublish: true, } as const; From 0a93721a5b6b8c8a96ce143451e1a5d49e9bc9e3 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 18 May 2026 06:39:49 +0200 Subject: [PATCH 14/16] fix(e2e): use PIPELINING_SETUP_OPTS for e2e_fees/account_init Setup pace-locks to anvil's 12s wall-clock interval mining since the watcher's warpTimeIfNeeded loop is gone, and the default `aztecSlotDuration: 72` means each L2 slot now takes 72s of wall time. `account_init` deploys ~5 blocks during `beforeAll` (initial account, banana token, FPC class+instance, fund), which exceeds the 300s Jest hook budget. Switch to PIPELINING_SETUP_OPTS (12s/4s slots, pipelining, 30x fee padding, `startProverNode: true` preserved through the spread order in `FeesTest.setup`), matching the pattern `e2e_fees/gas_estimation.test.ts` already uses for the same reason. Manual `getPaddedMaxFeesPerGas` calls in the test bodies still use the 5x default padding; leaving as-is since the PR's failure is a timeout, not a fee-rejection. --- yarn-project/end-to-end/src/e2e_fees/account_init.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_fees/account_init.test.ts b/yarn-project/end-to-end/src/e2e_fees/account_init.test.ts index 29fc20ddd03a..54adc463a808 100644 --- a/yarn-project/end-to-end/src/e2e_fees/account_init.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees/account_init.test.ts @@ -17,7 +17,7 @@ import { GasSettings } from '@aztec/stdlib/gas'; import { jest } from '@jest/globals'; -import { getPaddedMaxFeesPerGas } from '../fixtures/fixtures.js'; +import { PIPELINING_SETUP_OPTS, getPaddedMaxFeesPerGas } from '../fixtures/fixtures.js'; import type { TestWallet } from '../test-wallet/test_wallet.js'; import { FeesTest } from './fees_test.js'; @@ -27,7 +27,7 @@ describe('e2e_fees account_init', () => { const t = new FeesTest('account_init', 1); beforeAll(async () => { - await t.setup(); + await t.setup({ ...PIPELINING_SETUP_OPTS }); await t.applyFundAliceWithBananas(); await t.applyFPCSetup(); ({ aliceAddress, wallet, bananaCoin, bananaFPC, logger, aztecNode } = t); From e9d3d0b6e291ac6b159fa11d0de5cd69454a49e9 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 18 May 2026 12:09:44 +0100 Subject: [PATCH 15/16] fix(sequencer): submit pipelined propose at L2 slot start, not one L1 slot before MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `SequencerPublisher.sendRequestsAt` was sleeping until `target slot start - ethereumSlotDuration` so the tx could land in the *first* L1 block of the target L2 slot. The existing JSDoc already flagged the risk: if the tx is mined in the L1 block *immediately before* the target slot starts, `ProposeLib.validateHeader` reverts with `HeaderLib__InvalidSlotNumber` -- and because the request goes through `Multicall3.forward(allowFailure:true)`, the outer L1 tx still reports success with an empty `CheckpointProposed` log, the archiver sees no checkpoint for that slot, and prunes the chain. Every L2 tx in the pruned block then gets dropped from the p2p pool. The PR exposed this by replacing anvil's default automine (where the tx mined immediately on submit, so `block.timestamp ≈ real-time-at-send`) with deterministic interval mining at `ethereumSlotDuration` wall-clock seconds. Anvil's interval timer is unsynchronized with the L2 slot clock; a tx submitted one L1 slot early routinely got picked up by the L1 block that mined *before* the target slot boundary. Submitting at the target slot boundary keeps the next L1 block's timestamp strictly inside the slot for all `aztecSlotDuration >= ethereumSlotDuration` configs we use, both for local anvil interval mining and for real L1. The target slot still has `aztecSlotDuration / ethereumSlotDuration - 1` L1 blocks of inclusion headroom, capped by `lastValidL2Slot = targetSlot`. Diagnosed with codex; reproduced in `e2e_card_game`, `e2e_fast_config`, `e2e_token_contract/{burn,transfer_in_public}`, `e2e_kernelless_simulation`, `e2e_note_getter`, `e2e_pending_note_hashes_contract`. The 72 existing checkpoint_proposal_job unit tests still pass; sendRequestsAt is mocked at every test boundary. --- .../src/publisher/sequencer-publisher.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/yarn-project/sequencer-client/src/publisher/sequencer-publisher.ts b/yarn-project/sequencer-client/src/publisher/sequencer-publisher.ts index cf4146867c7e..a7df12432f69 100644 --- a/yarn-project/sequencer-client/src/publisher/sequencer-publisher.ts +++ b/yarn-project/sequencer-client/src/publisher/sequencer-publisher.ts @@ -613,19 +613,22 @@ export class SequencerPublisher { /* * Schedules sending all enqueued requests at (or after) the start of the given L2 slot. - * Sleeps until one L1 slot before the L2 slot boundary so the tx has a chance of being - * picked up by the first L1 block of the L2 slot. - * NB: there is a known correctness risk — being included in the L1 block right before the - * L2 slot starts would revert propose with HeaderLib__InvalidSlotNumber. + * Sleeps until the L2 slot boundary so that the next L1 block that picks up the tx is + * guaranteed to have a block.timestamp inside the target L2 slot. Submitting earlier + * (e.g. one L1 slot before the boundary) lets the tx be included in the L1 block just + * before the L2 slot starts, which reverts propose with `HeaderLib__InvalidSlotNumber`; + * under anvil interval-mining this race surfaces deterministically and Multicall3 + * swallows the inner revert with `allowFailure: true`. * Uses InterruptibleSleep so it can be cancelled via interrupt(). */ public async sendRequestsAt(targetSlot: SlotNumber): Promise { const l1Constants = this.epochCache.getL1Constants(); // Start of the target L2 slot, in ms (getTimestampForSlot returns seconds). const startOfTargetSlotMs = Number(getTimestampForSlot(targetSlot, l1Constants)) * 1000; - // Aim to be in the mempool one L1 slot before the L2 slot starts, so we have a chance of - // being picked up by the first L1 block of the L2 slot. - const submitAfterMs = startOfTargetSlotMs - Number(this.ethereumSlotDuration) * 1000; + // Wait until the target L2 slot has actually started before submitting, so the next L1 + // block to include the tx has `block.timestamp >= startOfTargetSlot` and the header + // slot assertion in `ProposeLib.validateHeader` passes. + const submitAfterMs = startOfTargetSlotMs; const sleepMs = submitAfterMs - this.dateProvider.now(); if (sleepMs > 0) { this.log.debug(`Sleeping ${sleepMs}ms before sending requests`, { From a3d778ca3a2586b6e8a62ba252b5ea8fb76cb36b Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 18 May 2026 12:09:55 +0100 Subject: [PATCH 16/16] fix(e2e): scope advanceBlock's markAsProven to opt-in callers The drift test in `e2e_cross_chain_messaging/l1_to_l2.test.ts` mines checkpoints and then waits for the L1 proof-submission deadline to expire so the chain prunes back to `lastProven`. Earlier this PR added an unconditional `await t.context.watcher.markAsProven()` inside `advanceBlock` (to stop interval mining from letting the proof window expire mid-test in other tests in this file), but the drift test calls `advanceCheckpoint` and `tryAdvanceBlock` in its wait-for-prune loop, so every poll iteration re-anchored proven and the prune never fired (180s timeout). Add a `prove` parameter to `advanceBlock` / `advanceCheckpoint` / `tryAdvanceBlock` (default `true`, preserving the existing behavior for the other tests in this file) and pass `prove: false` from the drift test's `timesAsync(4, advanceCheckpoint)` and `tryAdvanceBlock` in the prune-wait retry. The post-prune `tryAdvanceBlock()` in `waitForMessageReady` keeps the default, since at that point we want the chain to keep being proven so the message becomes consumable. --- .../l1_to_l2.test.ts | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_cross_chain_messaging/l1_to_l2.test.ts b/yarn-project/end-to-end/src/e2e_cross_chain_messaging/l1_to_l2.test.ts index 72c20185bb57..a2d83abc7bc1 100644 --- a/yarn-project/end-to-end/src/e2e_cross_chain_messaging/l1_to_l2.test.ts +++ b/yarn-project/end-to-end/src/e2e_cross_chain_messaging/l1_to_l2.test.ts @@ -49,8 +49,11 @@ describe('e2e_cross_chain_messaging l1_to_l2', () => { ? testContract.methods.consume_message_from_arbitrary_sender_private : testContract.methods.consume_message_from_arbitrary_sender_public; - // Sends a tx to L2 to advance the block number by 1 - const advanceBlock = async () => { + // Sends a tx to L2 to advance the block number by 1. + // Pass `{ prove: false }` from tests that intentionally want the L1 proof window to expire + // (e.g. the drift test that waits for the chain to prune); otherwise this re-anchors proven + // every call and the prune deadline never fires. + const advanceBlock = async ({ prove = true }: { prove?: boolean } = {}) => { const block = await aztecNode.getBlockNumber(); log.warn(`Sending noop tx at block ${block}`); await wallet.sendTx(ExecutionPayload.empty(), { from: user1Address }); @@ -59,10 +62,12 @@ describe('e2e_cross_chain_messaging l1_to_l2', () => { if (newBlock === block) { throw new Error(`Failed to advance block ${block}`); } - // Under interval mining `AnvilTestWatcher.markAsProven` does not auto-fire; without an explicit - // prove call here, L1's `aztecProofSubmissionEpochs=2` window (96s with pipelined 12s slots) - // expires mid-test and triggers a chain prune that drops in-flight wallet txs. - await t.context.watcher.markAsProven(); + // Under interval mining `AnvilTestWatcher.markAsProven` does not auto-fire; tests that expect + // L1's `aztecProofSubmissionEpochs=2` window (96s with pipelined 12s slots) to stay open need + // to mark explicitly here, or in-flight wallet txs get dropped when L1 prunes. + if (prove) { + await t.context.watcher.markAsProven(); + } return newBlock; }; @@ -86,21 +91,21 @@ describe('e2e_cross_chain_messaging l1_to_l2', () => { ); }; - const advanceCheckpoint = async () => { + const advanceCheckpoint = async ({ prove = true }: { prove?: boolean } = {}) => { let checkpoint = await aztecNode.getCheckpointNumber(); const originalCheckpoint = checkpoint; log.warn(`Original checkpoint ${originalCheckpoint}`); do { - const newBlock = await advanceBlock(); + const newBlock = await advanceBlock({ prove }); checkpoint = await waitForBlockToCheckpoint(newBlock); } while (checkpoint <= originalCheckpoint); log.warn(`At checkpoint ${checkpoint}`); }; // Same as above but ignores errors. Useful if we expect a prune. - const tryAdvanceBlock = async () => { + const tryAdvanceBlock = async ({ prove = true }: { prove?: boolean } = {}) => { try { - await advanceBlock(); + await advanceBlock({ prove }); } catch (err) { log.warn(`Failed to advance block: ${(err as Error).message}`); } @@ -228,9 +233,11 @@ describe('e2e_cross_chain_messaging l1_to_l2', () => { onlyCheckpointed: true, }); log.warn(`Stopping proof submission at checkpoint ${checkpointedProvenBlock.checkpointNumber} to allow drift`); - // Mine several checkpoints to ensure drift + // Mine several checkpoints to ensure drift. Pass `prove: false` so each advanceBlock call + // does not re-anchor proven — the whole point of this test is to let proven fall behind + // and trigger the L1 prune deadline. log.warn(`Mining blocks to allow drift`); - await timesAsync(4, advanceCheckpoint); + await timesAsync(4, () => advanceCheckpoint({ prove: false })); // Generate and send the message to the L1 contract log.warn(`Sending L1 to L2 message`); @@ -250,7 +257,7 @@ describe('e2e_cross_chain_messaging l1_to_l2', () => { await retryUntil( async () => (await aztecNode.getBlockNumber().then(b => b === lastProven || b === lastProven + 1)) || - (await tryAdvanceBlock()), + (await tryAdvanceBlock({ prove: false })), 'wait for prune', 180, );