test: add an in-process Tevm test lane, replacing Anvil where rc.151 supports it - #1
Open
roninjin10 wants to merge 1 commit into
Open
test: add an in-process Tevm test lane, replacing Anvil where rc.151 supports it#1roninjin10 wants to merge 1 commit into
roninjin10 wants to merge 1 commit into
Conversation
Replaces the Anvil child process for a large slice of the suite with an in-process Tevm `MemoryClient`, running a complete EVM inside the Vitest worker: no binary, no port, no Prool proxy, no startup polling. - `test/src/tevm.ts` exports `tevmMainnet`, the Tevm counterpart of `anvilMainnet`: a mainnet fork pinned to the blob-free block 22263621, manual mining, the familiar prefunded accounts, and per-test snapshot isolation. - A new `tevm` Vitest project (`src/**/*.tevm.test.ts`) runs with no `globalSetup`; `setup.shared.ts` holds what it shares with `core`. - 17 action/public suites and the complete HTTP transport suite are migrated. `test/src/tevm-server.ts` serves a `MemoryClient` over an ephemeral listener via `tevm/server`; `test/src/http-server.ts` covers the JSON-RPC error cases `tevm/server` answers with HTTP 400. - `src/tevm-showcase.tevm.test.ts` demonstrates the Tevm test library: in-process execution, manual mining, snapshot/revert, pinned forking, the lazy fork-state cache, the `tevm*` actions, the low-level `TevmNode` handlers, and every `@tevm/test-matchers` family. - `src/tevm-resolution.tevm.test.ts` smoke-tests that every Tevm entrypoint resolves its own published Viem, not the unbuilt workspace Viem, so a peer-resolution regression fails loudly and immediately. - Six suites keep their original Anvil coverage and gain a `.tevm` sibling asserting Tevm's actual rc.151 behaviour; `test/README.md` documents the retained-Anvil matrix and the known rc.151 gaps. Viem clients are still built with this repository's `createClient`, over a `custom` EIP-1193 transport; Tevm only supplies the node. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
The suite starts an
anvilchild process for essentially every stateful test, behind a Prool proxy on a fixed port. That means a Foundry binary onPATH, a process per worker, port bookkeeping, and startup polling before a single assertion runs.Tevm is an EVM that runs inside the Vitest worker. This PR wires it up as a first-class test lane and migrates as much of the suite to it as rc.151 correctly supports — while showing off what the Tevm test library can actually do.
Before / after
anvilchild processMemoryClientcreateMemoryClient()returns immediately;tevmReady()awaits the fork anchorevm_snapshotbaseline, reverted before every testsetup.global.tsnoMining: trueminingConfig: { type: 'manual' }Viem clients are still constructed with this repository's
createClient, over acustomEIP-1193 transport that forwards tomemoryClient.request. Migrated suites therefore still exercise this fork's actions, client, and transport code — Tevm only supplies the node. Tevm depends on a newer published Viem than this fork builds; that boundary is crossed in exactly one place, the adapter intest/src/tevm.ts.What's here
A third Vitest project.
tevmmatchessrc/**/*.tevm.test.ts, usestest/setup.tevm.ts, and has noglobalSetup. Everything it shares withcoremoved totest/setup.shared.ts.test/src/tevm.ts—tevmMainnet, the Tevm counterpart ofanvilMainnet. Pinned mainnet fork, manual mining, the familiar prefunded accounts,getClient()with the same shape as the Anvil fixture, and snapshot-based per-test isolation (a successfulevm_revertconsumes its id, so a replacement snapshot is taken immediately).17 migrated action suites —
getCode,getStorageAt,dropTransaction,dumpState,impersonateAccount,increaseTime,mine,revert,setBalance,setCode,setNextBlockTimestamp,setNonce,setStorageAt,snapshot,stopImpersonatingAccount,setBlockTimestampInterval,removeBlockTimestampInterval.The complete HTTP transport suite.
test/src/tevm-server.tsserves aMemoryClientover an ephemeral127.0.0.1listener (port0) usingcreateServerfromtevm/serverfor the real-node paths;test/src/http-server.tsis a plainnode:httpserver for the JSON-RPC error and header cases, whichtevm/serveranswers with HTTP 400 rather than 200-with-error. No coverage was dropped.Tevm test features shown off
src/tevm-showcase.tevm.test.ts, split into focused cases:MemoryClientand this repo's Viem client in one process; manual mining (transactions stay pending untiltevmMine); snapshot & revert through the Anvil-compatibleanvil_snapshot/anvil_revertRPC surfacetevmSetAccount,tevmDeal,tevmDeploy,tevmContract,tevmMine,impersonateAccountTevmNodehandlers —callHandler,contractHandler,dealHandler,deployHandler,setAccountHandleragainst a barecreateTevmNode()SimpleContract,AdvancedContract,ErrorContract,TestERC20from@tevm/test-utils@tevm/test-matchersfamily — primitives (toBeAddress,toBeHex,toEqualAddress,toEqualHex), account & state (toBeInitializedAccount,toHaveState,toHaveStorageAt), events (toEmitwithwithEventArgs/withEventNamedArgs), traces (toCallContractFunctionwithwithFunctionNamedArgs), reverts (toBeRevertedWithString,toBeRevertedWithErrorwithwithErrorNamedArgs), balances (toChangeBalance,toChangeTokenBalance)Honesty about rc.151
Several matcher families run against non-fork
createTevmNode()instances: on a forked node rc.151 resolves balances and storage througheth_getProofagainst the upstream historical block, so locally written values are invisible.test/README.mdlists every gap found.Six suites keep their original Anvil coverage and gain a
.tevmsibling that asserts Tevm's actual behaviour rather than restating Anvil's — nothing is weakened:.tevmsibling documentssetStorageAteth_getStorageAtreturns the storage word right-paddedgetStorageAtimpersonateAccount/stopImpersonatingAccountsetBlockTimestampInterval/removeBlockTimestampIntervalanvil_setBlockTimestampIntervalis recorded but not applied to mined blocksThe fork is pinned to 22263621, the nearest blob-free block below Anvil's 22263623: rc.151's
Common.copy()dropscustomCrypto, so a forked anchor containing EIP-4844 transactions cannot be deserialized. Choosing a blob-free anchor is preferred over filtering type-3 transactions out of an otherwise inconsistent block response — the fork sees exactly what the provider returns.Anvil is not going anywhere: WebSocket and IPC transports, the Alto bundler / account-abstraction suites, the Optimism / zkSync / Sepolia fixtures, wallet-provider emulation,
sendUnsignedTransaction,setAutomineandsetIntervalMiningall still need it, andpnpm installstill runscontracts:buildwithforge.Dependency hygiene
Tevm packages are pinned to exact
1.0.0-rc.151(the movinglatest/nexttags resolve to older builds with a much smaller Anvil surface), andpnpm.packageExtensionspins the entire Tevm family onto one published Viem —@tevm/errorswas resolving a second copy and is now pinned too.@tevm/serveris deliberately not installed (itslatesttag is an obsolete0.0.1);createServercomes fromtevm/server.@tevm/ts-pluginis not a dependency until direct Solidity imports are actually enabled.src/tevm-resolution.tevm.test.tsguards all of that at runtime: it imports every Tevm entrypoint the suite uses, so a peer-resolution regression — Tevm silently binding the unbuilt workspace Viem — fails here, first and legibly, instead of as an opaque module error deep inside an unrelated suite.No changeset: this change is entirely test infrastructure and
devDependencies, with no effect on the published package.Test evidence
The Tevm lane, against an archive mainnet RPC:
The six suites whose original Anvil coverage was restored, on the
core(Anvil) project:biome check src testreports no new findings (the 9 warnings are pre-existing, all insrc/tempo/).tsc -breports no errors in any file this PR adds or modifies; the remaining errors are the pre-existing Voltaire-migration ones onmain.Credits
Produced by a multi-agent run: three independent implementation lanes (
codex-sol,opus,kimi) were built and judged, and this branch is the winning lane with the best ideas from the others grafted in — the focused showcase split, the explicit rc.151 limitations matrix and retained-Anvil coverage, the blob-free fork block, dropping@tevm/ts-plugin, and the runtime resolution smoke tests.🤖 Generated with Smithers multi-agent orchestration