Releases: ajsutton/exec-rest-api
Release list
v1.0.0
v1.0.0 — first stable release
exec-rest-api is a single-binary REST + SSE proxy that sits in front of any Ethereum execution client (Geth, Nethermind, Erigon, Reth, anvil, …). It turns the JSON-RPC interface into a developer-friendly HTTP API: decimal numbers instead of hex, RFC 9457 problem details instead of {"error": {"code": -32000, …}}, RFC 8288 cursor pagination, content negotiation for raw RLP, and Server-Sent Event streams instead of a parallel WebSocket protocol.
This is the first tagged release intended for production use. The public surface — endpoints, response shapes, error types, SSE framing, configuration flags, headers, and /metrics series — is committed under semver for the 1.x line.
Endpoint surface
Chain & health
GET /chain,/chain/id,/chain/sync-status,/chain/client,/chain/peersGET /health,/health/ready
Blocks
GET /blocks/{id},/blocks/{id}/header,/blocks/{id}/transactions,/blocks/{id}/transactions/{index},/blocks/{id}/transaction-count,/blocks/{id}/receipts,/blocks/{id}/tracesPOST /blocks/{id}/traces/replay,/blocks/{id}/debug-traces
Accounts
GET /accounts/{addr}(composite),/accounts/{addr}/balance,/nonce,/code,/storage/{slot},/proof,/transaction-templatePOST /accounts/{addr}/proof/search
Transactions
GET /transactions/{hash},/transactions/{hash}/receipt,/transactions/{hash}/tracePOST /transactions(raw tx submission, JSON or RLP body),/transactions/{hash}/debug-trace
Logs & traces
GET /logs,POST /logs/search(paginated)GET /traces,POST /traces/search,GET /traces/{txHash}/{traceAddress}(paginated)
Computed reads
POST /call,/gas-estimate,/access-list,/simulatePOST /traces/call,/traces/call-many,/traces/raw-transaction,/traces/replay-transaction/{hash}POST /debug-traces/call
Gas
GET /gas/price,/gas/priority-fee,/gas/blob-base-fee,/gas/fee-history
Streams (SSE)
GET /streams/blocks,/streams/logs,/streams/pending-transactions,/streams/sync-status
Utilities & observability
POST /utils/keccak256GET /metrics(Prometheus text)
Design highlights
- No hex on the wire. Block numbers, gas, nonce, log index, etc. are JSON numbers when safe and decimal strings when they may exceed 2⁵³ (wei).
- RFC 9457 Problem Details for every error, including a discriminated
transaction-rejected/*family for mempool rejections and apath-not-supported404 that includes a catalogue of available URLs. - Reverts are not errors.
eth_call/eth_estimateGas/eth_simulateV1/ trace-call return200with{ "reverted": true, "data": "0x…", "reason": …, "panicCode": … }—Error(string)andPanic(uint256)are ABI-decoded for you. - EIP-7702 delegation detection.
GET /accounts/{addr}surfaces adelegatedTofield when the account holds the0xef0100-prefixed delegation marker. - Cursor pagination. Opaque base64url cursors for
/logsand/tracescarry the original filter, the frozentoBlock, and a boundary block hash for reorg detection (409 chain-reorged). Internal block-range chunking honours upstream caps automatically. - RLP content negotiation.
Accept: application/vnd.ethereum.rlpon/blocks/{id},/blocks/{id}/header,/blocks/{id}/receipts, and/transactions/{hash}returns raw bytes verbatim fromdebug_getRaw*.POST /transactionssymmetrically acceptsContent-Type: application/vnd.ethereum.rlp. - SSE multiplexing. One upstream
eth_subscribeper unique(kind, params)is fanned out to all client streams. WS reconnects re-issue subscriptions and emitevent: gap;Last-Event-IDreplay is supported for blocks and logs within a configurable window. Reorgs re-emit affected logs withremoved: true. - Per-request observability. Every response carries
X-Request-ID; non-streaming responses also carryX-Upstream-Method(the JSON-RPC method(s) the proxy invoked) andX-Block-Height(current chain head when known). - Prometheus metrics. Seven series cover HTTP request count/duration, upstream call count/duration, live SSE connections, live upstream subscriptions, and chain head block. Hand-written exporter — no client library dependency.
Operational footprint
- Single Python process; pure asyncio (aiohttp). One config flag is required (
--upstream-http); everything else has defensible defaults. - One runtime dependency:
aiohttp. No web framework, no ORM, no scheduler, no Prometheus client. - Structured JSON logging (auto-selected on non-TTY) with
request_id,method,path,status,latency_ms,upstream_method,upstream_latency_mson every line. - CLI flags and env vars are interchangeable (
--upstream-http↔EXEC_REST_API_UPSTREAM_HTTP); flags win.
Install
Four ways to run it:
pipx install exec-rest-api # PyPI (recommended)
pip install exec-rest-api # any virtualenv
# Single-file .pyz (Python 3.10+ on PATH)
curl -LO https://github.com/ajsutton/exec-rest-api/releases/download/v1.0.0/exec-rest-api.pyz
chmod +x exec-rest-api.pyz && ./exec-rest-api.pyz --upstream-http http://localhost:8545
# OCI image (multi-arch: linux/amd64, linux/arm64)
docker run --rm -p 8080:8080 ghcr.io/ajsutton/exec-rest-api:1.0.0 \
--upstream-http http://host.docker.internal:8545Supply-chain verification
All artefacts are signed via cosign keyless using GitHub Actions OIDC. A CycloneDX SBOM is attached.
# .pyz
cosign verify-blob \
--certificate exec-rest-api.pyz.crt --signature exec-rest-api.pyz.sig \
--certificate-identity 'https://github.com/ajsutton/exec-rest-api/.github/workflows/release.yml@refs/tags/v1.0.0' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
exec-rest-api.pyz
# OCI image
cosign verify \
--certificate-identity 'https://github.com/ajsutton/exec-rest-api/.github/workflows/release.yml@refs/tags/v1.0.0' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
ghcr.io/ajsutton/exec-rest-api:1.0.0See docs/operations.md for the hardened systemd unit, hardened docker run invocation, and Prometheus scrape config.
Compatibility
- Python 3.10, 3.11, 3.12 (verified in CI on ubuntu, macos, windows).
- Tested upstreams: Geth, Erigon, Reth, anvil. Any execution client implementing the standard
eth_*/web3_*/net_*/trace_*/debug_*JSON-RPC methods should work; methods the upstream doesn't implement surface as501 method-not-supported-by-upstream.
What's next
No breaking changes planned for 1.x. Bug fixes, additional content-negotiation representations, additional Prometheus series, and operator-side polish (improved JSON log fields, more granular metrics labels) are likely; the surface that's documented here will keep working.
v0.5.0
Full Changelog: https://github.com/ajsutton/exec-rest-api/commits/v0.5.0