Architecture

System architecture

Prism RPC sits between your application and every Robinhood Chain provider you would otherwise integrate one at a time. This is what happens inside.

your appeth_callprismRPCroute · retry · breakAlchemy41 msQuickNode38 msAnkr52 msChainstackcircuit openPublic node96 ms

Layers

L1

Edge

  • TLS termination in every region you call from
  • API key validation and method allowlisting
  • Per-key token buckets and burst allowances
  • JSON-RPC envelope and batch parsing
L2

Balancer core

  • Routing engine with four selectable strategies
  • Per-provider circuit breakers with half-open probing
  • Retry policy with exponential backoff and full jitter
  • In-flight deduplication and deterministic-result cache
L3

Transport

  • Keep-alive HTTP pools per upstream
  • WebSocket manager with automatic reconnection
  • Subscription registry replayed after a reconnect
  • Response validation and block-height drift checks
L4

Upstreams

  • Commercial providers: Alchemy, QuickNode, Ankr, Chainstack
  • Public Robinhood Chain nodes as overflow capacity
  • Optional private nodes you bring yourself
  • Independent health state per upstream and per region

Request flow

A cache miss on a read, routed to the fastest healthy upstream. Timings are representative of a warm pool.

  1. 1

    Request received

    Key validated, method allowlist checked

    0.08 ms
  2. 2

    Cache lookup

    Deterministic results answered immediately

    0.04 ms
  3. 3

    Dedupe

    Identical in-flight read joined instead of re-sent

    0.02 ms
  4. 4

    Provider selected

    Healthy upstreams ranked by rolling p50

    0.11 ms
  5. 5

    Upstream call

    JSON-RPC forwarded, response validated

    38 ms
  6. 6

    Metrics recorded

    Latency, status and breaker state updated

    0.03 ms

Failure isolation

Each upstream carries its own breaker. One provider degrading never becomes your outage.

Closed

Traffic flows. Prism counts failures in a rolling window.

5 failures in 30s →

Open

The provider is removed from the pool. Requests reroute instantly.

after 15s cooldown →

Half-open

A single probe request is allowed through to test recovery.

probe succeeds → Closed

Retries and breakers share one rule: a request is only replayed when replaying it is safe. Reads are retried across providers freely; anything that submits a transaction is sent exactly once, to one upstream, and its failure is returned to you verbatim rather than being silently duplicated.

policy defaults
{
  "retry": {
    "maxAttempts": 3,
    "baseDelayMs": 120,
    "maxDelayMs": 2000,
    "jitter": "full",
    "retryOn": ["timeout", "5xx", "429", "connection-reset"],
    "neverRetry": ["eth_sendRawTransaction"]
  },
  "breaker": {
    "failureThreshold": 5,
    "windowMs": 30000,
    "cooldownMs": 15000,
    "halfOpenProbes": 1
  }
}

Observability

Every routing decision is recorded. The same numbers Prism uses to pick a provider are the ones you see.

Provider health

live
Providerp50p99SuccessShare
Alchemy41 ms118 ms99.98%34%
QuickNode38 ms104 ms99.99%38%
Ankr52 ms191 ms99.81%19%
Chainstackbreaker open--87.40%0%
Public node96 ms402 ms99.20%9%
Metrics reference