From a663b8b64cb014c211c49600ef051dde04711d9e Mon Sep 17 00:00:00 2001 From: Justin Taylor <26264269+sjustintaylor@users.noreply.github.com> Date: Thu, 16 Oct 2025 11:08:10 +1000 Subject: [PATCH 1/7] wip --- .dockerignore | 63 ++++++++++++++++++++++++++++++++ Dockerfile | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..eecff2a --- /dev/null +++ b/.dockerignore @@ -0,0 +1,63 @@ +# Build artifacts +target/ +*.profraw +coverage/ + +# Git +.git/ +.gitignore +.github/ + +# IDE and editor files +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# Documentation +*.md +!README.md +spec/ +docs/ + +# Test files +tests/ +mock-relay/ +mock-services/ + +# Environment and secrets (NEVER include in Docker image) +.env +.env.example +*.pem +*.key +test-keys.sh +test-keys.sh.example + +# SQLx offline query cache (built during compile) +.sqlx/ + +# Cargo Husky git hooks +.cargo-husky/ + +# CI/CD +.github/ + +# Claude AI +.claude/ + +# Docker files (no need to copy into image) +docker-compose.yml +Dockerfile +.dockerignore + +# Task runner +Taskfile.yml + +# Development scripts +scripts/ + +# Misc +*.log +*.bak +plan.md diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..bd84904 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,99 @@ +# ============================================================================ +# Stage 1: Builder +# ============================================================================ +FROM rust:1.90-slim AS builder + +# Install build dependencies +RUN apt-get update && apt-get install -y \ + build-essential \ + libpq-dev \ + pkg-config \ + libssl-dev \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +# Set working directory +WORKDIR /build + +# Copy dependency manifests first for better layer caching +# This allows Docker to cache dependencies if only source code changes +COPY Cargo.toml Cargo.lock ./ + +# Copy source code +COPY src ./src +COPY migrations ./migrations +COPY rustfmt.toml ./ + +# Build the application in release mode +# --locked ensures Cargo.lock is used exactly as specified +# --release enables optimizations for production +RUN cargo build --release --locked + +# ============================================================================ +# Stage 2: Runtime +# ============================================================================ +FROM debian:bookworm-slim AS runtime + +# Install runtime dependencies +# libpq5: PostgreSQL client library +# ca-certificates: Required for HTTPS connections to external APIs +RUN apt-get update && apt-get install -y \ + libpq5 \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +# Create a non-root user for security +RUN useradd -m -u 1000 -s /bin/bash gateway + +# Set working directory +WORKDIR /app + +# Copy the compiled binary from builder stage +COPY --from=builder /build/target/release/preconfirmation-gateway ./preconfirmation-gateway + +# Copy migrations directory (required for automatic migration on startup) +COPY --from=builder /build/migrations ./migrations + +# Copy configuration file +COPY config.toml ./config.toml + +# Change ownership to non-root user +RUN chown -R gateway:gateway /app + +# Switch to non-root user +USER gateway + +# Expose ports +# 8080: JSON-RPC server port +# 9090: Prometheus metrics endpoint +EXPOSE 8080 9090 + +# Health check (optional but recommended) +# Checks if the metrics endpoint is responding +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD curl -f http://localhost:9090/metrics || exit 1 + +# Set entrypoint +ENTRYPOINT ["./preconfirmation-gateway"] + +# ============================================================================ +# Build instructions: +# docker build -t preconfirmation-gateway:latest . +# +# Run instructions: +# docker run -p 8080:8080 -p 9090:9090 \ +# -e DATABASE_URL="postgresql://user:pass@host:5432/db" \ +# -e BEACON_API_ENDPOINT="https://beacon-api.example.com" \ +# -e COMMITTER_PRIVATE_KEY="your_ecdsa_key" \ +# -e BLS_PRIVATE_KEY="your_bls_key" \ +# preconfirmation-gateway:latest +# +# Required environment variables: +# - DATABASE_URL: PostgreSQL connection string +# - BEACON_API_ENDPOINT: Beacon API endpoint URL +# - COMMITTER_PRIVATE_KEY: ECDSA private key (64 hex chars, no 0x prefix) +# - BLS_PRIVATE_KEY: BLS private key (64 hex chars, no 0x prefix) +# +# Optional environment variables: +# - RUST_LOG: Logging level (default: info) +# ============================================================================ From 3f8b86d521dc5ffeb6b92b0e3034ba8bcc950656 Mon Sep 17 00:00:00 2001 From: Justin Taylor <26264269+sjustintaylor@users.noreply.github.com> Date: Thu, 16 Oct 2025 11:08:11 +1000 Subject: [PATCH 2/7] wip --- Taskfile.yml | 57 ++++++++++++++++++++++++++++++++++++++++++++++ docker-compose.yml | 26 +++++++++++++++++++-- 2 files changed, 81 insertions(+), 2 deletions(-) diff --git a/Taskfile.yml b/Taskfile.yml index 16dd16b..a42f8f5 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -53,3 +53,60 @@ tasks: desc: "Wipes and migrates the database" cmds: - cargo sqlx database reset -yf + + docker:build: + desc: "Build Docker image" + cmds: + - docker build -t preconfirmation-gateway:latest . + + docker:run: + desc: "Run Docker container with environment variables from .env" + cmds: + - | + docker run -p 8080:8080 -p 9090:9090 \ + -e DATABASE_URL="${DATABASE_URL}" \ + -e BEACON_API_ENDPOINT="${BEACON_API_ENDPOINT}" \ + -e COMMITTER_PRIVATE_KEY="${COMMITTER_PRIVATE_KEY}" \ + -e BLS_PRIVATE_KEY="${BLS_PRIVATE_KEY}" \ + -e RUST_LOG="${RUST_LOG:-info}" \ + preconfirmation-gateway:latest + + docker:compose:up: + desc: "Start all services with docker-compose" + cmds: + - docker-compose up -d + + docker:compose:down: + desc: "Stop all services" + cmds: + - docker-compose down + + docker:compose:logs: + desc: "View logs from all services" + cmds: + - docker-compose logs -f + + docker:compose:logs:gateway: + desc: "View logs from gateway service only" + cmds: + - docker-compose logs -f gateway + + docker:compose:restart: + desc: "Restart all services" + cmds: + - docker-compose restart + + docker:compose:restart:gateway: + desc: "Restart gateway service only" + cmds: + - docker-compose restart gateway + + docker:compose:rebuild: + desc: "Rebuild and restart gateway service" + cmds: + - docker-compose up -d --build gateway + + docker:compose:ps: + desc: "Show status of all services" + cmds: + - docker-compose ps diff --git a/docker-compose.yml b/docker-compose.yml index 110417b..2e47907 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -28,12 +28,34 @@ services: PGADMIN_DEFAULT_EMAIL: admin@preconf.local PGADMIN_DEFAULT_PASSWORD: admin ports: - - "8080:80" + - "8081:80" depends_on: - - postgres + postgres: + condition: service_healthy volumes: - pgadmin_data:/var/lib/pgadmin + gateway: + build: + context: . + dockerfile: Dockerfile + container_name: preconf_gateway + restart: unless-stopped + ports: + - "8080:8080" # JSON-RPC API + - "9090:9090" # Prometheus metrics + environment: + DATABASE_URL: postgresql://postgres:postgres@postgres:5432/preconfirmation_gateway + BEACON_API_ENDPOINT: ${BEACON_API_ENDPOINT} + COMMITTER_PRIVATE_KEY: ${COMMITTER_PRIVATE_KEY} + BLS_PRIVATE_KEY: ${BLS_PRIVATE_KEY} + RUST_LOG: ${RUST_LOG:-info} + depends_on: + postgres: + condition: service_healthy + volumes: + - ./config.toml:/app/config.toml:ro + volumes: postgres_data: pgadmin_data: \ No newline at end of file From 420bbe579685c7235fe3f1030b4b63170794909a Mon Sep 17 00:00:00 2001 From: Justin Taylor <26264269+sjustintaylor@users.noreply.github.com> Date: Thu, 16 Oct 2025 15:58:18 +1000 Subject: [PATCH 3/7] wip --- .env.example | 74 ++++++++++++++++++++++++++++++++++++---------- .gitignore | 1 + config.toml | 6 ++-- docker-compose.yml | 6 ++++ src/config.rs | 10 ++++--- 5 files changed, 76 insertions(+), 21 deletions(-) diff --git a/.env.example b/.env.example index 50247f8..fd510e7 100644 --- a/.env.example +++ b/.env.example @@ -1,27 +1,71 @@ -# Environment variables for preconfirmation gateway -# Copy this file to .env and fill in your values +# ============================================================================ +# Environment Variables for Preconfirmation Gateway +# ============================================================================ +# This file is for LOCAL DEVELOPMENT (connecting to localhost services) +# For Docker deployment, use .env.docker instead +# +# SETUP INSTRUCTIONS: +# 1. Copy this file: cp .env.example .env +# 2. Fill in the REQUIRED variables marked below +# 3. The gateway will fail to start if required variables are missing +# ============================================================================ -# Database connection -DATABASE_URL=postgresql://postgres:postgres@localhost:5432/preconfirmation_gateway -TEST_DATABASE_URL=postgresql://postgres:postgres@localhost:5432/preconfirmation_gateway_test +# ============================================================================ +# REQUIRED VARIABLES - Gateway will NOT start without these +# ============================================================================ # Beacon API endpoint (REQUIRED) -# Example for Alchemy: https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY -# Example for Infura: https://mainnet.infura.io/eth/v1/YOUR_PROJECT_ID +# The gateway validates this on startup and will fail if not properly configured +# Examples: +# - Alchemy: https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY +# - Infura: https://mainnet.infura.io/eth/v1/YOUR_PROJECT_ID +# - Local: http://localhost:5052 BEACON_API_ENDPOINT=https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY -# ECDSA signing private key (hex string without 0x prefix, 64 hex characters) -# REQUIRED: The gateway will fail to start without this variable -# Generate with: cast wallet new (or use Hardhat account #0 for testing) +# ECDSA signing private key (REQUIRED) +# Format: 64 hex characters (32 bytes), without 0x prefix +# Used for commitment signing +# Generate with: +# - cast wallet new +# - Hardhat account #0 for testing: ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 +# SECURITY WARNING: Never commit your real private key to git! COMMITTER_PRIVATE_KEY=YOUR_ECDSA_PRIVATE_KEY_HERE -# BLS private key for constraint signing (hex string without 0x prefix, 64 hex chars) -# REQUIRED: The gateway will fail to start without this variable +# BLS private key (REQUIRED) +# Format: 64 hex characters (32 bytes), without 0x prefix +# Used for constraint signing # Generate with: openssl rand -hex 32 +# SECURITY WARNING: Never commit your real private key to git! BLS_PRIVATE_KEY=YOUR_BLS_PRIVATE_KEY_HERE -# Logging level +# ============================================================================ +# DATABASE CONFIGURATION - Local development uses localhost +# ============================================================================ + +# Database connection for local development +# For Docker: This is overridden in docker-compose.yml to use container network +DATABASE_URL=postgresql://postgres:postgres@localhost:5432/preconfirmation_gateway + +# Test database connection (used by test suite) +TEST_DATABASE_URL=postgresql://postgres:postgres@localhost:5432/preconfirmation_gateway_test + +# ============================================================================ +# OPTIONAL VARIABLES +# ============================================================================ + +# Logging level (default: info) +# Options: trace, debug, info, warn, error RUST_LOG=info -# Optional: Custom configuration file path -# CONFIG_FILE=config.toml \ No newline at end of file +# Custom configuration file path (default: config.toml) +# CONFIG_FILE=config.toml + +# ============================================================================ +# ADDITIONAL ENDPOINTS (Optional - can be configured in config.toml) +# ============================================================================ + +# Reth node RPC endpoint (optional override) +# RETH_ENDPOINT=http://localhost:8545 + +# Constraints API relay endpoint (optional override) +# CONSTRAINTS_API_ENDPOINT=http://localhost:3501 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 2a754e8..d865e60 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ target #.idea/ .env +.env.docker plan.md scratch.md diff --git a/config.toml b/config.toml index d3e786e..4f36613 100644 --- a/config.toml +++ b/config.toml @@ -3,8 +3,10 @@ [server] # Server binding configuration -host = "127.0.0.1" # IP address to bind the server to -port = 8080 # Port number for the JSON-RPC server +# Use 0.0.0.0 to bind to all network interfaces (required for Docker/container deployments) +# Use 127.0.0.1 for local-only access +host = "0.0.0.0" # IP address to bind the server to +port = 8080 # Port number for the JSON-RPC server [database] # Database connection configuration diff --git a/docker-compose.yml b/docker-compose.yml index 2e47907..c33344f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -44,7 +44,13 @@ services: ports: - "8080:8080" # JSON-RPC API - "9090:9090" # Prometheus metrics + # Load environment variables from .env.docker file + # Variables can still be overridden by explicit environment entries below + env_file: + - .env.docker environment: + # Override specific variables if needed + # These take precedence over .env.docker values DATABASE_URL: postgresql://postgres:postgres@postgres:5432/preconfirmation_gateway BEACON_API_ENDPOINT: ${BEACON_API_ENDPOINT} COMMITTER_PRIVATE_KEY: ${COMMITTER_PRIVATE_KEY} diff --git a/src/config.rs b/src/config.rs index 4168f08..cb064ff 100644 --- a/src/config.rs +++ b/src/config.rs @@ -137,12 +137,13 @@ impl std::fmt::Debug for SigningConfig { } impl Default for ServerConfig { - /// Creates a default ServerConfig with host "127.0.0.1" and port 8080. + /// Creates a default ServerConfig with host "0.0.0.0" and port 8080. + /// Binds to all network interfaces by default (required for container deployments). /// /// # Examples /// fn default() -> Self { - Self { host: "127.0.0.1".to_string(), port: 8080 } + Self { host: "0.0.0.0".to_string(), port: 8080 } } } @@ -669,7 +670,7 @@ mod tests { #[test] fn test_server_config_default() { let config = ServerConfig::default(); - assert_eq!(config.host, "127.0.0.1"); + assert_eq!(config.host, "0.0.0.0"); assert_eq!(config.port, 8080); } @@ -755,7 +756,7 @@ mod tests { assert!(result.is_ok()); let config = result.unwrap(); // Should return default config - assert_eq!(config.server.host, "127.0.0.1"); + assert_eq!(config.server.host, "0.0.0.0"); } #[test] @@ -1168,6 +1169,7 @@ cache_ttl_secs = 60 let config = create_test_config(); let debug_str = format!("{:?}", config); assert!(debug_str.contains("Config")); + // Note: create_test_config uses "127.0.0.1" for test isolation assert!(debug_str.contains("127.0.0.1")); assert!(debug_str.contains("8080")); } From 38c9e7348890a28062c61f45c7bcd647ae232c4a Mon Sep 17 00:00:00 2001 From: Justin Taylor <26264269+sjustintaylor@users.noreply.github.com> Date: Thu, 16 Oct 2025 17:09:13 +1000 Subject: [PATCH 4/7] wip: checkpoint --- .dockerignore | 2 +- Cargo.lock | 203 ++++++++++----------------------------------- Cargo.toml | 3 +- Dockerfile | 3 + docker-compose.yml | 8 +- 5 files changed, 54 insertions(+), 165 deletions(-) diff --git a/.dockerignore b/.dockerignore index eecff2a..939d12e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -35,7 +35,7 @@ test-keys.sh test-keys.sh.example # SQLx offline query cache (built during compile) -.sqlx/ +#.sqlx/ # Cargo Husky git hooks .cargo-husky/ diff --git a/Cargo.lock b/Cargo.lock index 9591bc2..ac8386e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,19 +17,6 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" -[[package]] -name = "ahash" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" -dependencies = [ - "cfg-if", - "getrandom 0.3.3", - "once_cell", - "version_check", - "zerocopy", -] - [[package]] name = "aho-corasick" version = "1.1.3" @@ -84,7 +71,7 @@ version = "3.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" dependencies = [ - "event-listener 5.4.1", + "event-listener", "event-listener-strategy", "pin-project-lite", ] @@ -802,12 +789,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - [[package]] name = "event-listener" version = "5.4.1" @@ -825,7 +806,7 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ - "event-listener 5.4.1", + "event-listener", "pin-project-lite", ] @@ -1130,10 +1111,6 @@ name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", - "allocator-api2", -] [[package]] name = "hashbrown" @@ -1141,18 +1118,11 @@ version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ + "allocator-api2", + "equivalent", "foldhash", ] -[[package]] -name = "hashlink" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" -dependencies = [ - "hashbrown 0.14.5", -] - [[package]] name = "hashlink" version = "0.10.0" @@ -1162,15 +1132,6 @@ dependencies = [ "hashbrown 0.15.5", ] -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "heck" version = "0.5.0" @@ -1341,7 +1302,7 @@ dependencies = [ "hyper 1.7.0", "hyper-util", "log", - "rustls 0.23.31", + "rustls", "rustls-pki-types", "tokio", "tokio-rustls", @@ -1678,7 +1639,7 @@ dependencies = [ "hyper-util", "jsonrpsee-core", "jsonrpsee-types", - "rustls 0.23.31", + "rustls", "rustls-platform-verifier", "serde", "serde_json", @@ -1783,11 +1744,10 @@ dependencies = [ [[package]] name = "libsqlite3-sys" -version = "0.27.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" dependencies = [ - "cc", "pkg-config", "vcpkg", ] @@ -1914,7 +1874,7 @@ dependencies = [ "crossbeam-epoch", "crossbeam-utils", "equivalent", - "event-listener 5.4.1", + "event-listener", "futures-util", "parking_lot", "portable-atomic", @@ -2201,12 +2161,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - [[package]] name = "pathdiff" version = "0.2.3" @@ -2838,17 +2792,6 @@ dependencies = [ "windows-sys 0.61.0", ] -[[package]] -name = "rustls" -version = "0.21.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" -dependencies = [ - "ring", - "rustls-webpki 0.101.7", - "sct", -] - [[package]] name = "rustls" version = "0.23.31" @@ -2859,7 +2802,7 @@ dependencies = [ "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.103.4", + "rustls-webpki", "subtle", "zeroize", ] @@ -2905,10 +2848,10 @@ dependencies = [ "jni", "log", "once_cell", - "rustls 0.23.31", + "rustls", "rustls-native-certs", "rustls-platform-verifier-android", - "rustls-webpki 0.103.4", + "rustls-webpki", "security-framework 3.4.0", "security-framework-sys", "webpki-root-certs 0.26.11", @@ -2921,16 +2864,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" -[[package]] -name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "rustls-webpki" version = "0.103.4" @@ -3011,16 +2944,6 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "sdd" version = "3.0.10" @@ -3275,6 +3198,9 @@ name = "smallvec" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +dependencies = [ + "serde", +] [[package]] name = "socket2" @@ -3331,21 +3257,11 @@ dependencies = [ "der", ] -[[package]] -name = "sqlformat" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bba3a93db0cc4f7bdece8bb09e77e2e785c20bfebf79eb8340ed80708048790" -dependencies = [ - "nom", - "unicode_categories", -] - [[package]] name = "sqlx" -version = "0.7.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9a2ccff1a000a5a59cd33da541d9f2fdcd9e6e8229cc200565942bff36d0aaa" +checksum = "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc" dependencies = [ "sqlx-core", "sqlx-macros", @@ -3356,70 +3272,62 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.7.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ba59a9342a3d9bab6c56c118be528b27c9b60e490080e9711a04dccac83ef6" +checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" dependencies = [ - "ahash", - "atoi", - "byteorder", + "base64 0.22.1", "bytes", "chrono", "crc", "crossbeam-queue", "either", - "event-listener 2.5.3", - "futures-channel", + "event-listener", "futures-core", "futures-intrusive", "futures-io", "futures-util", - "hashlink 0.8.4", - "hex", + "hashbrown 0.15.5", + "hashlink", "indexmap", "log", "memchr", "once_cell", - "paste", "percent-encoding", - "rustls 0.21.12", - "rustls-pemfile", "serde", "serde_json", "sha2", "smallvec", - "sqlformat", - "thiserror 1.0.69", + "thiserror 2.0.16", "tokio", "tokio-stream", "tracing", "url", "uuid", - "webpki-roots", ] [[package]] name = "sqlx-macros" -version = "0.7.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea40e2345eb2faa9e1e5e326db8c34711317d2b5e08d0d5741619048a803127" +checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d" dependencies = [ "proc-macro2", "quote", "sqlx-core", "sqlx-macros-core", - "syn 1.0.109", + "syn 2.0.106", ] [[package]] name = "sqlx-macros-core" -version = "0.7.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8" +checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b" dependencies = [ "dotenvy", "either", - "heck 0.4.1", + "heck", "hex", "once_cell", "proc-macro2", @@ -3431,20 +3339,19 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 1.0.109", - "tempfile", + "syn 2.0.106", "tokio", "url", ] [[package]] name = "sqlx-mysql" -version = "0.7.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418" +checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" dependencies = [ "atoi", - "base64 0.21.7", + "base64 0.22.1", "bitflags 2.9.4", "byteorder", "bytes", @@ -3475,7 +3382,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 1.0.69", + "thiserror 2.0.16", "tracing", "uuid", "whoami", @@ -3483,12 +3390,12 @@ dependencies = [ [[package]] name = "sqlx-postgres" -version = "0.7.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e" +checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" dependencies = [ "atoi", - "base64 0.21.7", + "base64 0.22.1", "bitflags 2.9.4", "byteorder", "chrono", @@ -3497,7 +3404,6 @@ dependencies = [ "etcetera", "futures-channel", "futures-core", - "futures-io", "futures-util", "hex", "hkdf", @@ -3515,7 +3421,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror 1.0.69", + "thiserror 2.0.16", "tracing", "uuid", "whoami", @@ -3523,9 +3429,9 @@ dependencies = [ [[package]] name = "sqlx-sqlite" -version = "0.7.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b244ef0a8414da0bed4bb1910426e890b19e5e9bccc27ada6b797d05c55ae0aa" +checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea" dependencies = [ "atoi", "chrono", @@ -3539,10 +3445,11 @@ dependencies = [ "log", "percent-encoding", "serde", + "serde_urlencoded", "sqlx-core", + "thiserror 2.0.16", "tracing", "url", - "urlencoding", "uuid", ] @@ -3584,7 +3491,7 @@ version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "rustversion", @@ -3872,7 +3779,7 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" dependencies = [ - "rustls 0.23.31", + "rustls", "tokio", ] @@ -4135,12 +4042,6 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" -[[package]] -name = "unicode_categories" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" - [[package]] name = "untrusted" version = "0.9.0" @@ -4159,12 +4060,6 @@ dependencies = [ "serde", ] -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -4350,12 +4245,6 @@ dependencies = [ "rustls-pki-types", ] -[[package]] -name = "webpki-roots" -version = "0.25.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" - [[package]] name = "whoami" version = "1.6.1" @@ -4706,7 +4595,7 @@ checksum = "4ce2a4ff45552406d02501cea6c18d8a7e50228e7736a872951fe2fe75c91be7" dependencies = [ "arraydeque", "encoding_rs", - "hashlink 0.10.0", + "hashlink", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 6e1eb98..7fb75f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,6 @@ http-body = "1.0.1" http-body-util = "0.1.3" hyper = { version = "0.14", features = ["server", "http1", "tcp"] } jsonrpsee = { version = "0.26.0", features = ["http-client", "server", "client-core"] } - moka = { version = "0.12", features = ["future"] } prometheus = "0.13" rand = "0.8" @@ -27,7 +26,7 @@ rlp = "0.5" secp256k1 = { version = "0.27", features = ["recovery", "global-context", "rand"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "postgres", "uuid", "chrono", "migrate"] } +sqlx = { version = "0.8", features = ["runtime-tokio", "postgres", "uuid", "chrono", "migrate"] } tiny-keccak = { version = "2.0", features = ["keccak"] } tokio = { version = "1.47.1", features = ["rt", "rt-multi-thread", "macros"] } tokio-cron-scheduler = "0.9" diff --git a/Dockerfile b/Dockerfile index bd84904..0213f97 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,6 +24,9 @@ COPY src ./src COPY migrations ./migrations COPY rustfmt.toml ./ +# Copy the slqx query cache +COPY .sqlx .sqlx + # Build the application in release mode # --locked ensures Cargo.lock is used exactly as specified # --release enables optimizations for production diff --git a/docker-compose.yml b/docker-compose.yml index c33344f..a372c0e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3.8' - services: postgres: image: postgres:15 @@ -42,8 +40,8 @@ services: container_name: preconf_gateway restart: unless-stopped ports: - - "8080:8080" # JSON-RPC API - - "9090:9090" # Prometheus metrics + - "8080:8080" # JSON-RPC API + - "9090:9090" # Prometheus metrics # Load environment variables from .env.docker file # Variables can still be overridden by explicit environment entries below env_file: @@ -64,4 +62,4 @@ services: volumes: postgres_data: - pgadmin_data: \ No newline at end of file + pgadmin_data: From b8c1f35650c7312db53288ef7bb49460765783d8 Mon Sep 17 00:00:00 2001 From: Justin Taylor <26264269+sjustintaylor@users.noreply.github.com> Date: Fri, 17 Oct 2025 11:10:52 +1000 Subject: [PATCH 5/7] wip: checkpoint --- Dockerfile.helios | 62 ++++++++ HELIOS_SETUP.md | 300 ++++++++++++++++++++++++++++++++++++++ Taskfile.yml | 14 +- config.toml | 5 +- docker-compose.helios.yml | 46 ++++++ docker-compose.yml | 44 ++++++ 6 files changed, 469 insertions(+), 2 deletions(-) create mode 100644 Dockerfile.helios create mode 100644 HELIOS_SETUP.md create mode 100644 docker-compose.helios.yml diff --git a/Dockerfile.helios b/Dockerfile.helios new file mode 100644 index 0000000..918dbe4 --- /dev/null +++ b/Dockerfile.helios @@ -0,0 +1,62 @@ +# Dockerfile for Helios Ethereum Light Client +# Helios is a fully trustless, efficient Ethereum light client written in Rust +# https://github.com/a16z/helios + +FROM rust:1.90-slim AS builder + +# Install dependencies +RUN apt-get update && apt-get install -y \ + build-essential \ + libssl-dev \ + pkg-config \ + curl \ + git \ + && rm -rf /var/lib/apt/lists/* + +# Install Helios using heliosup installer +WORKDIR /build +RUN curl https://raw.githubusercontent.com/a16z/helios/master/heliosup/install | bash +RUN /root/.helios/bin/heliosup + +# Runtime stage +FROM debian:trixie-slim + +# Install runtime dependencies +RUN apt-get update && apt-get install -y \ + ca-certificates \ + libssl3 \ + && rm -rf /var/lib/apt/lists/* + +# Copy the heliosup-installed binary from builder +COPY --from=builder /root/.helios/bin/helios /usr/local/bin/helios + +# Create data directory for checkpoint caching +RUN mkdir -p /data/helios + +# Expose RPC port +EXPOSE 8545 + +# Create a non-root user for security +RUN useradd -m -u 1000 helios && \ + chown -R helios:helios /data/helios + +USER helios +WORKDIR /data/helios + +# Default command using environment variables +# This runs Helios with: +# - Ethereum network (or custom network via HELIOS_NETWORK) +# - Execution RPC from HELIOS_EXECUTION_RPC (required) +# - Consensus RPC from HELIOS_CONSENSUS_RPC (optional, defaults to lightclientdata.org) +# - Bind to all interfaces for container access +# - Custom RPC port 8545 +# - Data directory for checkpoints +# - Optional checkpoint via HELIOS_CHECKPOINT +CMD ["sh", "-c", "helios ethereum \ + --execution-rpc ${HELIOS_EXECUTION_RPC} \ + --consensus-rpc ${HELIOS_CONSENSUS_RPC:-https://www.lightclientdata.org} \ + --network ${HELIOS_NETWORK:-mainnet} \ + --rpc-bind-ip 0.0.0.0 \ + --rpc-port 8545 \ + --data-dir /data/helios \ + ${HELIOS_CHECKPOINT:+--checkpoint ${HELIOS_CHECKPOINT}}"] diff --git a/HELIOS_SETUP.md b/HELIOS_SETUP.md new file mode 100644 index 0000000..06a010e --- /dev/null +++ b/HELIOS_SETUP.md @@ -0,0 +1,300 @@ +# Helios Ethereum Light Node Setup + +This document explains how to use the integrated Helios Ethereum light client with the preconfirmation gateway. + +## What is Helios? + +[Helios](https://github.com/a16z/helios) is a fast, secure, and portable Ethereum light client written in Rust by a16z. It provides: + +- **Trustless verification**: Cryptographically verifies all Ethereum data using light client proofs +- **Fast sync**: Syncs in seconds instead of hours/days +- **Low resource usage**: Minimal CPU, memory, and storage requirements +- **Local RPC endpoint**: Provides a standard Ethereum JSON-RPC interface at `http://localhost:8545` + +## Quick Start + +### 1. Configure Environment Variables + +Edit [.env.docker](.env.docker) and set your Execution RPC endpoint: + +```bash +# REQUIRED: Set your Alchemy or Infura API key +HELIOS_EXECUTION_RPC=https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY +``` + +**Important**: The execution RPC provider **must support `eth_getProof`**. Recommended providers: +- [Alchemy](https://www.alchemy.com/) - Supports `eth_getProof` +- [Infura](https://www.infura.io/) - Supports `eth_getProof` + +### 2. Start Helios with Docker Compose + +```bash +# Start all services including Helios +docker-compose up -d + +# Or start only Helios +docker-compose up -d helios + +# View Helios logs +docker-compose logs -f helios +``` + +Helios will: +1. Build the Docker image (first time only, takes ~5-10 minutes) +2. Sync with the Ethereum network (takes ~30-60 seconds) +3. Expose the JSON-RPC endpoint at `http://localhost:8545` + +### 3. Verify Helios is Running + +```bash +# Check if Helios is responding +curl -X POST http://localhost:8545 \ + -H "Content-Type: application/json" \ + -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' + +# Expected response: +# {"jsonrpc":"2.0","result":"0x...","id":1} +``` + +### 4. Configure Gateway to Use Helios (Optional) + +To use Helios as the RPC endpoint for the gateway's gas price oracle, update [config.toml](config.toml): + +```toml +[reth] +# Point to Helios container (when running in Docker) +endpoint = "http://helios:8545" +``` + +Or set the environment variable: + +```bash +export RETH_ENDPOINT=http://helios:8545 +``` + +## Configuration Options + +All Helios configuration is done via environment variables in [.env.docker](.env.docker): + +### Required Configuration + +| Variable | Description | Example | +|----------|-------------|---------| +| `HELIOS_EXECUTION_RPC` | Execution RPC endpoint (must support `eth_getProof`) | `https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY` | + +### Optional Configuration + +| Variable | Default | Options | Description | +|----------|---------|---------|-------------| +| `HELIOS_CONSENSUS_RPC` | `https://www.lightclientdata.org` | Any consensus node | Consensus layer endpoint | +| `HELIOS_NETWORK` | `mainnet` | `mainnet`, `sepolia`, `holesky` | Ethereum network to connect to | +| `HELIOS_CHECKPOINT` | (cached) | Beacon block hash | Weak subjectivity checkpoint | + +### Example: Connecting to Sepolia Testnet + +```bash +# .env.docker +HELIOS_EXECUTION_RPC=https://eth-sepolia.g.alchemy.com/v2/YOUR_API_KEY +HELIOS_NETWORK=sepolia +HELIOS_CHECKPOINT=0x... # Optional: Get from https://sepolia.beaconcha.in/ +``` + +## Architecture + +The Docker Compose setup includes: + +``` +┌─────────────────────────────────────────────────┐ +│ Docker Compose Stack │ +│ │ +│ ┌──────────────┐ ┌─────────────────────┐ │ +│ │ Gateway │───▶│ Helios Light Node │ │ +│ │ (port 8080) │ │ (port 8545) │ │ +│ └──────────────┘ └─────────────────────┘ │ +│ │ │ │ +│ │ ▼ │ +│ │ ┌──────────────────┐ │ +│ │ │ Alchemy/Infura │ │ +│ │ │ (eth_getProof) │ │ +│ │ └──────────────────┘ │ +│ ▼ │ +│ ┌──────────────┐ │ +│ │ PostgreSQL │ │ +│ │ (port 5432) │ │ +│ └──────────────┘ │ +└─────────────────────────────────────────────────┘ +``` + +Key features: +- **Health checks**: Gateway waits for Helios to be healthy before starting +- **Persistent storage**: Checkpoint data persists across container restarts in `helios_data` volume +- **Network isolation**: All services communicate via Docker internal network + +## Checkpoint Management + +Helios uses **weak subjectivity checkpoints** as a trust anchor. After the first sync: + +1. Helios caches the most recent finalized checkpoint in `/data/helios` +2. On subsequent starts, it uses the cached checkpoint automatically +3. The `helios_data` Docker volume persists this cache + +### Manually Setting a Checkpoint + +For faster first-time sync or to update an old checkpoint: + +1. Get a recent finalized block hash from [beaconcha.in](https://beaconcha.in/) +2. Set in [.env.docker](.env.docker): + ```bash + HELIOS_CHECKPOINT=0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef + ``` +3. Restart Helios: + ```bash + docker-compose restart helios + ``` + +## Testing and Development + +### Using Helios Locally (without Docker) + +If you want to run Helios outside Docker for development: + +```bash +# Install heliosup +curl https://raw.githubusercontent.com/a16z/helios/master/heliosup/install | bash +heliosup + +# Run Helios +helios ethereum \ + --execution-rpc https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY \ + --rpc-bind-ip 127.0.0.1 \ + --rpc-port 8545 +``` + +Then update [config.toml](config.toml): +```toml +[reth] +endpoint = "http://localhost:8545" +``` + +### Testing RPC Methods + +Helios implements most standard Ethereum RPC methods: + +```bash +# Get latest block number +curl -X POST http://localhost:8545 \ + -H "Content-Type: application/json" \ + -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' + +# Get block by number +curl -X POST http://localhost:8545 \ + -H "Content-Type: application/json" \ + -d '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["latest",false],"id":1}' + +# Get balance +curl -X POST http://localhost:8545 \ + -H "Content-Type: application/json" \ + -d '{"jsonrpc":"2.0","method":"eth_getBalance","params":["0x...", "latest"],"id":1}' + +# Get gas price +curl -X POST http://localhost:8545 \ + -H "Content-Type: application/json" \ + -d '{"jsonrpc":"2.0","method":"eth_gasPrice","params":[],"id":1}' +``` + +## Troubleshooting + +### Helios fails to start + +**Check execution RPC supports `eth_getProof`:** +```bash +curl -X POST https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY \ + -H "Content-Type: application/json" \ + -d '{"jsonrpc":"2.0","method":"eth_getProof","params":["0x0000000000000000000000000000000000000000",[], "latest"],"id":1}' +``` + +If this fails, your RPC provider doesn't support `eth_getProof`. Switch to Alchemy or Infura. + +### Checkpoint is too old + +If you see warnings about old checkpoints: + +1. Get a fresh checkpoint from https://beaconcha.in/ +2. Set `HELIOS_CHECKPOINT` in [.env.docker](.env.docker) +3. Restart: `docker-compose restart helios` + +### Slow sync or timeouts + +Helios sync typically takes 30-60 seconds. If it's slower: + +1. Check your internet connection +2. Try a different consensus RPC endpoint +3. Ensure your execution RPC has low latency +4. Check Helios logs: `docker-compose logs -f helios` + +### Gateway can't connect to Helios + +Ensure: +1. Helios is running: `docker-compose ps helios` +2. Helios is healthy: `docker-compose ps` (should show "healthy") +3. Config points to `http://helios:8545` (not `localhost` when in Docker) + +## Performance Considerations + +### Resource Usage + +Helios is lightweight: +- **CPU**: Minimal (mostly idle after sync) +- **Memory**: ~100-200 MB +- **Disk**: ~10 MB for checkpoint cache +- **Network**: Initial sync downloads ~50-100 MB, then minimal + +### Sync Time + +- **First sync**: 30-60 seconds +- **Subsequent starts**: 5-10 seconds (uses cached checkpoint) +- **Stay synced**: Continuous, automatic + +### RPC Performance + +Helios provides similar performance to remote RPC providers: +- **Latency**: ~50-200ms per request (includes verification) +- **Throughput**: Hundreds of requests per second +- **Reliability**: No rate limits, local access + +## Security Considerations + +### Trust Model + +Helios is a **trustless** light client: +- ✅ Verifies all data cryptographically using consensus proofs +- ✅ No trust in the execution RPC provider (only used for data, not trust) +- ✅ Trust only in the initial checkpoint (from beaconcha.in or Ethereum Foundation) + +### Production Recommendations + +1. **Checkpoint source**: Use checkpoints from trusted sources (beaconcha.in, Ethereum Foundation) +2. **Execution RPC**: Use reputable providers (Alchemy, Infura) for data availability +3. **Consensus RPC**: Use your own consensus node for maximum security +4. **Network isolation**: Keep Helios on internal network, not exposed to internet +5. **Monitoring**: Monitor sync status and health checks + +## Additional Resources + +- [Helios GitHub](https://github.com/a16z/helios) +- [Helios Documentation](https://github.com/a16z/helios/tree/master/docs) +- [Ethereum Light Client Specification](https://github.com/ethereum/consensus-specs/tree/dev/specs/altair/light-client) +- [beaconcha.in](https://beaconcha.in/) - Block explorer for checkpoints +- [Alchemy](https://www.alchemy.com/) - Recommended RPC provider +- [Infura](https://www.infura.io/) - Alternative RPC provider + +## Support + +For Helios-specific issues: +- [Helios GitHub Issues](https://github.com/a16z/helios/issues) +- [Helios Discord](https://discord.gg/a16z) + +For preconfirmation gateway integration issues: +- Check [CLAUDE.md](CLAUDE.md) for project architecture +- Review [SYSTEM_OVERVIEW.md](SYSTEM_OVERVIEW.md) for implementation details +- Open an issue in this repository diff --git a/Taskfile.yml b/Taskfile.yml index 7e4f401..bbe238a 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -62,7 +62,10 @@ tasks: desc: "Build Docker image" cmds: - docker build -t preconfirmation-gateway:latest . - + + docker:build:helios: + cmds: + - docker build -t helios:latest --file Dockerfile.helios . docker:run: desc: "Run Docker container with environment variables from .env" cmds: @@ -74,6 +77,15 @@ tasks: -e BLS_PRIVATE_KEY="${BLS_PRIVATE_KEY}" \ -e RUST_LOG="${RUST_LOG:-info}" \ preconfirmation-gateway:latest + + docker:run:helios: + cmds: + - | + docker run -p 8545:8545 \ + -e HELIOS_EXECUTION_RPC="${HELIOS_EXECUTION_RPC}" \ + -e HELIOS_CONSENSUS_RPC="${HELIOS_CONSENSUS_RPC}" \ + -e HELIOS_CHECKPOINT="${HELIOS_CHECKPOINT}" \ + helios:latest docker:compose:up: desc: "Start all services with docker-compose" diff --git a/config.toml b/config.toml index 4f36613..236f1b8 100644 --- a/config.toml +++ b/config.toml @@ -69,7 +69,10 @@ domain_application_gateway = "0x00000001" [reth] # Reth node configuration for gas price oracle -endpoint = "http://localhost:8545" # Reth node RPC endpoint +# Can also point to Helios light node for local trustless Ethereum access +# For Docker: use "http://helios:8545" to connect to Helios container +# For local: use "http://localhost:8545" for Helios or external RPC +endpoint = "http://localhost:8545" # Reth/Helios node RPC endpoint request_timeout_secs = 10 max_retries = 3 diff --git a/docker-compose.helios.yml b/docker-compose.helios.yml new file mode 100644 index 0000000..8286a49 --- /dev/null +++ b/docker-compose.helios.yml @@ -0,0 +1,46 @@ +# Docker Compose file for running ONLY Helios Ethereum Light Node +# This is useful for testing Helios independently or running it alongside +# a locally-running gateway (not in Docker) +# +# Usage: +# docker-compose -f docker-compose.helios.yml up -d +# +# After starting, Helios will be available at: http://localhost:8545 + +version: '3.8' + +services: + helios: + build: + context: . + dockerfile: Dockerfile.helios + container_name: preconf_helios_standalone + restart: unless-stopped + ports: + - "8545:8545" # Ethereum JSON-RPC + environment: + # Load from .env file or set these directly + HELIOS_EXECUTION_RPC: ${HELIOS_EXECUTION_RPC} + HELIOS_CONSENSUS_RPC: ${HELIOS_CONSENSUS_RPC:-https://www.lightclientdata.org} + HELIOS_NETWORK: ${HELIOS_NETWORK:-mainnet} + HELIOS_CHECKPOINT: ${HELIOS_CHECKPOINT:-} + command: > + ethereum + --execution-rpc ${HELIOS_EXECUTION_RPC} + --consensus-rpc ${HELIOS_CONSENSUS_RPC:-https://www.lightclientdata.org} + --network ${HELIOS_NETWORK:-mainnet} + --rpc-bind-ip 0.0.0.0 + --rpc-port 8545 + --data-dir /data/helios + ${HELIOS_CHECKPOINT:+--checkpoint ${HELIOS_CHECKPOINT}} + volumes: + - helios_data_standalone:/data/helios + healthcheck: + test: ["CMD-SHELL", "curl -f http://localhost:8545 -X POST -H 'Content-Type: application/json' -d '{\"jsonrpc\":\"2.0\",\"method\":\"eth_blockNumber\",\"params\":[],\"id\":1}' || exit 1"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 60s + +volumes: + helios_data_standalone: diff --git a/docker-compose.yml b/docker-compose.yml index a372c0e..845fb5a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -33,6 +33,47 @@ services: volumes: - pgadmin_data:/var/lib/pgadmin + helios: + build: + context: . + dockerfile: Dockerfile.helios + container_name: preconf_helios + restart: unless-stopped + ports: + - "8545:8545" # Ethereum JSON-RPC + environment: + # Execution RPC endpoint - REQUIRED + # Must support eth_getProof (Alchemy and Infura recommended) + HELIOS_EXECUTION_RPC: ${HELIOS_EXECUTION_RPC} + # Consensus RPC endpoint - OPTIONAL + HELIOS_CONSENSUS_RPC: ${HELIOS_CONSENSUS_RPC} + # Network selection - mainnet, sepolia, or holesky + HELIOS_NETWORK: ${HELIOS_NETWORK:-mainnet} + # Weak subjectivity checkpoint - OPTIONAL + # Uses cached checkpoint if not specified + HELIOS_CHECKPOINT: ${HELIOS_CHECKPOINT:-} + command: > + ethereum + --execution-rpc ${HELIOS_EXECUTION_RPC} + --consensus-rpc ${HELIOS_CONSENSUS_RPC:-https://www.lightclientdata.org} + --network ${HELIOS_NETWORK:-mainnet} + --rpc-bind-ip 0.0.0.0 + --rpc-port 8545 + --data-dir /data/helios + ${HELIOS_CHECKPOINT:+--checkpoint ${HELIOS_CHECKPOINT}} + volumes: + - helios_data:/data/helios + healthcheck: + test: + [ + "CMD-SHELL", + 'curl -f http://localhost:8545 -X POST -H ''Content-Type: application/json'' -d ''{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'' || exit 1', + ] + interval: 30s + timeout: 10s + retries: 3 + start_period: 60s + gateway: build: context: . @@ -57,9 +98,12 @@ services: depends_on: postgres: condition: service_healthy + helios: + condition: service_healthy volumes: - ./config.toml:/app/config.toml:ro volumes: postgres_data: pgadmin_data: + helios_data: From b8e2cde7f427a960f72c0eef8b5211daf34947eb Mon Sep 17 00:00:00 2001 From: Justin Taylor <26264269+sjustintaylor@users.noreply.github.com> Date: Fri, 17 Oct 2025 12:04:52 +1000 Subject: [PATCH 6/7] wip --- Dockerfile | 1 + Taskfile.yml | 1 + docker-compose.yml | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 0213f97..7828ed8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -43,6 +43,7 @@ FROM debian:bookworm-slim AS runtime RUN apt-get update && apt-get install -y \ libpq5 \ ca-certificates \ + curl \ && rm -rf /var/lib/apt/lists/* # Create a non-root user for security diff --git a/Taskfile.yml b/Taskfile.yml index bbe238a..ee64965 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -66,6 +66,7 @@ tasks: docker:build:helios: cmds: - docker build -t helios:latest --file Dockerfile.helios . + docker:run: desc: "Run Docker container with environment variables from .env" cmds: diff --git a/docker-compose.yml b/docker-compose.yml index 845fb5a..15e497c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -90,7 +90,7 @@ services: environment: # Override specific variables if needed # These take precedence over .env.docker values - DATABASE_URL: postgresql://postgres:postgres@postgres:5432/preconfirmation_gateway + DATABASE_URL: ${DATABASE_URL} BEACON_API_ENDPOINT: ${BEACON_API_ENDPOINT} COMMITTER_PRIVATE_KEY: ${COMMITTER_PRIVATE_KEY} BLS_PRIVATE_KEY: ${BLS_PRIVATE_KEY} From 7145f07badbc035fbc25692d760a737213397ea7 Mon Sep 17 00:00:00 2001 From: Justin Taylor <26264269+sjustintaylor@users.noreply.github.com> Date: Fri, 17 Oct 2025 15:04:01 +1000 Subject: [PATCH 7/7] wip --- Dockerfile.helios | 9 +++++++-- Taskfile.yml | 1 + config.toml | 3 ++- docker-compose.helios.yml | 14 +++++++++----- docker-compose.yml | 21 +++------------------ 5 files changed, 22 insertions(+), 26 deletions(-) diff --git a/Dockerfile.helios b/Dockerfile.helios index 918dbe4..2775541 100644 --- a/Dockerfile.helios +++ b/Dockerfile.helios @@ -25,6 +25,7 @@ FROM debian:trixie-slim RUN apt-get update && apt-get install -y \ ca-certificates \ libssl3 \ + curl \ && rm -rf /var/lib/apt/lists/* # Copy the heliosup-installed binary from builder @@ -43,18 +44,22 @@ RUN useradd -m -u 1000 helios && \ USER helios WORKDIR /data/helios +# Health check (optional but recommended) +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD curl -f http://localhost:8545 -X POST -H 'Content-Type: application/json' -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' || exit 1 + # Default command using environment variables # This runs Helios with: # - Ethereum network (or custom network via HELIOS_NETWORK) # - Execution RPC from HELIOS_EXECUTION_RPC (required) -# - Consensus RPC from HELIOS_CONSENSUS_RPC (optional, defaults to lightclientdata.org) +# - Consensus RPC from HELIOS_CONSENSUS_RPC (optional, defaults to https://ethereum.operationsolarstorm.org) # - Bind to all interfaces for container access # - Custom RPC port 8545 # - Data directory for checkpoints # - Optional checkpoint via HELIOS_CHECKPOINT CMD ["sh", "-c", "helios ethereum \ --execution-rpc ${HELIOS_EXECUTION_RPC} \ - --consensus-rpc ${HELIOS_CONSENSUS_RPC:-https://www.lightclientdata.org} \ + --consensus-rpc ${HELIOS_CONSENSUS_RPC:-https://ethereum.operationsolarstorm.org} \ --network ${HELIOS_NETWORK:-mainnet} \ --rpc-bind-ip 0.0.0.0 \ --rpc-port 8545 \ diff --git a/Taskfile.yml b/Taskfile.yml index ee64965..61f8b1d 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -90,6 +90,7 @@ tasks: docker:compose:up: desc: "Start all services with docker-compose" + dotenv: [".env.docker"] cmds: - docker-compose up -d diff --git a/config.toml b/config.toml index 236f1b8..dc67451 100644 --- a/config.toml +++ b/config.toml @@ -72,7 +72,8 @@ domain_application_gateway = "0x00000001" # Can also point to Helios light node for local trustless Ethereum access # For Docker: use "http://helios:8545" to connect to Helios container # For local: use "http://localhost:8545" for Helios or external RPC -endpoint = "http://localhost:8545" # Reth/Helios node RPC endpoint +# IMPORTANT: Set RETH_ENDPOINT environment variable or this will fail validation +endpoint = "${RETH_ENDPOINT}" # Reth/Helios node RPC endpoint request_timeout_secs = 10 max_retries = 3 diff --git a/docker-compose.helios.yml b/docker-compose.helios.yml index 8286a49..7b6969d 100644 --- a/docker-compose.helios.yml +++ b/docker-compose.helios.yml @@ -7,7 +7,7 @@ # # After starting, Helios will be available at: http://localhost:8545 -version: '3.8' +version: "3.8" services: helios: @@ -21,13 +21,13 @@ services: environment: # Load from .env file or set these directly HELIOS_EXECUTION_RPC: ${HELIOS_EXECUTION_RPC} - HELIOS_CONSENSUS_RPC: ${HELIOS_CONSENSUS_RPC:-https://www.lightclientdata.org} + HELIOS_CONSENSUS_RPC: ${HELIOS_CONSENSUS_RPC:-https://ethereum.operationsolarstorm.org} HELIOS_NETWORK: ${HELIOS_NETWORK:-mainnet} HELIOS_CHECKPOINT: ${HELIOS_CHECKPOINT:-} command: > - ethereum + helios ethereum --execution-rpc ${HELIOS_EXECUTION_RPC} - --consensus-rpc ${HELIOS_CONSENSUS_RPC:-https://www.lightclientdata.org} + --consensus-rpc ${HELIOS_CONSENSUS_RPC:-https://ethereum.operationsolarstorm.org} --network ${HELIOS_NETWORK:-mainnet} --rpc-bind-ip 0.0.0.0 --rpc-port 8545 @@ -36,7 +36,11 @@ services: volumes: - helios_data_standalone:/data/helios healthcheck: - test: ["CMD-SHELL", "curl -f http://localhost:8545 -X POST -H 'Content-Type: application/json' -d '{\"jsonrpc\":\"2.0\",\"method\":\"eth_blockNumber\",\"params\":[],\"id\":1}' || exit 1"] + test: + [ + "CMD-SHELL", + 'curl -f http://localhost:8545 -X POST -H "Content-Type: application/json" -d ''{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'' || exit 1', + ] interval: 30s timeout: 10s retries: 3 diff --git a/docker-compose.yml b/docker-compose.yml index 15e497c..59e4e19 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -18,21 +18,6 @@ services: timeout: 5s retries: 5 - pgadmin: - image: dpage/pgadmin4:latest - container_name: preconf_pgadmin - restart: unless-stopped - environment: - PGADMIN_DEFAULT_EMAIL: admin@preconf.local - PGADMIN_DEFAULT_PASSWORD: admin - ports: - - "8081:80" - depends_on: - postgres: - condition: service_healthy - volumes: - - pgadmin_data:/var/lib/pgadmin - helios: build: context: . @@ -53,9 +38,9 @@ services: # Uses cached checkpoint if not specified HELIOS_CHECKPOINT: ${HELIOS_CHECKPOINT:-} command: > - ethereum + helios ethereum --execution-rpc ${HELIOS_EXECUTION_RPC} - --consensus-rpc ${HELIOS_CONSENSUS_RPC:-https://www.lightclientdata.org} + --consensus-rpc ${HELIOS_CONSENSUS_RPC:-https://ethereum.operationsolarstorm.org} --network ${HELIOS_NETWORK:-mainnet} --rpc-bind-ip 0.0.0.0 --rpc-port 8545 @@ -95,6 +80,7 @@ services: COMMITTER_PRIVATE_KEY: ${COMMITTER_PRIVATE_KEY} BLS_PRIVATE_KEY: ${BLS_PRIVATE_KEY} RUST_LOG: ${RUST_LOG:-info} + RETH_ENDPOINT: ${RETH_ENDPOINT:-http://preconf_helios:8545} depends_on: postgres: condition: service_healthy @@ -105,5 +91,4 @@ services: volumes: postgres_data: - pgadmin_data: helios_data: