relayer/README.md
The Relayer is the bridge between fhevm host chains (e.g. Ethereum) and the Gateway.
It exposes the following capabilities:
The system follows an event-driven architecture with these key components:
flowchart TD
HTTP["HTTP API (v2)"] -->|request| ORCH
GWL["Gateway Listener (WSS)"] -->|blockchain event| ORCH
subgraph Orchestrator
ORCH[Event Router] --> HOOKS[Hooks
persistence · logging · metrics]
HOOKS --> DISP[Dispatcher]
end
DISP --> HANDLERS[Event Handlers
InputProof · PublicDecrypt · UserDecrypt · KeyUrl]
HANDLERS -->|send TX| GW[Gateway Blockchain]
GW -->|response event| GWL
HANDLERS -->|chain event| ORCH
HOOKS -.->|store state| DB[(PostgreSQL)]
HTTP -.->|poll status| DB
src
├── bin/ # Binary entry points
│ └── fhevm-relayer.rs # Main relayer service binary
├── config/ # Configuration loading and validation
├── core/ # Core domain events, IDs, and shared types
├── gateway/ # Gateway listeners, handlers, and tx engine
│ ├── arbitrum/ # Arbitrum listener and transaction processing
│ └── readiness_check/ # Readiness-check processing pipeline
├── http/ # HTTP server, API handlers, and middleware
│ ├── admin/ # Runtime admin endpoints
│ ├── endpoints/ # API implementations (common, v2)
│ ├── middleware/ # OpenAPI/docs and request middleware
│ ├── retry_after/ # Dynamic Retry-After estimation
│ └── utils/ # Parsing and validation helpers
├── logging/ # Structured logging helpers
├── metrics/ # Prometheus metrics and dashboard docs
├── orchestrator/ # Event orchestration system
├── store/sql/ # SQL models and repositories
├── lib.rs # Library entry point
├── startup.rs # Service startup wiring
├── startup_recovery.rs # Startup recovery orchestration
└── tracing.rs # Tracing initialization
relayer-migrate/ # Separate crate: DB migrations with connection retry and rollback support
config/local.yaml.example # Local config template
dev/docker-compose.yaml # Local Postgres compose
tests/ # Integration and API tests
test-support/ # Test helpers (e.g. Ethereum RPC mock)
docs/ # Supplemental project documentation
design-docs/ # Design and architecture notes
openapi-async-design.yaml # OpenAPI specification
Makefile # Test, lint, and migration helpers
cast) -- only needed for network onboarding (make preflight-*, make mint-zama-*, make approve-payment-*)make api-lint only)Run make help to see all available targets.
Configuration is handled via:
config/local.yaml by default if present)--config-file)APP_ prefix and __ for nesting (override file values)
APP_GATEWAY__BLOCKCHAIN_RPC__HTTP_URL=https://rpc.example.orgFor full deployment instructions, security considerations, and production configuration, see the Self-Hosting Guide.
The quickstart sections below cover the minimum steps to get a relayer running against Mainnet or Testnet.
make db-start # Start local Postgres (Docker Compose, port 5433)
make db-migrate # Apply database migrations
make preflight-mainnet # Interactive: config, private key, balance checks, approval
make run-mainnet # Start the relayer
make health # Verify health endpoints
make db-start # Start local Postgres (Docker Compose, port 5433)
make db-migrate # Apply database migrations
make preflight-testnet # Interactive: config, private key, balance checks, approval
make run-testnet # Start the relayer
make health # Verify health endpoints
For build, test, lint, local stack, and CI instructions, see docs/DEVELOPMENT.md. For contribution guidelines, see CONTRIBUTING.md.
make setup is the dev-oriented shortcut (db-start + db-migrate + copies local mock config).
| Endpoint | Description |
|---|---|
GET /liveness | Liveness probe |
GET /healthz | Readiness / health check |
GET /version | Build version info |
GET /docs | OpenAPI documentation |
Ciphertext endpoints follow async job semantics: POST submits a request and returns a job_id, then GET .../{job_id} polls for the result.
| Operation | Endpoint |
|---|---|
| Input proof verification | POST /v2/input-proof |
| Public decryption | POST /v2/public-decrypt |
| User decryption | POST /v2/user-decrypt |
| Delegated user decryption | POST /v2/delegated-user-decrypt |
| Key material URLs | GET /v2/keyurl |
For complete schemas, see GET /docs or openapi-async-design.yaml.
GET /admin/config
POST /admin/config
Controlled by enable_admin_endpoint (returns 403 Forbidden when disabled). Supports runtime tuning of throttler TPS and retry-after fields. Primarily intended for testing and benchmarking.
Note. These endpoints are disabled by default and intentionally have no application-level authentication. When enabling them, restrict reachability via network-level controls — bind
http.endpointto loopback or an internal subnet, or place the endpoint behind an authentication layer.
LOGGING_POLICY.mdsrc/metrics/docs_and_dashboards/http_metrics.mdGET /metrics on port 9898A background worker marks requests stuck in receipt_received status as timed_out when the gateway chain has not responded within the configured timeout window.
This worker is always enabled and runs as a background cron job implemented in src/store/sql/repositories/timeout_repo.rs.
The timeout durations are configurable per request type in the cron section of your configuration:
| Config key | Default | Description |
|---|---|---|
storage.cron.timeout_cron_interval | 60s | How often the worker checks for stale requests |
storage.cron.public_decrypt_timeout | 30m | Timeout for public decryption requests |
storage.cron.user_decrypt_timeout | 30m | Timeout for user decryption requests |
storage.cron.input_proof_timeout | 30m | Timeout for input proof requests |
The relayer can purge stale request data from the database to manage storage growth.
Old records for public decryption, user decryption, and input proof verification are periodically deleted based on configurable retention windows.
This cleanup process runs as a background cron job implemented in src/store/sql/repositories/expiry_repo.rs.
The expiry worker is disabled by default.
Stale data can be purged manually by running the equivalent DELETE queries against the database directly.
To enable automatic cleanup instead, set expiry_enabled: true in the cron section of your configuration,
and ensure the relayer's database user has DELETE permission on the relevant tables.
The local Postgres in dev/docker-compose.yaml maps to port 5433 to avoid conflicts. If you see "connection refused" errors, check you are targeting port 5433.
The Docker build relies on pre-computed query metadata in .sqlx/. After adding or modifying SQL queries, run make sqlx-prepare before building Docker images.
The relayer Dockerfile mounts .git/HEAD, .git/objects, and .git/refs for build-time version embedding. In a Git worktree .git is a file (not a directory), so the mount fails. Build from a primary clone instead.
config/local.yaml.example ships with localhost:8757 RPC URLs and 0.0.0.0:3001 key URLs that only work against a local mock stack. When targeting Testnet or Mainnet, use make preflight-testnet / make preflight-mainnet which copies the correct example config automatically.
Running ./fhevm-cli deploy requires at least 12 GB of Docker memory.
BSD 3-Clause Clear License