rpc-doctor
v0.1.0
Published
Diagnose any EVM JSON-RPC endpoint: freshness vs chain tip, method support, archive depth, getLogs caps, WebSocket health, latency. Find out why your RPC endpoint is lying to you.
Maintainers
Readme
rpc-doctor
Diagnose any EVM JSON-RPC endpoint in one command. Find out why your RPC endpoint is lying to you.
npx rpc-doctor https://ethereum-rpc.publicnode.comIdentity
chain 1 (Ethereum)
client Geth/v1.17.1-stable/linux-amd64
Freshness
latest block 25,830,788 (15s old)
status at tip
Method support
eth_getBlockReceipts yes
eth_getProof yes
debug_traceCall no
...
Historical state
state at block 1 pruned (Archive requests require a personal token...)
Verdict: HEALTHYWhy
RPC endpoints fail in ways that look like your bug:
- A node can respond fast and still be hours behind the chain tip —
eth_syncing: falsedoesn't mean synced, it also means "not even trying." A liveness check is not a freshness check. - Public endpoints silently restrict methods: no
debug_/trace_,eth_getLogsrange caps, archive state gated behind a paid tier — and the errors ("method not found", "missing trie node") read like application bugs. - Archive depth varies wildly: "full node" means recent state only, and where the pruning horizon sits is almost never documented.
- WebSocket endpoints can accept connections and then silently deliver nothing.
rpc-doctor probes all of it in ~30 seconds and gives you a verdict.
Checks
| Section | What it does |
|---|---|
| Identity | eth_chainId (mapped to a chain name) + client version |
| Freshness | latest block age vs wall clock; stall detection; optional --reference <url> cross-check |
| Latency | 5× eth_blockNumber, min/median/max |
| Method support | eth_getBlockReceipts, eth_feeHistory, eth_getProof, eth_createAccessList, debug_traceCall, trace_block, txpool_status, JSON-RPC batching |
| getLogs behavior | small-range and 10k-block queries, with the endpoint's actual error text when capped |
| Historical state | archive probe at block 1; --deep binary-searches the pruning horizon |
| CORS | preflight check — can a browser app call this endpoint? |
| WebSocket | connect, eth_subscribe newHeads, time-to-first-head (--ws <url> or a wss:// URL) |
Options
--json machine-readable output (CI-friendly; exit code 0/1/2 = healthy/degraded/unhealthy)
--deep binary-search the archive/pruning horizon (~15 extra calls)
--ws <url> also test a WebSocket endpoint
--reference <url> cross-check the chain tip against a second endpoint
--gap <ms> pacing between requests (default 350ms — polite to rate-limited free tiers)Notes
- No telemetry. Every request goes only to the URL(s) you pass. Nothing is phoned home.
- Probes are read-only and paced; a single run is ~25 requests. On 429 it waits and retries once.
- "yes" for a method means the node has it wired up — including cases where it answers with a state/param rejection (that still proves the method exists). "no" means the method is missing or disabled.
Background reading
Each check is described in depth on the SwiftNodes engineering blog: stale endpoints · getLogs range caps · eth_getProof · what "free RPC" really gets you · full vs archive nodes
Maintained by SwiftNodes — flat-rate RPC for 75+ chains. MIT licensed.
