Skip to content

test(e2e): speed up individual e2e tests - #24345

Merged
PhilWindle merged 66 commits into
merge-train/spartan-v5from
spl/e2e-speed-up-1
Jun 30, 2026
Merged

test(e2e): speed up individual e2e tests#24345
PhilWindle merged 66 commits into
merge-train/spartan-v5from
spl/e2e-speed-up-1

Conversation

@spalladino

@spalladino spalladino commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Speeds up the slowest individual e2e tests. Shared clock-warp helpers (warpToEpochStart, warpNearSubmissionWindowEnd) were also lifted into single_node_test_context.ts. Further production and shared-fixture speedup opportunities found along the way are catalogued for a follow-up PR.

Measured speedup

From full instrumented CI runs (per-test timing JSONL), comparing this PR's green run (40b792f7, CI 1782821707760521) against the nearest healthy baseline on the same post-consolidation merge-train era (bab9650f / #24378). Timings are sums across parallel CI processes, not wall-clock.

  • Across the 24 changed suites: −38.8% total time (11,002s → 6,735s, ≈71 min of summed process time saved per run), −38.7% body. Every changed suite got faster.
  • Whole e2e suite (~630 tests): −20.1% overall (8h 44m → 6h 59m), −21.1% body — the changed suites account for ~85% of the total body reduction; the rest is run-to-run noise across unchanged tests.

Biggest wins (total time, base → PR):

Suite Base PR Δ
proof_boundary.parallel 2535s 1333s −1202s (−47%)
multiple_validators_sentinel.parallel 617s 123s −495s (−80%)*
optimistic.parallel 2249s 1775s −474s (−21%)
world_state_pruning 350s 113s −236s (−68%)
publisher_funding_multi 253s 17s −236s (−93%)
escape_hatch_vote_only 260s 89s −170s (−66%)
sync_after_reorg 339s 182s −156s (−46%)
sentinel_status_slash.parallel 306s 165s −140s (−46%)
upload_failed_proof 187s 67s −120s (−64%)
long_proving_time 390s 270s −119s (−31%)

…and 14 more suites, all faster (full per-suite table in the Linear "Times tracking" doc).

*multiple_validators_sentinel merged two overlapping attestation tests into one (no coverage lost).

Strategies used

  • Clock warping — fast-forward cheat-clock waits (proof-submission windows, epoch/proven-checkpoint tails, dead slots) instead of sleeping in real time.
  • Slot-cadence cut — shrink L1/L2 slot durations (down to the 4s/12s floor) for single-node prover tests that march through empty checkpoints in real wall-clock.
  • Shared setup — collapse per-it beforeEach setups into a single beforeAll where the tests are independent.
  • Drive the chain directly — replace real-time tx-confirmation waits with NO_WAIT send + advanceToSlot, and trim redundant tx counts.

A handful of speedups were reverted or tuned after CI showed they raced the production sequencer (warp loops) or broke fresh-per-test state; those are catalogued for the follow-up PR, along with a production prover-shutdown defect found in passing.

Tests changed

Single-node

  • proving: multi_proof, optimistic, proof_fails, world_state_pruning, cross_chain_public_message, long_proving_time, upload_failed_proof
  • partial-proofs: multi_root, single_root
  • recovery: manual_rollback, prune_when_cannot_build, sync_after_reorg
  • l1-reorgs: blocks
  • sequencer: escape_hatch_vote_only, publisher_funding_multi

Multi-node

  • block-production: blob_promotion, proof_boundary
  • governance: add_rollup
  • slashing: multiple_validators_sentinel, sentinel_status_slash

p2p

  • gossip_network, fee_asset_price_oracle_gossip, late_prover_tx_collection

automine

  • ordering

Speedups to empty_blocks, block_building, account_init, messages, l1_to_l2, and l2_to_l1 were reverted to baseline after CI flagged instability, and are left for the follow-up PR.

@spalladino spalladino added S-do-not-merge Status: Do not merge this PR ci-no-fail-fast Sets NO_FAIL_FAST in the CI so the run is not aborted on the first failure labels Jun 26, 2026
@spalladino
spalladino force-pushed the spl/e2e-speed-up-1 branch 2 times, most recently from 62c4bde to 76070f2 Compare June 29, 2026 13:10
Each of the 5 its spent ~432s (83% of ~511s) in a single wall-clock wait advancing
12 L2 slots at 36s each. Warp the L1 clock over the dead slots to the build window of
slot N-1, leaving the boundary neighbourhood (N-1..N+2) to build in real time so the
proof-landing and prune assertions stay valid. Est. ~310s saved per it (~1,550s off
the file's CI total).
Cut aztecSlotDuration 36->24 (ethereumSlotDuration 8->4, blockDurationMs 6000->4000):
every wait in the file is bound to the slot duration, so all bodies scale ~0.667x.
Merge the three single-attack signature/ordering scenarios (high-s, unrecoverable,
shuffled) into one it that pays the ~20s multi-node setup once instead of 3x, stopping
sequencers between scenarios since Sequencer.start() is not idempotent. Trim a trailing
checkpoint check from +3 to +2. Est. ~32% (~616s) off the file's CI total.
Each it in this .parallel file runs as a separate CI job re-paying the ~100-130s
cross-chain setup. Merge the private/public scope pairs into one it each (non-registered
portal; inbox drift) so the setup is paid 2x instead of 4x. Both scope drivers are
self-anchoring with freshly randomized message content, so they don't interfere on the
shared chain. Est. ~234s (~18%) off the file's CI cost. Warp is not usable here: the
production sequencer needs real wall-clock to build each block.
Bodies are ~78% wall-clock waiting for an epoch to end so the optimistic (fake) proof
can land. Add a local warpToEpochStart(epoch, leadSlots=1) helper that warps the L1
clock to ~1 slot before the boundary (the shared TestDateProvider means the prover
sees the warp too, so proving completes right after), and replace 7 epoch-end
waitUntilEpochStarts calls with it. Guard the two happy-path warps on the prover
registering its sub-tree so the optimistic-proving-start sampler isn't raced. For the
last-slot reorg it, warp to the build window two slots before the epoch end. Est. ~614s
(~28%) off the file's CI total.
The two reorg its that wait out a full proof-submission window (prunes/restores L2
blocks on L1 reorg) spend ~130-140s sleeping while the chain idles at the L1 cadence.
Add warpNearSubmissionWindowEnd(epoch) that warps the L1 clock to ~2 slots before the
window's last slot before waitUntilLastSlotOfProofSubmissionWindow, leaving real slots
for prune/recovery. The 'restores' it first waits in real time for the cancelled proof
tx to be captured, then warps. The other 3 its are genuine build/prove work and are
left untouched. Est. ~129s off the file's CI total.
Nearly all wall-clock in this single-node prod-sequencer file is L2-slot pacing (warp
can't skip the build window). Add FAST_BLOCK_BUILDING_OPTS (aztecSlotDuration 12->8,
blockDurationMs 3000->1500) on top of PIPELINING_SETUP_OPTS and route all 7
setupBlockProducer call sites through it. blockDurationMs=1500 keeps 2 blocks/checkpoint
at S=8 (floor((8-2.5-1.5)/1.5)=2). Adjust the timetable test's BLOCK_DURATION_MS and the
multi-txs afterEach reset to 1500 so they don't throw at the smaller slot. All 19 its and
the downstream AVM-input dump coverage preserved. Est. ~200s (~29%) off the file.
Each it spends ~73% of its body waiting (sequencers idle) for the epoch holding the
multi-block checkpoint to close on L1 before its proof can be submitted
(aztecProofSubmissionEpochs:1), ~190s of dead interval-mining at the 72s/12s wide-slot
cadence. Add warpToProofSubmissionEpoch() that stops the sequencers then warps the L1
clock to one block before the start of checkpointEpoch+proofSubmissionEpochs, before each
waitForProvenCheckpoint. Block production and the A-914 wide-slot timing are untouched.
Est. proven-tail ~215s->~30s per it (~370s off the file, 2 CI jobs).
The L2->L1 it stops building once its assertions pass, then idles ~116s waiting for the
epoch holding the multi-block checkpoint to seal before its (single-unit) epoch proof can
be submitted. Add warpPastEpochTailAndWaitForProven() that stops sequencers and warps the
L1 clock to the next epoch start before waitForProvenCheckpoint. The L1->L2 it keeps
building past the boundary so its proving already overlaps — left unchanged. Est. ~116s
(~20%) off the file.
The ~528s body is bounded by a real-wall-clock prover delay (a sleep in the fake prover,
not the date provider) serialized across one agent, so warp is useless. Pass
ethereumSlotDuration:4 + aztecSlotDurationInL1Slots:2 (L1 12s->4s, L2 24s->8s) to
getSlotDurations and setupWithProver. proverTestDelayMs is slot-derived so it shrinks
together with the build cadence, keeping the delay-to-slot ratio and the 'proving lags
block production by ~3 epochs' / maxJobCount assertions intact. Est. ~352s (~3x) off.
Both its wait out dead inter-epoch advances before their at-deadline assertions. Add a
warpToEpochStart(epoch, leadSlots) helper (forward-only, 2-slot lead) and use it for the
epoch boundaries. IT1: warp the epoch-0 and epoch-1 advances; the held prover tx
(pauseNextTxUntilTimestamp) and the post-deadline prune still settle in real time. IT2:
keep epoch-0 real (the prover needs real block production to engage), gate the warp on a
proveSleepStarted promise so the prover is provably mid-prove before jumping, and cut the
mocked-prove sleep from 9 to 5 slots so it outlasts the warped gap. Est. ~171s (~32%) off.
Body is real per-slot attestation production (warp N/A), and scales ~linearly with slot
duration. Cut ethereumSlotDuration 8->4, aztecSlotDuration 36->8, blockDurationMs
6000->2000 to match the passing sibling validators_sentinel.parallel (same sentinel
assertions, 6 validators); eth<8 also enables the fast operational budgets. Merge the 2
its into one CI job (phase 1 both nodes online, phase 2 stops node[1] and self-anchors on
a fresh slot window) so the ~19s cluster setup is paid once. Est. ~76% (~420s) off.
The 3-epoch loop spends ~77% of its body advancing one empty checkpoint per slot in real
time just to end each epoch so its fake proof can land. Add a local warpToEpochStart
(leadSlots=2) and use it in place of waitUntilEpochStarts(epoch+1). Assertions derive from
whatever checkpoint the epoch reaches and pruning is relative to cumulative block growth,
so a shorter epoch doesn't change what's verified. Est. ~157s (~37% of body) off.
The body is paced by cross-chain bridging checkpoint production (~175s at one checkpoint
per slot); the governance voting/execution windows are already warped. Override
GOVERNANCE_TIMING's 12s L2 slot to 8s (ethereumSlotDuration stays 4s, fast-profile budgets,
the eth4/aztec8 profile the sentinel siblings use with 4+ validators) to scale the bridging
waits down ~33%. Replace the coarse while(true)+48s-sleep vote-quorum loop (which overshot)
with a per-slot retryUntil poll, resolving the file's REFACTOR marker. Est. ~70-85s off.
The single it pays a ~143s dead proven-checkpoint tail (~47% of body): after the
deploy+call are checkpointed, the proof can only be submitted once the next epoch begins
(aztecProofSubmissionEpochs:1), ~12 L1 blocks of empty 72s-slot interval-mining away. Reuse
the sibling proposed_chain warpToProofSubmissionEpoch helper (stop sequencers, warp L1 to
checkpointEpoch+proofSubmissionEpochs start) before waitForProvenCheckpoint. Block
production and assertions untouched. Est. ~113s (~37%) off.
Body is real per-slot attestation production (warp N/A), scaling ~linearly with slot
duration. The ETHEREUM_SLOT_DURATION = process.env.CI ? 8 : 4 guard silently ran CI on the
slow eth=8/aztec=16 path; set it unconditionally to 4 (aztecSlot 16->8, blockMs 4000->2000)
to match the proven validators_sentinel/multiple_validators_sentinel profile. proofSubEpochs
=1024 disables proving deadlines and assertions are sentinel-only, so the fast profile is
safe. All retryUntil timeouts are slot-derived and auto-scale. Est. ~43% (~138s) off.
Both its are real production-sequencer block-building on interval mining (warp N/A). Halve
slot durations 8/16 -> 4/8 (FAST_REORG cadence, ratio preserved); all timeouts and the
setupVotingRound warp offset are slot-derived and auto-scale. eth<8 fast-profile budgets
still fit one checkpoint per 8s slot. Also replace TestContract.deploy with
registerTestContract: the test only calls the private entrypoint
(create_l2_to_l1_message_arbitrary_recipient_private), which needs no on-chain bytecode, so
the deploy tx (~one epoch of interval-mined blocks in setup) is removed. No proving/reorg
deadlines (proofSubmissionEpochs:128, no prover), so assertions are unaffected. Est. ~55% off.
The public l1-to-l2 claim tx lands early in its epoch, then the test waits out the full dead
remainder-of-epoch (~120s) for the fake proof to become submittable. Add a local
warpToEpochStart helper (optimistic.parallel pattern) and warp the L1 clock to 2 slots before
txEpoch+proofSubmissionEpochs's start before waitForProvenBlock; the claim-tx production stays
real time. Est. ~93s (~32%) off.
The test floods txs then waitForTx(all), but only asserts the first CHECKPOINTS_TO_CHECK (3)
checkpoints build without errors. It sent an extra checkpoint+buffer (32 txs), spilling into
checkpoints 4-5 that cost ~72s of unchecked real block production (waitForTx blocks on the
last tx). Send exactly 3 checkpoints' worth (24 txs); the lead-time wait makes the first
checkpoint fully reachable and each checked checkpoint tolerates being one block short. No
warpable tail (real prod-sequencer wall-clock). Est. ~81s (~30%) off.
The test spreads PIPELINING_SETUP_OPTS (eth=4s/aztec=12s) but then overrode the slots back
up to eth=12s/aztec=36s with no assertion-level rationale (introduced in a pure relocation
refactor). The body is a live production sequencer casting one governance vote per slot in
real wall-clock (warp useless), and all assertions are slot-count based with the escape-hatch
open/closed math being pure epoch arithmetic, invariant to slot duration. No proving deadline
(proofSubmissionEpochs=15). Drop the override (eth=4/aztec=12/blockDurationMs=3000) for ~3x
faster per-slot voting. Est. ~60% (~167s) off.
Each it in this .parallel file is a separate CI job re-paying the ~138s cross-chain harness
setup (token/portal/bridge deploy + warm-up), and advanceToEpochProven already warps the
proven tail so the bodies have no warpable dead time. With 6 its that setup is paid ~6x.
Merge the 5 message-tree scenarios into one it (each former body now a self-documented
phase function called back-to-back with scope-labeled logs; assertions preserved verbatim),
keeping only the deep-reorg it separate. 6 CI jobs -> 2. Est. ~540s of CI compute removed.
The ~472s run is ~100% real-interval-mined block production (1 tx -> 1 block -> wait one
real 12s L2 slot; zero idle gaps). Swap PIPELINING_SETUP_OPTS -> AUTOMINE_E2E_OPTS
(AutomineSequencer mines one block per tx synchronously) to remove the per-tx slot latency.
This suite only asserts gas/banana balances and tx fees (no coinbase/prover-fee/proven-chain
assertions), so automine is safe; grounded in the passing client_flows_benchmark precedent
using the same bridge+claim+account-deploy flow. Lower the timeout 15->10 min.
After building 5 checkpoints and stopping the node, the test waits an extra epoch
(waitUntilEpochStarts(2), ~108s) so the unproven checkpoints' proof-submission deadline
passes and the new node detects the reorg — but the node is stopped and the chain is frozen,
so it's pure dead clock-ticking. Warp the L1 clock to 2 slots before epoch 2's start before
the wait (resetBlockInterval); the new node syncs against the identical L1 height. Real
checkpoint production untouched. Est. ~80s (~31%) off.
The ~248s body is dominated by ~173s of real block production: 34 txs are waitForTx'd,
forcing two checkpoints built (slots 14+15), but the assertions only need one >=8-block
checkpoint (findMultiBlockCheckpoint) plus node-0's per-checkpoint blob fetch. Cut
PIPELINE_TX_COUNT 34->24 (= maxTxsPerCheckpoint) so exactly one ~12-block checkpoint builds,
dropping the wasted ~72s second-checkpoint slot. That stops mid-epoch, so reuse the sibling
warpToProofSubmissionEpoch helper to reclaim the resulting dead epoch-close gap before
waitForProvenCheckpoint. Est. ~74s (~30%) off.
The body waits ~160s for the epoch-0 proof-submission window to expire so the pending chain
becomes prunable, but sync is paused (the proposer cannot build) so it's pure dead clock-
ticking until the fixed deadline. Reuse the blocks.parallel warpNearSubmissionWindowEnd helper
to warp the L1 clock to ~3 slots before the deadline before
waitUntilLastSlotOfProofSubmissionWindow(0); the post-deadline fallback-prune slots run in
real time. The fallback prune is stateless per slot, so skipping dead slots is safe. Est.
~112s (~46%) off.
~240s of the ~241s body was pure poll latency: the PublisherManager checks funding on a
hardcoded 2-minute RunningPromise, and the test waited two full cycles (~120s each) while the
actual funding multicall took ~1s. Grab the manager's fundingPromise (same (publisherManager
as any) reach-in the file already uses for .publishers/.funder) and await its trigger() before
each retryUntil confirmation to force an immediate funding cycle. Assertions preserved. Est.
body ~241s -> ~10s (~88% off).
Each it in this .parallel file is a separate CI job and the bodies are real interval-mined
production (dateProvider pinned to wall-clock, no proof-submission window) so warp is useless.
Merge the two self-anchoring reorg scenarios (remove-message, insert-cancelled-message) into
one it: pays the ~21s setup once, and the second scenario reuses the first's already-built
chain so it skips its own ~67s multi-block-checkpoint ramp (the archiver L1-syncpoint advances
on empty checkpoints). Assertions preserved. Est. ~25% (~62s) off.
The 4 empty checkpoints each cost ~1 L2 slot of real L1 wall-clock. After each
checkpoint lands on-chain, advanceToNextSlot warps the clock forward so the
sequencer builds+publishes the next immediately, one slot at a time, preserving
the one-checkpoint-per-slot layout. ~75s saved.
Body is dominated by waitUntilEpochStarts(1) marching the prod sequencer
through epoch 0 in real wall-clock. Cut ethSlot 12s->4s / L2 slot to 12s (the
multi_proof/long_proving_time-proven floor). ~45s saved.
The body's full ~107s was waitUntilCheckpointNumber(4) idling one L2 slot per
empty checkpoint. Apply the single_root warp loop (advanceToNextSlot after each
lands), preserving the one-checkpoint-per-slot layout so the later reorg(2)
removes the same checkpoints. ~90s saved.
Cut ethSlot 12s->4s / L2 slot to 12s (multi_proof-proven floor) and replace the
real-time waitUntilEpochStarts(1) with the warp-to-next-epoch helper. Added a
checkpointNumberAtEndOfEpoch0 > 0 guard so the test fails loudly rather than
passing vacuously if the warp ever leaves no build window. ~70s saved.
…ck, empty_blocks

The per-checkpoint warp loop raced the production sequencer's building:
single_root hit EmptyEpochError, manual_rollback timed out awaiting block 4,
empty_blocks' guard fired with 0 checkpoints (slot expired). Switch all three to
the slot-cadence cut (eth=4/aztec=12) that multi_proof/upload_failed_proof proved
reliable in the same CI round — ~50s/test, no race. empty_blocks keeps its guard.
@spalladino
spalladino force-pushed the spl/e2e-speed-up-1 branch from 76070f2 to ce505dc Compare June 29, 2026 18:54
Move the follow-up opportunities notes to a local scratch location; this PR
is scoped to e2e test speedups only.
…nd to SingleNodeTestContext

Unify the four near-duplicate warpToEpochStart closures and the two warpNearSubmissionWindowEnd
closures into shared methods on SingleNodeTestContext, importable by single-node and multi-node
tests alike. Both take an options-object for leadSlots (default 2).
…allel suites

Restore the per-test setup in l1_to_l2, l2_to_l1, and messages parallel suites. CI runs each
`it` as its own parallel shard, so keeping separate per-test setup is preferred over a merged
shared setup even at the cost of repeated setup.
Revert account_init to the production-sequencer PIPELINING_SETUP_OPTS preset; a single-node test
should not use the AutomineSequencer.
Revert the FAST_BLOCK_BUILDING_OPTS timing change (which drove blockDurationMs down to 1500ms)
back to the shared PIPELINING_SETUP_OPTS preset. Block time must stay at or above 2s, and the
block-count assertions are derived from the block-duration and slot timing, so the speedup is
dropped rather than left with a sub-2s block time and desynced assertions.
…ed subclass

Change PublisherManager's publishers, funder, and fundingPromise fields from private to protected,
and add a TestPublisherManager subclass in the test that exposes them via public getters, so the
test reads the internals it asserts on without `as any` casts.
Epoch 0 can be empty when the node's sequencer comes up after the chain has already
advanced past it under CI load, leaving no checkpoint to prove (the vacuous-pass guard
then fires). Anchor on a freshly-started epoch and wait for it to elapse, matching the
proven multi_proof pattern.
A cast to a method-bearing subclass fails at runtime: the instance is a base
PublisherManager, so the subclass methods are not on it. Re-declare the protected fields
as public on the subclass and read them as fields instead.
…ne timing

The 4s/12s slot-cadence speedup is not CI-stable for empty_blocks: with
minTxsPerBlock=1 and the fast cadence, an empty checkpoint often is not
built/proven reliably under CI load, failing three consecutive runs. Revert
this file to the base branch to drop the speedup entirely.
@PhilWindle
PhilWindle merged commit 82a53fe into merge-train/spartan-v5 Jun 30, 2026
19 checks passed
@PhilWindle
PhilWindle deleted the spl/e2e-speed-up-1 branch June 30, 2026 20:38
PhilWindle pushed a commit that referenced this pull request Jul 1, 2026
## Motivation

The e2e suite is littered with hand-rolled `retryUntil` / `sleep` /
`Promise.all(...waitForTx)` polls, each flagged with a `// REFACTOR:`
marker. Most duplicate logic that already exists in the shared
`fixtures/wait_helpers.ts` library or on the test contexts. This PR
resolves those markers by adopting the shared helpers (and adding a
handful of small new ones), removing the duplicated, brittle wait code.

Stacked on top of #24345 (`spl/e2e-speed-up-1`), which shipped the
warp/build-window helpers this PR adopts.

## Approach

Every change is **behavior-preserving**: the original loop's timeout,
polling interval, and comparator/predicate are matched exactly. The
mechanism is swapped, not what the test waits for or asserts. Where an
existing helper didn't quite match the original semantics, the helper
was extended with an option rather than the test's behavior being
changed.

- **Adoption** (most families): replace a hand-rolled poll with a call
to a helper that already ships in `wait_helpers.ts` or on
`SingleNodeTestContext` / `MultiNodeTestContext`.
- **New helpers** (the minority): small additions to `wait_helpers.ts`
and `RollupCheatCodes`, each behavior-preserving and adopted in the same
change.

33 of 50 `// REFACTOR:` markers are resolved. The remaining 17 are
deliberately deferred (see Follow-ups) - they are single-use, read from
a data source no shared helper covers, or are the riskiest swaps that
warrant their own focused change.

## Changes (by helper-family)

**Adoption of existing `wait_helpers.ts` functions**
- Block-number waits to `waitForBlockNumber` / `waitForProvenBlock`:
`block_building`, `debug_trace`, `genesis_timestamp`, `l1_to_l2`,
`fee_settings`.
- Node checkpoint waits to `waitForNodeCheckpoint`: `genesis_timestamp`,
`fee_settings`.
- Batch tx waits to `waitForTxs`: `block_building` (3 sites),
`multiple_blobs`, `gossip_network`.
- L2-to-L1 witness waits to `waitForL2ToL1Witness`:
`token_bridge_public`, `token_bridge_private`.
- Monitor checkpoint wait to
`MultiNodeTestContext.waitUntilCheckpointNumber`: `proof_boundary`.
- P2P mesh readiness to `waitForP2PMeshConnectivity` (replaces a fixed
`sleep(8000)`): `fee_asset_price_oracle_gossip`.
- Build-window wall-clock wait to `waitForBuildWindowForSlot`:
`high_tps`.
- Slot-search with `EpochNotStable` warp to existing
`MultiNodeTestContext.findSlotsWithProposers`: `invalidate_block`,
`ha_checkpoint_handoff`.

**New helpers (added + adopted)**
- `wait_helpers.ts`: `waitForTxReceipt` / `waitForTxStatus` (tx-status
transitions in `block_building`), `waitForPendingTxCount`
(`attested_invalid_proposal`), `waitForSequencerState` with an
`after`-action hook - and **deleted** the three duplicated
`waitForSequencerIdle` copies in `l2_to_l1`, `gas_estimation`, and
`reload_keystore`.
- `waitForBlockNumber` extended with a `compare` option for the
prune-backward poll in `synching`.
- `RollupCheatCodes.waitForEpoch` / `waitForSlot` (poll-only, no warp),
adopted in `escape_hatch_vote_only` and `gov_proposal`.

**Inline cleanups (no shared helper warranted)**
- `fee_asset_price_oracle`: two identical price-convergence polls
consolidated into one local helper.
- `upgrade_governance_proposer`: `while(true) + sleep(12000)` quorum
poll to `retryUntil`.
- `upload_failed_proof`: local-variable upload poll to
`promiseWithResolvers` resolved from the upload callback.
- `synching`: archiver-prune `sleep(3000)` to `retryUntil` on the
archiver checkpoint number.

## Follow-ups (deferred markers)

These were left in place because adopting a helper would either change
behavior or add a single-use abstraction:

- `proof_fails:109` - rollback detection reads the L1 rollup contract
(`RollupContract.getCheckpointNumber`), not the node; swapping to a node
helper would change the data source. Needs a rollup-contract-based wait.
- `snapshot_sync:89` - reads `ChainMonitor.checkpointNumber` (not the
node) with `>` semantics; the test uses the legacy `EndToEndContext`,
which has no `waitUntilCheckpointNumber`.
- `long_proving_time:74` - the loop records peak proving-job parallelism
on every iteration; that sampling is the behavior under test, so it
can't be replaced by a plain wait.
- `preferred_gossip_network:183` - per-node exact peer counts in a
heterogeneous topology; doesn't map onto `waitForP2PMeshConnectivity`'s
uniform `>=` check.
- `gov_proposal:245` - ChainMonitor poll that returns a full snapshot
(checkpoint + slot) consumed downstream; no helper returns that.
- `failures:100` - a two-call `advanceToNextEpoch` +
`catchUpProvenChain` sequence, not a hand-rolled poll.
- Family-13 one-offs (`pruned_blocks:117`, `offchain_payment:215`,
`snapshot_sync:100`, `l1_to_l2:130`) - single-use, heterogeneous polls
(error-message match, note-balance, readdir, advance-block-per-poll)
that already use `retryUntil` rather than a sleep.
- `state_vars:439` - a chain-advance-by-sending-txs loop
(side-effecting), not a poll.
- `optimistic:115` - a disposable sampler; single call-site.
- `rediscovery:61` - a `sleep(2500)` guarding against port conflicts
between node restarts, not connectivity.
- `bridging_race.notest.ts:70/77` - in a disabled `.notest.ts` file.
- `fee_settings:121` - the L1-base-fee-spike + oracle-rotation loop
returns a value and is fee-domain specific; warrants its own focused
`RollupCheatCodes` change.

## Verification

`yarn build`, `yarn lint`, and `yarn format` all pass on the touched
packages (`end-to-end`, `ethereum`). The e2e tests themselves are
validated by CI on this stacked PR.
spalladino added a commit that referenced this pull request Jul 1, 2026
…tracts (#24408)

Stacked on top of #24345. Continues the e2e speedup work, targeting two
levers that cut wasted setup work in the single-node cross-chain suites.

## 1. Skip the token bridge deploy for arbitrary-message cross-chain
tests (A-1185)

`l1_to_l2.parallel` and `l2_to_l1.parallel` only pass arbitrary L1↔L2
messages from their own `TestContract`; they never touch the L2 token,
bridge, or portal — they use the cross-chain harness solely for
`ethAccount` and the L1 client/contract handles. They were nonetheless
paying for the full token+portal+bridge setup (an L1 ERC20 deploy, an L1
portal deploy, two L2 contract deploys, and their init txs) on every
run.

`CrossChainMessagingTest` now takes a `deployTokenBridge` flag (default
`true`). When `false`, it sets up the L1 handles + `ethAccount` and
skips the token bridge entirely. The two suites pass `false` and read
the L1 bits directly off the test object. No coverage lost — neither
suite asserts anything on the token bridge.

## 2. Deploy cross-chain L1 contracts before the node starts, under
automine

When a test needs extra L1 contracts (e.g. the cross-chain token portal
+ ERC20), deploying them after the node is running means paying the L1
block interval per deploy and racing the live sequencer/archiver.
`setup` already mines its own L1 contract deployment under anvil
automine before the node starts; this adds a `deployL1Contracts` hook to
`SetupOptions` that runs in that same window, so a test's L1 deploys
mine instantly and finish before any node exists. The resolved value is
exposed on the context as `l1DeployResult`.

The token-bridge path of `CrossChainMessagingTest` now uses this hook to
deploy the ERC20 + token portal pre-node; `CrossChainTestHarness`
accepts the pre-deployed portal address and skips its own portal deploy
(backward compatible — existing callers that pass nothing still deploy
it). This benefits `token_bridge_private`, `token_bridge_public`, and
`token_bridge_failure_cases`.

## Notes

- The `deployL1Contracts` hook is general-purpose; any suite that
deploys L1 contracts in setup can move them into the automine window.
- A second codex pass over the deferred-speedup catalogue surfaced
further low-risk items (fold the warp into the shared multi-node
`waitForProvenCheckpoint`; audited automine swaps for a few fee tests)
that are left for follow-ups.
rangozd pushed a commit to rangozd/aztec-packages that referenced this pull request Aug 5, 2026
BEGIN_COMMIT_OVERRIDE
refactor(e2e): relocate no-node straggler tests (AztecProtocol#24344)
test(e2e): pin gas_estimation public-payment txs to one block to deflake
fee comparison (AztecProtocol#24382)
feat(archiver): event-trigger L2BlockStream sync from archiver updates
(AztecProtocol#24317)
test(e2e): speed up individual e2e tests (AztecProtocol#24345)
chore(e2e): warm blob KZGs in parallel during setup (AztecProtocol#24383)
chore: add perf as a valid PR title prefix (AztecProtocol#24412)
test(e2e): adopt shared wait helpers (AztecProtocol#24404)
test(e2e): run prover client.test.ts in CI (AztecProtocol#24399)
fix(ethereum): mine empty L1 blocks without touching the mempool
(AztecProtocol#24414)
test(e2e): deflake empty block proving test (AztecProtocol#24411)
test(e2e): allocate HA node p2p ports above the ephemeral range to
deflake e2e_ha_full (AztecProtocol#24418)
fix(sequencer): use evmMine in automine auto-settle to avoid dropping
test L1 txs (AztecProtocol#24421)
test(e2e): instrument common spans for wall-clock tracking (AztecProtocol#24407)
test(e2e): remove redundant reqresp_no_handshake e2e test (AztecProtocol#24424)
END_COMMIT_OVERRIDE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-no-fail-fast Sets NO_FAIL_FAST in the CI so the run is not aborted on the first failure

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants