feat(e2e): add two-chain anvil environment - #1802
Conversation
… assumptions
Implements T3's design (aggkit-env-design.md): a new test/e2e/envs/anvil-2chains/
env built from the kurtosis-cdk anvil devnet snapshot (commit fc160450, K8's
GHCR-published digest-pinned images for anvil-001/l2-anvil-001/l2-anvil-002/
agglayer; aggkit-001/aggkit-002/aggkit-proxy-001 on aggkit:local). Two anvil L2
sovereign chains settle PessimisticProof certificates (TriggerCertMode=ASAP,
explicit in both configs) against one anvil L1, each aggkit running
aggsender+aggoracle+bridge+autoclaim, fronted by a shared aggkit-proxy.
Config tree copied from the actual published-run images' baked config (not a
separate local re-run capture, whose block numbers didn't match the digest-
pinned anvil chain state and caused "no contract code at given address" against
the RollupManager at a stale genesis block), then renamed per
extract-state.sh's documented kurtosis->aggkit path mapping.
agglayer carries a real TCP-connect healthcheck against its gRPC port (K5c's
fix); aggkit-00X/aggkit-proxy-001 gate on service_healthy against it and carry
no healthcheck of their own (distroless image, confirmed no shell). This avoids
the aggsender claim-syncer deadlock a `service_started` dependency reproducibly
hits.
Four Go edits generalize hardcoded op-pp-2chains assumptions so this new env
(and any future multi-chain env) works without a new env-name branch:
- loader.go: add EnvAnvil2Chains; load L2B based on summary.json key presence
instead of env name; add Env.ComposeServices(ctx) (docker compose config
--services) for log collection.
- checks.go: extend the L2A chain-ID check's env-name condition (kept
name-keyed on purpose -- it exists to catch a stale/wrong summary.json).
- testmain_test.go: dumpContainerLogs now iterates ComposeServices(ctx) instead
of a hardcoded, already under-covering service list.
Also fixes a real race in bridge_utils.go's BridgeL1ToL2: this env runs
AutoClaim's L1ToL2BridgeDetector on the same network TestMain's post-test
bridge check manually claims into, so the manual ClaimAsset call can lose the
race and revert with AlreadyClaimed. Check IsClaimed first (same check
autoclaim_test.go already uses) and treat an already-claimed deposit as
success instead of a failure.
anvil-2chains's aggkit-001 also sets user: "${UID}:${GID}" (matching op-pp's
own /tmp-bind-mount precedent) so files written to the host-mounted
aggkit-001-data dir stay host-owned and removable by the next run.
Verified: AGGKIT_E2E_ENV=anvil-2chains make test-e2e TEST_RUN='TestZZZNoSuchTest'
passes green from a clean docker state (43s wall clock), including both
post-test L1->L2 and L2->L1 bridge flows; op-pp and op-pp-2chains pass
unchanged with the same pattern (61.6s, 138.7s respectively); make lint and
gofmt are clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015Q5xUjjWCiNQdm7cmeWYrs
A3: sweep and measure config knobs for test/e2e/envs/anvil-2chains against
the TestMain-only wall-clock (AGGKIT_E2E_ENV=anvil-2chains make test-e2e
TEST_RUN='TestZZZNoSuchTest'), 27 timed runs across 7 configurations.
- config/agglayer/config.toml: add
[settlement.pessimistic-proof-tx-config.retry-on-not-included-on-l1]
initial-interval = "5s" (was unset/60s default). Confirmed via container
log (sleep_duration dropped from ~62s to ~9-14s) and via
`agglayer validate-config` dump. Real isolated effect on this measured
command is smaller than the design doc expected (~6s), because the
measured post-test bridge check reads state through aggkit's own
L1InfoTreeSync (watches L1 directly), not through agglayer's internal
settlement-confirmation bookkeeping -- kept anyway since it is free
(no reorg-safety cost) and matters for any future test that reads
agglayer's own certificate-status API instead.
- config/{001,002}/aggkit-config.toml: AggOracle.WaitPeriodNextGER and
AggOracle.EVMSender.WaitPeriodMonitorTx lowered 10s -> 1s. This, not the
settlement retry interval, is the dominant lever found for this env:
it collapsed a reproducible ~36s/~43s bimodal split (poll-cycle alignment
noise on the L1->L2 GER-injection wait) into a tight ~35-37s cluster.
WaitPeriodMonitorTx=1s restores config/default.go's own upstream default;
WaitPeriodNextGER=1s is a deliberate deviation below its 10s default,
justified since it is a pure poll-frequency knob with no finality/
reorg-safety semantics.
Measured median: 43.18s (pre-tuning) -> 35.58s (chosen config), verified
green 3 consecutive times from clean docker in two independent batches.
settlement-policy=LatestBlock was tested and NOT shipped (no measured
benefit over SafeBlock at this scale). The MinimumNewCertificateInterval
default discrepancy (aggsender/config/config.go's dead 1h Go-struct
fallback vs config/default.go's 5m vs the env comment's incorrect 5s claim)
is resolved in writing with evidence: the real effective default is 5m,
confirmed via `aggkit run --save-config-path` dump
(Duration = 300000000000ns), and does not gate this measured command since
only one certificate per network is ever required by it.
Full measurement table, raw run logs, and effective-config dumps in
plans/snapshot-v2-aggkit-e2e/A3-evidence/.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015Q5xUjjWCiNQdm7cmeWYrs
|
Claude finished @arnaubennassar's task in 2m 12s —— View job Code Review Complete ✅🚀 What's NewThis PR introduces 🐛 Bug FixesNone. 📋 Config Updates
|
Changes Summary
anvil-2chains, a hermetic two-L2 Anvil E2E environment assembled from the published kurtosis-cdk snapshot bundle.force_ger_updatetest, fromop-pp/op-pp-2chainstoanvil-2chains.anvil-2chainsthe local Go E2E default while retainingAGGKIT_E2E_ENVas an override.Config Updates
001and002, plus Agglayer and proxy config.aggkit:local.5579and publishes it as14579/15579for AutoClaim approval tests.TriggerCertMode = "ASAP", one-second AggOracle polling, and the current Agglayer pessimistic-proof settlement schema.Testing
go test -short ./test/e2e/....github/workflows/test-go-e2e.ymldocker compose config --quietforanvil-2chainsTestAutoClaimL1ToL2APIApproveonanvil-2chains, including its post-test bridge health checkmake lintcould not run locally becausegolangci-lintis not installed in the development environment.Related PRs
The snapshot provenance, immutable image digests, port map, and regeneration procedure are documented in
test/e2e/envs/anvil-2chains/README.md.