Skip to content
Holits

Blockchain Infrastructure

Ethereum RPC Router

An intelligent load balancer for Ethereum RPC nodes with canonical-data guarantees, re-org detection, client-aware routing and native WebSocket proxying.

By Holits

The problem

A generic load balancer in front of Ethereum nodes is wrong in ways that don't show up until they matter:

  • Tiers differ. Minimal, full and archive nodes answer different subsets of the API. Routing to the wrong tier fails, or worse, returns partial data.
  • Clients differ. Some methods exist only on Erigon (erigon_*, ots_*). txpool_status and txpool_inspect work on Geth and Reth, but Erigon only supports txpool_content.
  • Lag is invisible. A node a few blocks behind returns a well-formed answer that is simply out of date, and the caller cannot tell.
  • Re-orgs happen. Without hash tracking you can serve a block from a fork that has been abandoned.
  • Sessions are stateful. Filters and subscriptions belong to the node that created them, and break the instant a balancer moves them.
  • Archive capacity is expensive. Sending light queries to archive nodes wastes the costliest hardware you own.

The approach

A Node Weighter middleware sits behind HAProxy and makes routing a function of the request rather than of connection counts.

Method classification. Every RPC method is categorised by cost and by the capability it requires, then routed to the cheapest tier that can serve it correctly. Light methods prefer minimal nodes.

Canonical fallback. When the preferred tier falls more than two blocks behind, the router escalates to the node with the highest block height — so cost optimisation never silently costs you correctness.

Client capability filtering. Nodes are probed via web3_clientVersion and their client type is detected automatically. Erigon-only methods never reach a Geth node.

Re-org detection. Block hashes are tracked across nodes so responses from an abandoned fork are identified rather than served as canonical.

Unknown block probing. When no node obviously holds a requested block, nodes are probed in an order derived from what they are likely to have, instead of fanning out blindly.

WebSocket handling

JSON-RPC received over WebSocket is forwarded to nodes over WebSocket, rather than being translated into HTTP requests. That removes the HTTP round-trip overhead for subscription-heavy clients while keeping method-aware routing. Filter sessions (eth_newFilter and friends) retain affinity to their originating node.

Observability

Routing is only trustworthy if it is measurable. The router exports:

  • haproxy_eth_routing_decisions_total, labelled by method
  • haproxy_eth_tier_fallback_total, labelled by source tier, target tier and reason
  • haproxy_eth_websocket_rpc_forwards_total by method, node and status
  • haproxy_eth_websocket_rpc_duration_seconds as a round-trip histogram

The method allowlist is maintained deliberately so metrics never degrade into unknown_* buckets — a dashboard that silently stops describing your traffic is worse than no dashboard.

Also in the box

Full JSON-RPC 2.0 compliance including notification handling and batch limits, rate limiting and authentication, and multi-tenant isolation.

Case study

See this router in production: Making Ethereum RPC correct under load and re-orgs.

Availability

This project is not currently public. We are happy to walk through the routing design and the re-org handling in detail.