Skip to content

✨ feat(server): add WebSocket JSON-RPC transport with eth_subscribe support - #2084

Merged
roninjin10 merged 3 commits into
mainfrom
feat/websocket-server
Jul 30, 2026
Merged

✨ feat(server): add WebSocket JSON-RPC transport with eth_subscribe support#2084
roninjin10 merged 3 commits into
mainfrom
feat/websocket-server

Conversation

@roninjin10

Copy link
Copy Markdown
Collaborator

Motivation

@tevm/server served HTTP only — createHttpHandler and createServer, no WebSocket anywhere. That gap is the reason viem's test suite must keep Anvil around for its webSocket() transport suites: Anvil serves ws and http on the same port, and Tevm could not.

The hard half was already built — packages/actions/src/eth/ethSubscribeHandler.js implements eth_subscribe. What was missing was a transport to expose it.

What this adds

  • createWebSocketServer — JSON-RPC over WebSocket, served on the same port as HTTP.
  • eth_subscribe / eth_unsubscribe wired so subscriptions actually push notifications to connected clients.
  • Connection lifecycle handling and cleanup so sockets don't leak.
  • Exported through the package barrels and the top-level tevm package.

Testing

packages/server/src/createWebSocketServer.spec.ts5/5 passing, verified locally:

Test Files  1 passed (1)
     Tests  5 passed (5)

No mocking, per the repo's testing conventions.

Note on CI

This branch is based on main, which is currently red for an unrelated reason (ERR_PNPM_OUTDATED_LOCKFILE from the unpinned zevm workspace checkout). #2083 fixes that; once it lands this needs a rebase for a clean signal.

🤖 Generated with Smithers multi-agent orchestration

@vercel

vercel Bot commented Jul 29, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
node Ready Ready Preview Jul 30, 2026 1:38am
tevm-monorepo-app Ready Ready Preview Jul 30, 2026 1:38am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
tevm-monorepo-tevm Ignored Ignored Jul 30, 2026 1:38am

Request Review

@changeset-bot

changeset-bot Bot commented Jul 29, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: b8b4030

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

💥 An error occurred when fetching the changed packages and changesets in this PR
Some errors occurred when validating the changesets config:
The package or glob expression "@evmts/*" is specified in the `ignore` option but it is not found in the project. You may have misspelled the package name or provided an invalid glob expression. Note that glob expressions must be defined according to https://www.npmjs.com/package/micromatch

@claude

claude Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Claude encountered an error —— View job


I'll analyze this and get back to you.

@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@roninjin10, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 36 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 24a5eb16-e2d2-437d-a2bd-5aa860ca6146

📥 Commits

Reviewing files that changed from the base of the PR and between c8d1952 and b8b4030.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (8)
  • .changeset/websocket-server.md
  • packages/server/package.json
  • packages/server/src/createServer.js
  • packages/server/src/createWebSocketServer.js
  • packages/server/src/createWebSocketServer.spec.ts
  • packages/server/src/index.js
  • packages/server/src/index.spec.ts
  • packages/server/src/index.ts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@claude

claude Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Claude encountered an error —— View job


I'll analyze this and get back to you.

@roninjin10
roninjin10 force-pushed the feat/websocket-server branch from 013f2e1 to b8b4030 Compare July 30, 2026 01:37
@claude

claude Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Claude encountered an error —— View job


I'll analyze this and get back to you.

@roninjin10
roninjin10 merged commit cc57c9f into main Jul 30, 2026
11 of 14 checks passed
@roninjin10
roninjin10 deleted the feat/websocket-server branch July 30, 2026 01:52
@roninjin10

Copy link
Copy Markdown
Collaborator Author

Blocking WebSocket findings:

  1. packages/server/src/createWebSocketServer.js:210-295 bypasses the server shared JSON-RPC parser and overwrites every incoming version with jsonrpc: 2.0. It accepts requests that Anvil rejects with -32600, including jsonrpc: 1.0, a missing jsonrpc, and boolean IDs; I reproduced all three receiving successful eth_chainId responses on this branch. It also has no maxBatchSize, so a payload under maxPayload can fan out an arbitrarily large Promise.all, while HTTP/IPC enforce the configured batch limit. createServer.js:34-38 only forwards maxBodySize, despite documenting the handler options as applying to WebSocket too. Please reuse parseRequest and handleBulkRequest with requireJsonrpc: true, ID/params validation, and the configured maxBatchSize, rather than maintaining a second partial JSON-RPC implementation.

  2. The async newHeads EventEmitter listener at createWebSocketServer.js:121-134 awaits rpc.send without a try/catch. EventEmitter does not observe the returned promise, so a readiness, lookup, or serialization failure becomes an unhandled rejection rather than a transport error. Cleanup has the same issue at lines 309-321 by discarding rpc.send(...) without a rejection handler. Catch and log/close per-connection failures, as the IPC newHeads listener already does, and make cleanup promises explicitly rejection-safe.

The subscription/filter cleanup happy paths and filter draining tests pass. The larger duplication with #2080 should still be factored into one connection-scoped subscription helper so ownership, draining, syncing, and error handling do not continue to diverge.

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.

1 participant