Architecture

The gateway

The gateway is the network-access layer that sits between the untrusted public internet and the chain. It is three components glued together by docker-compose.yml:

Why a gateway and not expose the chain directly? Three reasons: (1) rate limiting per IP for the public JSON-RPC, (2) batched-call cap to prevent JSON-RPC amplification, (3) a normalized read API in front of the chain for wallets that should not parse EVM logs directly.

At a glance

RPC proxy OpenResty (nginx + Lua) on :8080
Indexer Node.js, polls every 1.5s, writes to Postgres
Read API Node.js on :3000
Database PostgreSQL 15 ("SyncDB")
Rate limit per-IP token bucket, configurable
Batch cap configurable, blocks eth_sendRawTransaction inside batches

The three pieces

RPC proxy (:8080)

  • Forwards eth_* calls to the chain JSON-RPC.
  • Per-IP rate limit (token bucket) — see gateway/openresty/conf/rate-limit.conf.
  • Batch-call cap: more than N calls in a single batch ? rejected.
  • The debug_* namespace is hard-blocked at the proxy.
  • The eth_sendRawTransaction is allowed but the proxy strips the from and forces a re-check of nonce and gasPrice against the chain before forwarding.

Indexer

  • Polls eth_getBlockByNumber("latest") every 1.5 seconds.
  • For each new block: writes block, transactions, receipts, logs, and an internal-token-transfer row.
  • Idempotent: re-indexing the same block is a no-op.
  • Backfill mode for first start: walks from genesis to tip before tailing.

Read API (:3000)

  • HTTP/JSON for the wallet and the explorer.
  • Endpoints: /v1/address/{addr}/balance, /v1/address/{addr}/txs, /v1/tx/{hash}, /v1/block/{n}.
  • No write endpoints. The gateway never holds keys.

What is and is not in the gateway

No key custody. The gateway never has a private key. The wallet signs, the gateway forwards.
No transaction submission from the API. The read API does not accept eth_sendRawTransaction. Transactions always come in through the RPC proxy so the rate limit and batch cap apply.
The Blockscout instance is not part of the gateway. It is a separate explorer/ service that reads from the chain directly, not from SyncDB.