Architecture Overview
Containment Chamber is a single statically-linked Rust binary that acts as an Ethereum remote signer. It exposes a Web3Signer-compatible HTTP API, enforces EIP-3076 slashing protection before every signature, and loads validator keys from multiple sources. A separate metrics server runs on port 3000 for Prometheus scraping.
System Architecture
Section titled “System Architecture”Request Flow
Section titled “Request Flow”A signing request follows this path through the system:
- Validator client sends
POST /api/v1/eth2/sign/{pubkey}with a JSON body describing the signing operation (attestation, block proposal, etc.) - Backpressure layers apply load shedding, concurrency limiting, and a 30-second timeout — if the system is overloaded, the request is rejected with
503before reaching any handler - Axum router matches the path and dispatches to the signing handler
- AuthPolicy extracts the HTTP Basic auth token, computes its HMAC-SHA256 hash, and checks scope, key, and operation permissions — unauthorized requests get
401/403 - Signing handler parses the JSON body into a
SigningRequestOwnedvariant, validates the public key format, and delegates toEthereumSigner - Signing semaphore limits concurrent signing operations to prevent resource exhaustion
- Network guard verifies the request’s genesis validators root matches the configured network — rejects cross-network requests
- Anti-slashing check calls
check_and_update()on the configured backend (PostgreSQL, SQLite, or DynamoDB) — if the operation would cause a slashable offense, it returns412 - BLS signing computes the domain, signing root, and produces the BLS signature using the keypair from the
KeyStore - Response returns
{"signature": "0x..."}with the hex-encoded BLS signature
The health endpoint (GET /upcheck) bypasses all backpressure layers and always responds, even under heavy load.
Key Sources
Section titled “Key Sources”Containment Chamber loads validator BLS keypairs from three sources, checked in order at startup:
-
Filesystem — EIP-2335 encrypted keystores (PBKDF2, Scrypt) or raw hex files loaded from one or more directories. Keys are decrypted in parallel using a CPU semaphore. Filesystem keys take precedence on pubkey collision.
-
DynamoDB + KMS — Keys stored in DynamoDB, encrypted with AES-256-GCM using a master key protected by Shamir secret sharing across multiple AWS KMS keys (M-of-N threshold). Supports background key refresh on a configurable interval.
-
Key Manager API — Hot-load and remove EIP-2335 keystores at runtime via
GET/POST/DELETE /eth/v1/keystores. Useful for dynamic validator scaling without restarts.
All three sources feed into the same in-memory KeyStore backed by a lock-free DashMap. Keys are wrapped in Arc for cheap concurrent access across async tasks.
Seal/Unseal State Machine
Section titled “Seal/Unseal State Machine”When the DynamoDB key source is configured, the signer operates a 6-state seal machine that controls whether signing is permitted. The master key only exists in memory during the Unsealed and AwaitingRotation states — all other states reject signing requests.
The six states are: Uninitialized, Sealed, AwaitingUnseal, Unsealed, AwaitingRotation, and Rotating. Transitions are driven by operator actions (init ceremony, unseal share submissions, seal commands) and by the signer itself (threshold reached, rotation complete).
Filesystem-only deployments bypass the seal machine entirely. The state machine only activates when key_sources.dynamodb is configured.
For the full state diagram, transition rules, and operational procedures, see Seal & Unseal.