ethereum-optimism / ethereum-optimism/optimism

opgeth-decoupling: re-home the RPC recording hooks (recorder seam + rpc.JsonError)

Open
#22,753 0 comments 0 reactions 0 assignees Claimed by @sebastianst View on GitHub
Dominant language
Go
Stars
6.5k
Forks
4k
Avg merge
2d 15h
Merged PRs (30d)
145

Description

Part of #21745 (§15 of the [op-geth decoupling doc](https://github.com/ethereum-optimism/optimism/blob/1657fbe391d3f37785a6a3609422ee79fe86d9fa/docs/ai/opgeth-decoupling.md#L437-L444)). **Blocks #20266.**

op-geth adds `rpc.Recorder` / `RecordedMsg` / `RecordDone` / `WithRecorder` hooks *inside* geth's RPC client **and** server, and exports `rpc.JsonError` (unexported upstream). Three op-service foundations build on them; upstream go-ethereum offers no equivalent, so we have to own the seam.

## Scope (measured at 1657fbe)

- [`op-service/metrics/rpc_metrics.go`](https://github.com/ethereum-optimism/optimism/blob/1657fbe391d3f37785a6a3609422ee79fe86d9fa/op-service/metrics/rpc_metrics.go#L16-L45) — `RPCMetricer.NewRecorder(name) rpc.Recorder` leaks the geth type into every service's metrics struct; [`rpcRecorder`](https://github.com/ethereum-optimism/optimism/blob/1657fbe391d3f37785a6a3609422ee79fe86d9fa/op-service/metrics/rpc_metrics.go#L171-L211) emits the client *and* server RPC metrics.
- Client side: [`op-service/client.WithRPCRecorder`](https://github.com/ethereum-optimism/optimism/blob/1657fbe391d3f37785a6a3609422ee79fe86d9fa/op-service/client/rpc.go#L109-L115) forwards straight into `rpc.WithRecorder` on the geth client.
- Server side: [`op-service/rpc.Handler.recorder`](https://github.com/ethereum-optimism/optimism/blob/1657fbe391d3f37785a6a3609422ee79fe86d9fa/op-service/rpc/handler.go#L46) / [`WithRPCRecorder`](https://github.com/ethereum-optimism/optimism/blob/1657fbe391d3f37785a6a3609422ee79fe86d9fa/op-service/rpc/handler_options.go#L70-L75). The handler already has an outer HTTP middleware stack ([handler.go#L74-L80](https://github.com/ethereum-optimism/optimism/blob/1657fbe391d3f37785a6a3609422ee79fe86d9fa/op-service/rpc/handler.go#L74-L80)), but geth's `rpc.Server` dispatches by reflection with no upstream hook, so per-method/batch/websocket granularity is not free there.
- `rpc.JsonError`: [`op-node/rollup/engine/api.go`](https://github.com/ethereum-optimism/optimism/blob/1657fbe391d3f37785a6a3609422ee79fe86d9fa/op-node/rollup/engine/api.go), [`op-test-sequencer/sequencer/seqtypes/types.go`](https://github.com/ethereum-optimism/optimism/blob/1657fbe391d3f37785a6a3609422ee79fe86d9fa/op-test-sequencer/sequencer/seqtypes/types.go#L124-L139) (16 sentinel errors), [`op-interop-filter/filter/frontend.go`](https://github.com/ethereum-optimism/optimism/blob/1657fbe391d3f37785a6a3609422ee79fe86d9fa/op-interop-filter/filter/frontend.go#L28), `op-service/rpc/stream.go`, plus tests.

## PRs

1. **Own the recorder interfaces + client-side recording, and drop `rpc.JsonError`.** Define `Recorder`/`RecordedMsg`/`RecordDone` in op-service (no geth types in the signature) and move `RPCMetricer` onto them; implement recording in our own RPC client wrapper in `op-service/client` — a seam we already own. Replace `rpc.JsonError` with a local error type carrying the same `Code`/`Message`/`Data` and `ErrorCode()`, so JSON-RPC error codes on the wire are unchanged. Can land before the cutover.
2. **Server-side interception.** Design and build the replacement observation point — HTTP middleware that parses the JSON-RPC envelope, or wrapping the registered `rpc.API` services — and wire `op-service/rpc.Handler` to it. Metric **names and labels must not change**; per-message fidelity may be approximated (document what is approximated: batches, websocket, notifications).

## Acceptance criteria

- No monorepo Go file references `rpc.Recorder`, `rpc.RecordedMsg`, `rpc.RecordDone`, `rpc.WithRecorder`, or `rpc.JsonError`.
- The `_rpc_client_*` / `_rpc_server_*` metric names and label sets are identical before and after, verified by a test over the registered collectors.
- JSON-RPC error codes served by op-node engine API, op-test-sequencer, and op-interop-filter are unchanged.

🤖 *Co-created with Claude Opus 5 (1M context)*

Contributor guide

Open the contributing guide

Research direction

Start with op-service/metrics/rpc_metrics.go and the client and handler entry points in op-service/client/rpc.go, op-service/rpc/handler.go, and handler_options.go. Trace the existing recorder and JsonError uses, then inspect the related engine, sequencer, filter, stream, and metric tests. Done means no listed geth hook references remain, metric names and labels are unchanged, and the specified JSON-RPC error codes remain unchanged.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
backend-api-design, observability
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.