Skip to content

Espresso 4: e2e tests - #475

Draft
lukeiannucci wants to merge 41 commits into
espresso/batcherfrom
espresso/e2e-tests-2
Draft

lukeiannucci wants to merge 41 commits into
espresso/batcherfrom
espresso/e2e-tests-2

Conversation

@lukeiannucci

@lukeiannucci lukeiannucci commented Jul 21, 2026 •

Copy link
Copy Markdown

Espresso 4: e2e tests

Ports the Espresso end-to-end test suite into the monorepo as espresso/environment and runs it in CI on free GitHub runners. The tests exercise the full integration — batcher, streamer, derivation pipeline, BatchAuthenticator contract — against an in-memory mock Espresso dev node, so no docker or external espresso-dev-node is needed in CI or locally. Builds on #459 (TEE batcher).

What's included

  • espresso/environment — the e2e suite: soft-confirmation integrity, forced transactions, batcher fallback/switching, L1 reorgs, batch-inbox authentication, stateless batcher, pipeline enhancement, the EspressoTime enforcement hardfork, dispute game.
  • espresso/mock_client.go — in-memory mock Espresso client shared by the batcher and the tests, injected via the new WithEspressoClientOverride option (the only op-batcher change here; the streamer-v2 batcher itself lives in Espresso 3b: TEE batcher (re-hosted) #459).
  • .github/workflows/espresso-e2e-tests.yaml — runs the suite as five parallel matrix groups (core, integrity, fallback, forced-reorg, dispute) with a forge-artifacts cache; contracts only, no cannon prestates needed. Triggers on espresso/**, op-batcher/**, op-challenger/**, op-e2e/**, op-node/**, packages/contracts-bedrock/**.
  • op-deployer / op-chain-ops / op-e2e — Espresso deploy pipeline (BatchAuthenticator + mock TEE verifiers) and e2esys support for Espresso systems (fallback batcher on the SystemConfig batcher key, espresso batcher on a dedicated key at HD index 6).
  • flake.nix — dev shell for running the suite locally.
  • README_ESPRESSO.md + just go-tests-espresso-e2e — how to run the suite locally. The recipe mirrors the CI invocation (all three packages, -p 1, 45m timeout), takes an optional -run regexp, fails fast if contracts aren't built, and honours GOTESTSUM_FORMAT=standard-verbose (stream full output) and OP_TESTLOG_FILE_LOGGER_OUTDIR (one log file per test; the recipe creates the directory, which testlog itself does not).

What runs in CI

25 tests, all in espresso/environment, split across the five groups (as of a92fa2d):

core (8) — TestE2eDevnetWithEspressoSimpleTransactions, TestE2eDevnetWithEspressoAndAltDaSimpleTransactions, TestE2eDevnetWithoutEspressoSimpleTransaction, TestE2eDevnetWithoutAuthenticatingBatches, TestStatelessBatcher, TestAnsiEscapeCodeLineReader, TestEspressoDevNodeLogEntry, TestEspressoDeployedContractLogEntryReader

integrity (5) — TestSequencerFeedConsistency, TestSequencerFeedConsistencyWithAttackOnEspresso, TestDeterministicDerivationExecutionStateWithInvalidTransaction, TestValidEspressoTransactionCreation, TestConfirmationIntegrityWithReorgs

fallback (4) — TestBatcherSwitching, TestFallbackMechanismIntegrationTestChannelNotClosed, TestEspressoEnforcementHardfork, TestE2eDevnetWithEspressoDegradedLiveness

forced-reorg (7) — TestForcedTransactionWithEspressoLargeWindow, TestForcedTransactionWithEspressoSmallWindow, TestForcedTransactionWithoutEspressoLargeWindow, TestForcedTransactionWithoutEspressoSmallWindow, TestBatcherWaitForFinality, TestE2eDevnetWithL1Reorg, TestPipelineEnhancement

dispute (1) — TestOutputAlphabetGameWithEspresso_ChallengerWins. An output alphabet game: the trace comes from the in-process challenger, so it needs no cannon prestate and runs in ~90s.

Every filter matches a test and every test is matched by a filter (checked mechanically), so nothing is silently absent from CI.

Skipped tests (11)

Everything not runnable yet ships as a t.Skip stub with a TODO describing what unblocks it, so gaps show up as SKIP in CI:

  • TestE2eDevnetWithInvalidAttestation, TestE2eDevnetWithUnattestedBatcherKey — need the SP1 attestation-verifier service, which the mock doesn't emulate. Not blocked on TEE hardware: the verifier is a plain Docker container (ghcr.io/espressosystems/attestation-verifier-zk, public), or can be faked in-process. The suite exercises the TEE auth flow (EIP-712 commitment, authenticateBatchInfo, event-based derivation auth) but not attestation verification itself — that's covered by the BatchAuthenticator.t.sol unit tests and the vendored espresso-tee-contracts repo.
  • espresso/devnet-tests (8) and espresso/enclave-tests (1) — the reference repo's heavier devnet/real-TEE tier, stubbed so the eventual port is a drop-in. Its workflows (espresso-devnet-tests.yaml, espresso-devnet-tests-tee.yaml, ec2-devnet-test.yaml) are checked in but workflow_dispatch-only. The standard compose profile needs the devnet harness (devnet_tools.go, compose files) ported and a larger runner; only the TEE profile and the enclave test need Nitro-enclave EC2 runners and AWS secrets (each workflow's TODO header lists it). Until then, real-TEE coverage continues to run in the reference repo.

The test inventory was diffed function-by-function against the reference repo (celo-integration-rebase-17). Dropped without stubs: the Caff-node tests (the Caff node is no longer supported), TestEnforceMajorityRule (MajorityRule was deprecated in favor of SingleNode) and TestEspressoDockerDevNodeSmokeTest (the dockerized dev-node launcher was replaced by the in-memory mock).

Notes for reviewers

  • The espresso batcher submits every frame as an ordered auth+batch pair via TxManager.SendPairAsync; test doubles that wrap txmgr.TxManager must override that method too (see TxManagerIntercept).
  • During the enforcement grace window (EspressoTime → + BatchAuthEnforcementDelaySecs) the verifier authorizes batches by L1 sender only, so handing the chain to the TEE batcher inside that window requires rotating SystemConfig.batcherHash to its address (exercised by the hardfork test).
  • StopBatchSubmitting force-kills only when the passed context expires, so tests that wedge the batcher on purpose stop it with a short-lived context.
  • StartE2eDevnet closes the system when the caller's context is cancelled; that goroutine is tied to t.Cleanup so System.Close (which logs via t.Log) can never run after the test has returned — doing so panics the whole test binary, not one test.

🤖 Generated with Claude Code

@philippecamacho

Copy link
Copy Markdown
Collaborator

Great! Can we start adding the E2E tests?

@lukeiannucci

lukeiannucci commented Jul 21, 2026 •

Copy link
Copy Markdown
Author

Great! Can we start adding the E2E tests?

@philippecamacho

The code is in here, I need to ask celo about potentially running it in their CI. Not sure the cost / runners they have.

Update i am trying some of them on what should be free runners.

@lukeiannucci lukeiannucci changed the title Espresso/e2e tests 2 4: Espresso e2e tests Jul 21, 2026
@lukeiannucci lukeiannucci changed the title 4: Espresso e2e tests Espresso 4: e2e tests Jul 21, 2026
@lukeiannucci
lukeiannucci force-pushed the espresso/e2e-tests-2 branch 2 times, most recently from 1bc3c45 to 92c832c Compare July 31, 2026 12:28
@philippecamacho
philippecamacho force-pushed the espresso/e2e-tests-2 branch 5 times, most recently from 3ef0782 to 7b0ced9 Compare August 8, 2026 23:47
@philippecamacho
philippecamacho force-pushed the espresso/e2e-tests-2 branch 2 times, most recently from 37e7b56 to 455d86e Compare August 14, 2026 00:00
@philippecamacho

Copy link
Copy Markdown
Collaborator

Rebased on #459

lukeiannucci and others added 23 commits October 30, 2026 10:19
- 3_2: use batch.SignerAddress — batch.Signer() only exists in a newer
  espresso-streamers than the pinned one; broke compilation of every
  espresso-e2e job and go-lint
- 14: TxManagerIntercept now also intercepts SendPairAsync — the batcher
  submits frames as auth+batch pairs via Queue.SendPair, so the simulated
  failure never fired and TestFallbackMechanismIntegrationTestChannelNotClosed
  waited out its whole budget; also bound StopBatchSubmitting with a short
  context, since a batcher whose every submission fails can never drain
  gracefully and only force-kills when the passed context expires
- 15: rotate the SystemConfig batcher hash to the TEE batcher key when
  handing over inside the enforcement grace window — the verifier authorizes
  by L1 sender alone until EspressoTime + BatchAuthEnforcementDelaySecs
  (auth events are not scanned yet), so the phase-4 TEE batches were dropped
  as 'tx in inbox with unauthorized submitter'

Both tests pass locally (388s / 379s vs deterministic 600s / 490s failures).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ration

- 6: zero the BatchAuthenticatorAddress only after StartBatchSubmitting —
  the v2 streamer is constructed there and requires the real contract to
  validate batches read back from Espresso. Zeroing afterwards still makes
  the publish path send authenticateBatchInfo to the zero-address EOA,
  which succeeds without emitting the event, so batches land on the
  BatchInbox unauthenticated as the test intends
- 8: TestBatcherWaitForFinality now asserts the safe head's L1 origin
  against the L1 chain's own finalized tag instead of the verifier's
  FinalizedL1 view — the batcher gates submission on the sequencer node's
  finality view, and the verifier's finality poller can briefly lag it,
  tripping the assertion without any batcher misbehavior

Both pass locally (67s / 44s).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lity

Use bigs.Uint64Strict instead of big.Int.Uint64, as required by the
custom bigint analyzer.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Make the missing Espresso tests visible in the tree and in CI output as
SKIP instead of silently absent, each with a TODO describing what the
port needs:

- espresso/devnet-tests: stub package mirroring the reference repo's
  devnet test tier (smoke, batcher active-publish/restart/switching,
  challenge game, forced transaction, key rotation, withdrawal). The
  real bodies drive a docker-compose devnet and, in the TEE profile,
  a batcher in a real AWS Nitro enclave via the ec2-devnet-test.yaml
  workflow — none of that infrastructure exists here yet; the package
  doc carries the porting checklist.
- espresso/environment/5_batch_authentication_test.go: restore
  TestE2eDevnetWithInvalidAttestation and
  TestE2eDevnetWithUnattestedBatcherKey as skipped stubs — their
  original bodies (dropped in 3dd70bc) gate on the SP1 zk
  attestation verifier, which the in-memory mock does not emulate.
- espresso-e2e-tests.yaml: include ./espresso/devnet-tests/... in the
  test path and add the stub names to the core group filter so every
  stub surfaces as SKIP in CI.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
flake.nix/flake.lock are local tooling for running the e2e suite in a
nix dev shell; they were swept into the previous commit by accident.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bring over espresso-devnet-tests.yaml, espresso-devnet-tests-tee.yaml and
the reusable ec2-devnet-test.yaml from optimism-espresso-integration
(celo-integration-rebase-17) so the devnet/real-TEE tier is visible in
this repo next to its skipped test stubs (espresso/devnet-tests).

Each carries a TODO header listing what enabling needs: the compose
devnet + devnet_tools harness, compile-contracts.yaml and the
cache-submodules action, and for the TEE path the Nitro-enclave EC2
runner infrastructure (ec2-github-runner enclave fork, AWS secrets and
role, nitro-cli AMI). The two callers trigger on workflow_dispatch only
until then; the reusable workflow is workflow_call-only and inert.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Full diff of test functions against optimism-espresso-integration
(celo-integration-rebase-17) found ten tests absent from this fork.
Resolution by category:

- espresso_dev_node_logs_test.go (TestAnsiEscapeCodeLineReader,
  TestEspressoDevNodeLogEntry, TestEspressoDeployedContractLogEntryReader):
  ported live — they unit-test the log-reader helpers that already ship
  here, and pass.
- espresso/enclave-tests (TestE2eDevnetWithEspressoAndEnclaveSimpleTransactions):
  new stub package for the enclave tier — the real body needs a
  Nitro-enabled EC2 runner and the op-batcher enclave image.
- TestEspressoDockerDevNodeSmokeTest: skipped stub — the dockerized
  espresso-dev-node it smoke-tests was replaced by the in-memory mock.
- Caff-node tests (TestE2eDevnetWithEspressoFastConfirmationStability,
  TestE2eDevnetWithEspressoWithCaffNodeDeterministicDerivation,
  TestFastDerivationAndCaffNode, TestCaffNodeWaitForFinality,
  TestE2eDevnetWithEspressoDegradedLivenessViaCaffNode): intentionally
  NOT ported — the Caff node is no longer supported.

The e2e workflow now also runs ./espresso/enclave-tests/... and lists
the new stub and log-reader test names in the core group filter.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pins the same toolchain the espresso-e2e-tests workflow uses in CI
(go 1.26, just, gotestsum, forge 1.2.3 official release binaries) so
the tests can be run locally with 'nix develop' instead of mise.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Commit 608840b removed --espresso.rollup-l1-url (the espresso L1 is
always the rollup L1), but the e2e harness still set the deleted
CLIConfig field, breaking the test build across all espresso-e2e CI
shards. L1URL already carries the same RPC.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ness

#512 (af22822) deleted CLIConfig.AllowEmptyAttestationService on the
premise that nothing set it, but the mock dev-node harness did, so
CLIConfig.Check now requires the attestation service URL unconditionally
and the test build broke across all espresso-e2e CI shards.

Set a placeholder URL instead, mirroring the espresso-mock.invalid
QueryServiceURLs placeholder in e2esys. It is never dialed: the only
consumers are registerBatcher and GenerateZKProof, both gated on a
non-empty Nitro attestation, which never exists outside a TEE.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
#513 moved the generated bindings from espresso/bindings to
op-service/bindings/<contract>, so the two e2e tests that construct a
BatchAuthenticator now import op-service/bindings/batchauthenticator.

The package is a full abigen binding, so this is only a requalification
of the import and the three NewBatchAuthenticator call sites.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* ci: run the Espresso fault-proof test in its own shard

TestOutputAlphabetGameWithEspresso_ChallengerWins has been complete and
passing all along, but no shard filter selected it, so it never ran and
never even showed up as a SKIP.

The group was disabled pending a cannon prestate build on free runners,
but the test plays an output *alphabet* game: the trace comes from the
in-process challenger, not from cannon, so no prestate is involved. It
passes locally in 92s with op-program/bin absent and no prestate built.

Since the shard drives the in-process challenger, add op-challenger/** to
the workflow's path filter so a challenger-only change triggers it.
#534 removed the accessor when the driver's streamer became an interface
recreated on each start, but the Espresso e2e deterministic-state test still
uses it to unmarshal a batch. Restore it, taking the driver mutex that now
guards the field and returning nil when the batcher is not running.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…reamer

#538 moved the driver's streamer into espressoSession, so the restored
accessor no longer compiled. Read it from the session instead, returning
nil when no session is active.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
philippecamacho and others added 4 commits October 30, 2026 12:19
…2e harness

#566 replaced espresso.CLIConfig.QueryServiceURLs with a single
QueryServiceURL, but the e2e harness still set the old field, so op-e2e and
espresso/environment no longer compiled. Set the single URL in e2esys and the
query-service proxy option, and drop SetEspressoUrls, which had no callers and
only existed to exercise the removed multi-node majority rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ticatingBatches

#560 made the batcher bind the BatchAuthenticator once at construction and
build authenticateBatchInfo transactions from that binding, so zeroing
RollupConfig.BatchAuthenticatorAddress after startup no longer stopped the
batches from being authenticated, and the verifier derived them.

Wrap the test's tx manager so transactions addressed to the
BatchAuthenticator go to the zero-address EOA instead: they succeed without
emitting BatchInfoAuthenticated, which restores the scenario under test while
the batcher keeps reading the real contract.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The batcher submits each authenticateBatchInfo call and its batch tx as an
ordered pair through Queue.SendPair, which calls TxManager.SendPairAsync.
RedirectingTxManager only overrode Send and SendAsync, so the embedded
manager still sent the auth call to the real BatchAuthenticator and the
verifier derived the batches. Override SendPairAsync too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat: Support upgrade test for TEE batcher

* docs: clarify TEE upgrade test runner and epoch setup

* ci: configure TEE upgrade runner AMI through repository variable

* ci: configure TEE upgrade AWS role through repository variable

* ci: use GitHub App token for EC2 runner

* ci: configure scoped AWS runner for TEE batcher upgrade test

* ci: fix Nitro allocator configuration parsing

* test: wait for usable Espresso header before starting TEE batcher

* test: set recipient for TEE upgrade pending transaction

* test: use the single Espresso query URL flag in enclave tests

* ci: run TEE upgrade tests automatically on branch pushes

* ci: validate TEE batcher upgrades on pull requests

* test: bound enclave readiness reads with a deadline

A connection accepted before the vsock bridge is up could block conn.Read
indefinitely, bypassing waitForEnclaveReady's two-minute timeout. Dial with
the context and cap each read at 5s (or the context deadline) so stalled
connections are retried.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Javier Cortejoso <javier.cortejoso@gmail.com>
Co-authored-by: Jean Gal <jgatbkk@gmail.com>
Co-authored-by: Philippe Camacho <philippe@espressosys.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants