Skip to content

iamkunal9/singleRPC

Repository files navigation

       .__               .__        _____________________________  
  _____|__| ____    ____ |  |   ____\______   \______   \_   ___ \ 
 /  ___/  |/    \  / ___\|  | _/ __ \|       _/|     ___/    \  \/ 
 \___ \|  |   |  \/ /_/  >  |_\  ___/|    |   \|    |   \     \____
 /____  >__|___|  /\___  /|____/\___  >____|_  /|____|    \______  /
      \/        \/_____/           \/       \/                  \/ 

                                                            iamkunal9.in

Robust, blazing-fast single RPC for multiple chains with smart load balancing, health checks, continuous retries, and per-request timeouts built in.

Features

  • Hyper v1 + hyper-util async server
  • Reqwest client for outbound requests
  • Round-robin load balancing with simple failure backoff and health tracking
  • Continuous retry across endpoints (no 503) until a healthy response is obtained
  • Per-request timeout (default 5s, configurable with -t)
  • Verbose logging levels with -v/-vv
  • CLI flags for config, port, timeout, verbosity
  • Library API for embedding the same routing/failover logic in another Rust process

Install

One-liner (downloads the latest release for macOS or Linux and drops the singlerpc binary into /usr/local/bin, falling back to ~/.local/bin if not writable):

curl -fsSL https://raw.githubusercontent.com/iamkunal9/singleRPC/refs/heads/main/install.sh | bash

Or build from source:

cargo install --path .

Already installed? Upgrade in place:

singlerpc --update

Usage

singlerpc -c path/to/config.json -p 3000

# with custom timeout (seconds)
singlerpc -c config.json -p 3000 -t 10

# verbose logs: endpoints and statuses
singlerpc -c config.json -v

# very verbose: also prints upstream response body
singlerpc -c config.json -vv

# lock the proxy behind a token (clients must send the same token)
singlerpc -c config.json -a supersecret
  • -c, --config : Path to JSON config mapping chain IDs to arrays of RPC URLs
  • -p, --port : Port to listen on (default: 3000)
  • -t, --timeout : Per-RPC request timeout (default: 5)
  • -a, --auth : Require clients to include the matching token (via Authorization: Bearer <token>, X-SingleRPC-Auth: <token>, or ?auth=<token>); omit to keep the proxy open
  • --health-file : Persist hard-dead endpoint health in this file (default: ~/.singlerpc/health.json)
  • --no-health-file: Keep endpoint health in memory only
  • -v: Log incoming JSON, endpoint URL, and upstream status
  • -vv: Also log upstream response body
  • -h, --help: Show help
  • -V, --version: Show version

Library usage

singlerpc can also be embedded as a Rust library, so another daemon can reuse the Chainlist-backed routing and failover without running a separate HTTP server.

use singlerpc::{DEFAULT_CONFIG_JSON, RpcProxy, load_config_from_str};
use serde_json::json;
use std::time::Duration;

# async fn example() -> Result<(), Box<dyn std::error::Error>> {
let chains = load_config_from_str(DEFAULT_CONFIG_JSON)?;
let proxy = RpcProxy::with_timeout(chains, 0, Duration::from_secs(10), None);

let response = proxy.request_json("1", json!({
    "jsonrpc": "2.0",
    "id": 1,
    "method": "eth_chainId",
    "params": []
})).await?;

assert_eq!(response["result"], "0x1");
# Ok(())
# }

The CLI still uses the same library internally.

The bundled Chainlist snapshot includes both mainnets and testnets. Use a custom config file if you want to restrict routing to a smaller set.

Config format

Example config.json:

{
  "eth-mainnet": [
    "https://rpc1.example.com",
    "https://rpc2.example.com"
  ],
  "polygon": [
    "https://polygon-rpc.example.com"
  ]
}

Notes

  • The proxy rotates through endpoints in a round-robin loop. If all fail in a pass, it keeps retrying (with short sleeps) until one succeeds.
  • JSON-RPC error objects from a healthy upstream are returned to the caller immediately. They are transaction or method errors, not endpoint health failures.
  • 429 rate-limit responses get a short in-memory cooldown and are retried later without being persisted as dead.
  • Hard endpoint failures such as timeouts, connect errors, body read errors, 5xx responses, or invalid upstream responses are marked dead after 3 consecutive failures. The CLI persists hard-dead endpoints for 24 hours in ~/.singlerpc/health.json by default, then retries them.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the MIT License - see the LICENSE file for details.

About

Robust, blazing-fast single RPC for multiple chains with smart load balancing, health checks, continuous retries, and per-request timeouts built in.

Topics

Resources

License

Stars

Watchers

Forks

Contributors