ethereum-optimism / ethereum-optimism/optimism
opgeth-decoupling: re-home the RPC recording hooks (recorder seam + rpc.JsonError)
- 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
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