From 54c2dc2cfd7639fa540f4d571a8a0d69a61dc004 Mon Sep 17 00:00:00 2001 From: mertcano <35747700+mertcano@users.noreply.github.com> Date: Sat, 15 Aug 2026 14:40:46 +0300 Subject: [PATCH] Fix: Enforce safe default for GENVM_DEBUG_MODE This PR updates docker-compose.yml to explicitly default GENVM_DEBUG_MODE to false for the consensus-worker. If this environment variable is omitted during deployment, the runtime helper defaults to an unsafe mode. Setting it to false ensures the consensus worker defaults to a bounded, deterministic state when the configuration is incomplete. --- docker-compose.yml | 903 +++++++++++++++++++++++---------------------- 1 file changed, 452 insertions(+), 451 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 62c6394f2..54987ff74 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,451 +1,452 @@ -services: - traefik: - profiles: ["studio"] - image: traefik:v3.6 - command: - # Core configuration - - "--providers.docker=true" - - "--providers.docker.exposedbydefault=false" - - "--providers.file.filename=/etc/traefik/tls.yml" - - "--providers.file.watch=true" - - # Entrypoints for local development - - "--entrypoints.web.address=:80" - - "--entrypoints.websecure.address=:443" # Needed for frontend/hardhat labels - # API Dashboard (for local dev monitoring) - - "--api.dashboard=true" - # Extended timeouts for large contract state loading (20 minutes to match GenVM timeout) - - "--entryPoints.web.transport.respondingTimeouts.readTimeout=1200s" - - "--entryPoints.web.transport.respondingTimeouts.writeTimeout=1200s" - - "--entryPoints.web.transport.respondingTimeouts.idleTimeout=1200s" - - "--entryPoints.websecure.transport.respondingTimeouts.readTimeout=1200s" - - "--entryPoints.websecure.transport.respondingTimeouts.writeTimeout=1200s" - - "--entryPoints.websecure.transport.respondingTimeouts.idleTimeout=1200s" - # Server transport with extended forwarding timeouts - - "--serversTransport.forwardingTimeouts.responseHeaderTimeout=1200s" - - "--serversTransport.forwardingTimeouts.idleConnTimeout=1200s" - ports: - - "80:80" - - "443:443" - - "8081:8080" # Traefik dashboard (8081 to avoid conflict with frontend on 8080) - volumes: - - /var/run/docker.sock:/var/run/docker.sock:ro - - /opt/genlayer-studio/nginx/ssl/:/etc/ssl/traefik:ro - - ./traefik/tls.yml:/etc/traefik/tls.yml:ro - logging: - driver: "json-file" - options: - max-size: "50m" - max-file: "10" - - frontend: - build: - context: ./ - dockerfile: ./docker/Dockerfile.frontend - target: ${FRONTEND_BUILD_TARGET:-final} - ports: - - "${FRONTEND_PORT}:8080" - volumes: - - ./examples:/app/src/assets/examples - - ./frontend/src:/app/src - depends_on: - jsonrpc: - condition: service_healthy - expose: - - "${FRONTEND_PORT}" - environment: - - VITE_GENLAYER_NETWORK=${VITE_GENLAYER_NETWORK} - - VITE_CHAIN_ID=${VITE_CHAIN_ID} - - VITE_CHAIN_NAME=${VITE_CHAIN_NAME} - - VITE_JSON_RPC_SERVER_URL=${VITE_JSON_RPC_SERVER_URL} - - VITE_WS_SERVER_URL=${VITE_WS_SERVER_URL} - - VITE_IS_HOSTED=${VITE_IS_HOSTED} - - VITE_FINALITY_WINDOW=${VITE_FINALITY_WINDOW} - - VITE_FINALITY_WINDOW_APPEAL_FAILED_REDUCTION=${VITE_FINALITY_WINDOW_APPEAL_FAILED_REDUCTION} - - VITE_MAX_ROTATIONS=${VITE_MAX_ROTATIONS} - - VITE_PLAUSIBLE_DOMAIN=${VITE_PLAUSIBLE_DOMAIN} - - VITE_APPKIT_PROJECT_ID=${VITE_APPKIT_PROJECT_ID} - - VITE_EXPLORER_URL=${VITE_EXPLORER_URL} - - VITE_LOCK_NETWORK=${VITE_LOCK_NETWORK} - - GENLAYER_CHAIN_ID=${GENLAYER_CHAIN_ID} - - HARDHAT_CHAIN_ID=${HARDHAT_CHAIN_ID} - restart: always - security_opt: - - "no-new-privileges=true" - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: - traefik.enable: true - traefik.http.routers.frontend.rule: Host(`${SERVER_NAME}`) - traefik.http.routers.frontend.entrypoints: websecure - traefik.http.routers.frontend.tls: true - - explorer: - build: - context: ./ - dockerfile: ./docker/Dockerfile.explorer - target: ${EXPLORER_BUILD_TARGET:-final} - ports: - - "${EXPLORER_PORT:-3001}:3000" - volumes: - - ./explorer/src:/app/src - depends_on: - jsonrpc: - condition: service_healthy - environment: - - BACKEND_URL=http://jsonrpc:4000 - restart: always - security_opt: - - "no-new-privileges=true" - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - - jsonrpc: - build: - context: ./ - dockerfile: ./docker/Dockerfile.backend - target: prod - args: - GENVM_TAG: ${GENVM_TAG:-} - GENVM_REF: ${GENVM_REF:-} - GENVM_SOURCE_MODE: ${GENVM_SOURCE_MODE:-} - GENVM_EXECUTOR_VERSION_NAME: ${GENVM_EXECUTOR_VERSION_NAME:-} - environment: - - PYTHONUNBUFFERED=1 - - WEBDRIVERHOST=${WEBDRIVERHOST} - - WEBDRIVERPORT=${WEBDRIVERPORT} - - REDIS_URL=${REDIS_URL:-redis://redis:6379/0} - - WEB_CONCURRENCY=${WEB_CONCURRENCY:-1} - - DATABASE_POOL_SIZE=${DATABASE_POOL_SIZE:-20} - - DATABASE_MAX_OVERFLOW=${DATABASE_MAX_OVERFLOW:-10} - - LOG_LEVEL=${LOG_LEVEL:-info} - - GENVMROOT=/genvm - - RATE_LIMIT_ENABLED=${RATE_LIMIT_ENABLED:-false} - - RATE_LIMIT_ANON_PER_MINUTE=${RATE_LIMIT_ANON_PER_MINUTE:-30} - - RATE_LIMIT_ANON_PER_HOUR=${RATE_LIMIT_ANON_PER_HOUR:-500} - - RATE_LIMIT_ANON_PER_DAY=${RATE_LIMIT_ANON_PER_DAY:-5000} - - GENLAYER_STUDIO_GEN_PER_TIME_UNIT=${GENLAYER_STUDIO_GEN_PER_TIME_UNIT:-1000000000000000} - - GENLAYER_STUDIO_STORAGE_UNIT_PRICE=${GENLAYER_STUDIO_STORAGE_UNIT_PRICE:-1} - - GENLAYER_STUDIO_RECEIPT_GAS_PRICE=${GENLAYER_STUDIO_RECEIPT_GAS_PRICE:-1} - - GENLAYER_STUDIO_FIXED_PROPOSE_RECEIPT_GAS=${GENLAYER_STUDIO_FIXED_PROPOSE_RECEIPT_GAS:-210000} - - GENLAYER_STUDIO_FIXED_MESSAGE_REVEAL_GAS=${GENLAYER_STUDIO_FIXED_MESSAGE_REVEAL_GAS:-100000} - - GENLAYER_STUDIO_RECEIPT_WRAPPER_BYTES=${GENLAYER_STUDIO_RECEIPT_WRAPPER_BYTES:-1024} - # Per-contract / per-sender PENDING tx caps (admission control on - # eth_sendRawTransaction). Empty/unset = no cap. Set in shared - # deployments to keep one heavy user from filling the queue. - - MAX_PENDING_PER_CONTRACT_DEFAULT=${MAX_PENDING_PER_CONTRACT_DEFAULT:-} - - MAX_PENDING_PER_SENDER_DEFAULT=${MAX_PENDING_PER_SENDER_DEFAULT:-} - ports: - - "${RPCHOSTPORT:-4000}:${RPCPORT:-4000}" - expose: - - "${RPCPORT}" - volumes: - - ./.env:/app/.env - - ./backend:/app/backend - - ${GENVM_CACHE_DIR:-genvm_cache}:/genvm-cache - # - hardhat_artifacts:/app/hardhat/artifacts - # - hardhat_deployments:/app/hardhat/deployments - depends_on: - traefik: - condition: service_started - required: false - database-migration: - condition: service_completed_successfully - webdriver: - condition: service_healthy - redis: - condition: service_healthy - # hardhat: - # condition: service_healthy - # required: false - ollama: - condition: service_started - required: false - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:${RPCPORT}/health"] - interval: 30s - timeout: 10s - retries: 5 - start_period: 300s - restart: always - security_opt: - - "no-new-privileges=true" - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - mem_limit: ${COMPOSE_RPC_MEM_LIMIT:-8g} - mem_reservation: ${COMPOSE_RPC_MEM_RESERVATION:-2g} - memswap_limit: ${COMPOSE_RPC_MEM_SWAP_LIMIT:-8g} - oom_kill_disable: false - deploy: - replicas: ${JSONRPC_REPLICAS:-3} - resources: - limits: - cpus: '${COMPOSE_RPC_CPU_LIMIT:-2}' - memory: ${COMPOSE_RPC_MEM_LIMIT:-8g} - reservations: - cpus: ${COMPOSE_RPC_CPU_RESERVATION:-1} - memory: ${COMPOSE_RPC_MEM_RESERVATION:-2g} - labels: - traefik.enable: true - # Define service with port - traefik.http.services.jsonrpc.loadbalancer.server.port: ${RPCPORT} - # HTTPS router for main API - traefik.http.routers.jsonrpc.rule: Host(`${SERVER_NAME}`) && (PathPrefix(`/api`) || PathPrefix(`/socket.io`) || PathPrefix(`/ws`) || PathPrefix(`/monitoring`)) - traefik.http.routers.jsonrpc.entrypoints: websecure - traefik.http.routers.jsonrpc.tls: true - traefik.http.routers.jsonrpc.service: jsonrpc - # HTTP router for health endpoints (no TLS required) - traefik.http.routers.jsonrpc-health.rule: Host(`${SERVER_NAME}`) && (PathPrefix(`/health`) || PathPrefix(`/ready`) || PathPrefix(`/metrics`)) - traefik.http.routers.jsonrpc-health.entrypoints: web - traefik.http.routers.jsonrpc-health.service: jsonrpc - - webdriver: - image: yeagerai/genlayer-genvm-webdriver:0.0.9 - shm_size: 2gb - environment: - - PORT=${WEBDRIVERPORT:-4444} - expose: - - "${WEBDRIVERPORT:-4444}" - restart: always - security_opt: - - "no-new-privileges=true" - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - mem_limit: 16g - mem_reservation: 2g - memswap_limit: 24g - oom_kill_disable: false - deploy: - resources: - limits: - cpus: 2 - memory: 16g - reservations: - cpus: 1 - memory: 2g - - ollama: - profiles: ["ollama"] - image: ollama/ollama:0.17.6 - ports: - - 11434:11434 - volumes: - - ./.ollama:/root/.ollama - container_name: ollama - tty: true - restart: always - security_opt: - - "no-new-privileges=true" - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - - postgres: - image: postgres:16-alpine - command: sh -c "if [ \"$REMOTE_DATABASE\" = \"true\" ]; then echo 'Postgres disabled in hosted environment' && exec tail -f /dev/null; else exec docker-entrypoint.sh postgres; fi" - ports: - - "${DBHOSTPORT:-5432}:5432" - environment: - - POSTGRES_USER=${DBUSER} - - POSTGRES_PASSWORD=${DBPASSWORD} - - POSTGRES_DB=${DBNAME} - - REMOTE_DATABASE=${REMOTE_DATABASE} - healthcheck: - test: if [ "$REMOTE_DATABASE" = "true" ]; then exit 0; else pg_isready -U ${DBUSER} -d ${DBNAME}; fi - interval: 10s - timeout: 3s - retries: 3 - restart: always - security_opt: - - "no-new-privileges=true" - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - # Database data - use 'docker compose down -v' to wipe - volumes: - - postgres_data:/var/lib/postgresql/data - - database-migration: - build: - context: . - dockerfile: docker/Dockerfile.database-migration - environment: - - DBUSER=${DBUSER} - - DBPASSWORD=${DBPASSWORD} - - DBHOST=${DBHOST} - - DBPORT=${DBPORT} - - DBNAME=${DBNAME} - depends_on: - postgres: - condition: service_healthy - required: false - - consensus-worker: - build: - context: ./ - dockerfile: ./docker/Dockerfile.consensus-worker - target: ${CONSENSUS_BUILD_TARGET:-base} - args: - GENVM_TAG: ${GENVM_TAG:-} - GENVM_REF: ${GENVM_REF:-} - GENVM_SOURCE_MODE: ${GENVM_SOURCE_MODE:-} - GENVM_EXECUTOR_VERSION_NAME: ${GENVM_EXECUTOR_VERSION_NAME:-} - environment: - - DBUSER=${DBUSER} - - DBPASSWORD=${DBPASSWORD} - - DBHOST=${DBHOST} - - DBNAME=${DBNAME} - - WORKER_PORT=4001 - - WORKER_POLL_INTERVAL=${WORKER_POLL_INTERVAL:-5} - - TRANSACTION_TIMEOUT_MINUTES=${TRANSACTION_TIMEOUT_MINUTES:-30} - - LOG_LEVEL=${LOG_LEVEL:-info} - - WEBDRIVERHOST=${WEBDRIVERHOST} - - WEBDRIVERPORT=${WEBDRIVERPORT} - - REDIS_URL=${REDIS_URL:-redis://redis:6379/0} - - GENLAYER_STUDIO_GEN_PER_TIME_UNIT=${GENLAYER_STUDIO_GEN_PER_TIME_UNIT:-1000000000000000} - - GENLAYER_STUDIO_STORAGE_UNIT_PRICE=${GENLAYER_STUDIO_STORAGE_UNIT_PRICE:-1} - - GENLAYER_STUDIO_RECEIPT_GAS_PRICE=${GENLAYER_STUDIO_RECEIPT_GAS_PRICE:-1} - - GENLAYER_STUDIO_FIXED_PROPOSE_RECEIPT_GAS=${GENLAYER_STUDIO_FIXED_PROPOSE_RECEIPT_GAS:-210000} - - GENLAYER_STUDIO_FIXED_MESSAGE_REVEAL_GAS=${GENLAYER_STUDIO_FIXED_MESSAGE_REVEAL_GAS:-100000} - - GENLAYER_STUDIO_RECEIPT_WRAPPER_BYTES=${GENLAYER_STUDIO_RECEIPT_WRAPPER_BYTES:-1024} - volumes: - - ./.env:/app/.env - - ./backend:/app/backend - - ${GENVM_CACHE_DIR:-genvm_cache}:/genvm-cache - depends_on: - database-migration: - condition: service_completed_successfully - webdriver: - condition: service_healthy - redis: - condition: service_healthy - ollama: - condition: service_started - required: false - jsonrpc: - condition: service_healthy - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:4001/health"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 180s - mem_limit: ${COMPOSE_WORKER_MEM_LIMIT:-8g} - mem_reservation: ${COMPOSE_WORKER_MEM_RESERVATION:-2g} - memswap_limit: ${COMPOSE_WORKER_MEM_SWAP_LIMIT:-8g} - oom_kill_disable: false - deploy: - replicas: ${CONSENSUS_WORKERS:-1} # Minimum 1 worker required for consensus processing - restart_policy: - condition: on-failure # Only restart on failure (not on clean exit) - delay: 5s - max_attempts: 0 - window: 120s - resources: - limits: - cpus: '${COMPOSE_WORKER_CPU_LIMIT:-2}' - memory: ${COMPOSE_WORKER_MEM_LIMIT:-8g} - reservations: - cpus: ${COMPOSE_WORKER_CPU_RESERVATION:-1} - memory: ${COMPOSE_WORKER_MEM_RESERVATION:-2g} - restart: unless-stopped - security_opt: - - "no-new-privileges=true" - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - - # hardhat: - # profiles: ["hardhat"] - # build: - # context: . - # dockerfile: docker/Dockerfile.hardhat - # ports: - # - "${HARDHAT_PORT:-8545}:8545" - # env_file: - # - .env - # volumes: - # - ./hardhat:/app/hardhat_src - # - hardhat_artifacts:/app/artifacts - # - hardhat_cache:/app/cache - # - hardhat_deployments:/app/deployments - # - hardhat_snapshots:/app/snapshots - # restart: always - # logging: - # driver: "json-file" - # options: - # max-size: "50m" - # max-file: "10" - # # For local dev, hardhat is accessed directly on its port - - redis: - image: redis:8-alpine - ports: - - "${REDISPORT:-6379}:6379" - volumes: - - redis_data:/data - healthcheck: - test: ["CMD", "redis-cli", "ping"] - interval: 10s - timeout: 3s - retries: 3 - restart: always - security_opt: - - "no-new-privileges=true" - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - - vector: - profiles: ["monitoring"] # Only run when monitoring is needed - image: timberio/vector:0.53.0-alpine - container_name: vector - environment: - - GOOGLE_APPLICATION_CREDENTIALS=/etc/vector/gcp_credentials.json - - VECTOR_LOG=info - - GCP_PROJECT_ID=${GCP_PROJECT_ID} - - SERVER_NAME=${SERVER_NAME} - volumes: - - ./vector.yaml:/etc/vector/vector.yaml:ro - - /var/run/docker.sock:/var/run/docker.sock:ro - - ./gcp_credentials.json:/etc/vector/gcp_credentials.json:ro - - /var/log:/var/log:ro # Mount the host's /var/log directory - # network_mode: host - restart: unless-stopped - logging: - driver: "json-file" - options: - max-size: "10m" - max-file: "3" - labels: - org.label-schema.group: "monitoring" - -volumes: - # hardhat_artifacts: - # hardhat_cache: - # hardhat_deployments: - ignition_deployments: - # hardhat_snapshots: - genvm_cache: - postgres_data: - redis_data: +services: + traefik: + profiles: ["studio"] + image: traefik:v3.6 + command: + # Core configuration + - "--providers.docker=true" + - "--providers.docker.exposedbydefault=false" + - "--providers.file.filename=/etc/traefik/tls.yml" + - "--providers.file.watch=true" + + # Entrypoints for local development + - "--entrypoints.web.address=:80" + - "--entrypoints.websecure.address=:443" # Needed for frontend/hardhat labels + # API Dashboard (for local dev monitoring) + - "--api.dashboard=true" + # Extended timeouts for large contract state loading (20 minutes to match GenVM timeout) + - "--entryPoints.web.transport.respondingTimeouts.readTimeout=1200s" + - "--entryPoints.web.transport.respondingTimeouts.writeTimeout=1200s" + - "--entryPoints.web.transport.respondingTimeouts.idleTimeout=1200s" + - "--entryPoints.websecure.transport.respondingTimeouts.readTimeout=1200s" + - "--entryPoints.websecure.transport.respondingTimeouts.writeTimeout=1200s" + - "--entryPoints.websecure.transport.respondingTimeouts.idleTimeout=1200s" + # Server transport with extended forwarding timeouts + - "--serversTransport.forwardingTimeouts.responseHeaderTimeout=1200s" + - "--serversTransport.forwardingTimeouts.idleConnTimeout=1200s" + ports: + - "80:80" + - "443:443" + - "8081:8080" # Traefik dashboard (8081 to avoid conflict with frontend on 8080) + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + - /opt/genlayer-studio/nginx/ssl/:/etc/ssl/traefik:ro + - ./traefik/tls.yml:/etc/traefik/tls.yml:ro + logging: + driver: "json-file" + options: + max-size: "50m" + max-file: "10" + + frontend: + build: + context: ./ + dockerfile: ./docker/Dockerfile.frontend + target: ${FRONTEND_BUILD_TARGET:-final} + ports: + - "${FRONTEND_PORT}:8080" + volumes: + - ./examples:/app/src/assets/examples + - ./frontend/src:/app/src + depends_on: + jsonrpc: + condition: service_healthy + expose: + - "${FRONTEND_PORT}" + environment: + - VITE_GENLAYER_NETWORK=${VITE_GENLAYER_NETWORK} + - VITE_CHAIN_ID=${VITE_CHAIN_ID} + - VITE_CHAIN_NAME=${VITE_CHAIN_NAME} + - VITE_JSON_RPC_SERVER_URL=${VITE_JSON_RPC_SERVER_URL} + - VITE_WS_SERVER_URL=${VITE_WS_SERVER_URL} + - VITE_IS_HOSTED=${VITE_IS_HOSTED} + - VITE_FINALITY_WINDOW=${VITE_FINALITY_WINDOW} + - VITE_FINALITY_WINDOW_APPEAL_FAILED_REDUCTION=${VITE_FINALITY_WINDOW_APPEAL_FAILED_REDUCTION} + - VITE_MAX_ROTATIONS=${VITE_MAX_ROTATIONS} + - VITE_PLAUSIBLE_DOMAIN=${VITE_PLAUSIBLE_DOMAIN} + - VITE_APPKIT_PROJECT_ID=${VITE_APPKIT_PROJECT_ID} + - VITE_EXPLORER_URL=${VITE_EXPLORER_URL} + - VITE_LOCK_NETWORK=${VITE_LOCK_NETWORK} + - GENLAYER_CHAIN_ID=${GENLAYER_CHAIN_ID} + - HARDHAT_CHAIN_ID=${HARDHAT_CHAIN_ID} + restart: always + security_opt: + - "no-new-privileges=true" + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + labels: + traefik.enable: true + traefik.http.routers.frontend.rule: Host(`${SERVER_NAME}`) + traefik.http.routers.frontend.entrypoints: websecure + traefik.http.routers.frontend.tls: true + + explorer: + build: + context: ./ + dockerfile: ./docker/Dockerfile.explorer + target: ${EXPLORER_BUILD_TARGET:-final} + ports: + - "${EXPLORER_PORT:-3001}:3000" + volumes: + - ./explorer/src:/app/src + depends_on: + jsonrpc: + condition: service_healthy + environment: + - BACKEND_URL=http://jsonrpc:4000 + restart: always + security_opt: + - "no-new-privileges=true" + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + + jsonrpc: + build: + context: ./ + dockerfile: ./docker/Dockerfile.backend + target: prod + args: + GENVM_TAG: ${GENVM_TAG:-} + GENVM_REF: ${GENVM_REF:-} + GENVM_SOURCE_MODE: ${GENVM_SOURCE_MODE:-} + GENVM_EXECUTOR_VERSION_NAME: ${GENVM_EXECUTOR_VERSION_NAME:-} + environment: + - PYTHONUNBUFFERED=1 + - WEBDRIVERHOST=${WEBDRIVERHOST} + - WEBDRIVERPORT=${WEBDRIVERPORT} + - REDIS_URL=${REDIS_URL:-redis://redis:6379/0} + - WEB_CONCURRENCY=${WEB_CONCURRENCY:-1} + - DATABASE_POOL_SIZE=${DATABASE_POOL_SIZE:-20} + - DATABASE_MAX_OVERFLOW=${DATABASE_MAX_OVERFLOW:-10} + - LOG_LEVEL=${LOG_LEVEL:-info} + - GENVMROOT=/genvm + - RATE_LIMIT_ENABLED=${RATE_LIMIT_ENABLED:-false} + - RATE_LIMIT_ANON_PER_MINUTE=${RATE_LIMIT_ANON_PER_MINUTE:-30} + - RATE_LIMIT_ANON_PER_HOUR=${RATE_LIMIT_ANON_PER_HOUR:-500} + - RATE_LIMIT_ANON_PER_DAY=${RATE_LIMIT_ANON_PER_DAY:-5000} + - GENLAYER_STUDIO_GEN_PER_TIME_UNIT=${GENLAYER_STUDIO_GEN_PER_TIME_UNIT:-1000000000000000} + - GENLAYER_STUDIO_STORAGE_UNIT_PRICE=${GENLAYER_STUDIO_STORAGE_UNIT_PRICE:-1} + - GENLAYER_STUDIO_RECEIPT_GAS_PRICE=${GENLAYER_STUDIO_RECEIPT_GAS_PRICE:-1} + - GENLAYER_STUDIO_FIXED_PROPOSE_RECEIPT_GAS=${GENLAYER_STUDIO_FIXED_PROPOSE_RECEIPT_GAS:-210000} + - GENLAYER_STUDIO_FIXED_MESSAGE_REVEAL_GAS=${GENLAYER_STUDIO_FIXED_MESSAGE_REVEAL_GAS:-100000} + - GENLAYER_STUDIO_RECEIPT_WRAPPER_BYTES=${GENLAYER_STUDIO_RECEIPT_WRAPPER_BYTES:-1024} + # Per-contract / per-sender PENDING tx caps (admission control on + # eth_sendRawTransaction). Empty/unset = no cap. Set in shared + # deployments to keep one heavy user from filling the queue. + - MAX_PENDING_PER_CONTRACT_DEFAULT=${MAX_PENDING_PER_CONTRACT_DEFAULT:-} + - MAX_PENDING_PER_SENDER_DEFAULT=${MAX_PENDING_PER_SENDER_DEFAULT:-} + ports: + - "${RPCHOSTPORT:-4000}:${RPCPORT:-4000}" + expose: + - "${RPCPORT}" + volumes: + - ./.env:/app/.env + - ./backend:/app/backend + - ${GENVM_CACHE_DIR:-genvm_cache}:/genvm-cache + # - hardhat_artifacts:/app/hardhat/artifacts + # - hardhat_deployments:/app/hardhat/deployments + depends_on: + traefik: + condition: service_started + required: false + database-migration: + condition: service_completed_successfully + webdriver: + condition: service_healthy + redis: + condition: service_healthy + # hardhat: + # condition: service_healthy + # required: false + ollama: + condition: service_started + required: false + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:${RPCPORT}/health"] + interval: 30s + timeout: 10s + retries: 5 + start_period: 300s + restart: always + security_opt: + - "no-new-privileges=true" + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + mem_limit: ${COMPOSE_RPC_MEM_LIMIT:-8g} + mem_reservation: ${COMPOSE_RPC_MEM_RESERVATION:-2g} + memswap_limit: ${COMPOSE_RPC_MEM_SWAP_LIMIT:-8g} + oom_kill_disable: false + deploy: + replicas: ${JSONRPC_REPLICAS:-3} + resources: + limits: + cpus: '${COMPOSE_RPC_CPU_LIMIT:-2}' + memory: ${COMPOSE_RPC_MEM_LIMIT:-8g} + reservations: + cpus: ${COMPOSE_RPC_CPU_RESERVATION:-1} + memory: ${COMPOSE_RPC_MEM_RESERVATION:-2g} + labels: + traefik.enable: true + # Define service with port + traefik.http.services.jsonrpc.loadbalancer.server.port: ${RPCPORT} + # HTTPS router for main API + traefik.http.routers.jsonrpc.rule: Host(`${SERVER_NAME}`) && (PathPrefix(`/api`) || PathPrefix(`/socket.io`) || PathPrefix(`/ws`) || PathPrefix(`/monitoring`)) + traefik.http.routers.jsonrpc.entrypoints: websecure + traefik.http.routers.jsonrpc.tls: true + traefik.http.routers.jsonrpc.service: jsonrpc + # HTTP router for health endpoints (no TLS required) + traefik.http.routers.jsonrpc-health.rule: Host(`${SERVER_NAME}`) && (PathPrefix(`/health`) || PathPrefix(`/ready`) || PathPrefix(`/metrics`)) + traefik.http.routers.jsonrpc-health.entrypoints: web + traefik.http.routers.jsonrpc-health.service: jsonrpc + + webdriver: + image: yeagerai/genlayer-genvm-webdriver:0.0.9 + shm_size: 2gb + environment: + - PORT=${WEBDRIVERPORT:-4444} + expose: + - "${WEBDRIVERPORT:-4444}" + restart: always + security_opt: + - "no-new-privileges=true" + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + mem_limit: 16g + mem_reservation: 2g + memswap_limit: 24g + oom_kill_disable: false + deploy: + resources: + limits: + cpus: 2 + memory: 16g + reservations: + cpus: 1 + memory: 2g + + ollama: + profiles: ["ollama"] + image: ollama/ollama:0.17.6 + ports: + - 11434:11434 + volumes: + - ./.ollama:/root/.ollama + container_name: ollama + tty: true + restart: always + security_opt: + - "no-new-privileges=true" + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + + postgres: + image: postgres:16-alpine + command: sh -c "if [ \"$REMOTE_DATABASE\" = \"true\" ]; then echo 'Postgres disabled in hosted environment' && exec tail -f /dev/null; else exec docker-entrypoint.sh postgres; fi" + ports: + - "${DBHOSTPORT:-5432}:5432" + environment: + - POSTGRES_USER=${DBUSER} + - POSTGRES_PASSWORD=${DBPASSWORD} + - POSTGRES_DB=${DBNAME} + - REMOTE_DATABASE=${REMOTE_DATABASE} + healthcheck: + test: if [ "$REMOTE_DATABASE" = "true" ]; then exit 0; else pg_isready -U ${DBUSER} -d ${DBNAME}; fi + interval: 10s + timeout: 3s + retries: 3 + restart: always + security_opt: + - "no-new-privileges=true" + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + # Database data - use 'docker compose down -v' to wipe + volumes: + - postgres_data:/var/lib/postgresql/data + + database-migration: + build: + context: . + dockerfile: docker/Dockerfile.database-migration + environment: + - DBUSER=${DBUSER} + - DBPASSWORD=${DBPASSWORD} + - DBHOST=${DBHOST} + - DBPORT=${DBPORT} + - DBNAME=${DBNAME} + depends_on: + postgres: + condition: service_healthy + required: false + + consensus-worker: + build: + context: ./ + dockerfile: ./docker/Dockerfile.consensus-worker + target: ${CONSENSUS_BUILD_TARGET:-base} + args: + GENVM_TAG: ${GENVM_TAG:-} + GENVM_REF: ${GENVM_REF:-} + GENVM_SOURCE_MODE: ${GENVM_SOURCE_MODE:-} + GENVM_EXECUTOR_VERSION_NAME: ${GENVM_EXECUTOR_VERSION_NAME:-} + environment: + - DBUSER=${DBUSER} + - DBPASSWORD=${DBPASSWORD} + - DBHOST=${DBHOST} + - DBNAME=${DBNAME} + - WORKER_PORT=4001 + - GENVM_DEBUG_MODE=${GENVM_DEBUG_MODE:-false} + - WORKER_POLL_INTERVAL=${WORKER_POLL_INTERVAL:-5} + - TRANSACTION_TIMEOUT_MINUTES=${TRANSACTION_TIMEOUT_MINUTES:-30} + - LOG_LEVEL=${LOG_LEVEL:-info} + - WEBDRIVERHOST=${WEBDRIVERHOST} + - WEBDRIVERPORT=${WEBDRIVERPORT} + - REDIS_URL=${REDIS_URL:-redis://redis:6379/0} + - GENLAYER_STUDIO_GEN_PER_TIME_UNIT=${GENLAYER_STUDIO_GEN_PER_TIME_UNIT:-1000000000000000} + - GENLAYER_STUDIO_STORAGE_UNIT_PRICE=${GENLAYER_STUDIO_STORAGE_UNIT_PRICE:-1} + - GENLAYER_STUDIO_RECEIPT_GAS_PRICE=${GENLAYER_STUDIO_RECEIPT_GAS_PRICE:-1} + - GENLAYER_STUDIO_FIXED_PROPOSE_RECEIPT_GAS=${GENLAYER_STUDIO_FIXED_PROPOSE_RECEIPT_GAS:-210000} + - GENLAYER_STUDIO_FIXED_MESSAGE_REVEAL_GAS=${GENLAYER_STUDIO_FIXED_MESSAGE_REVEAL_GAS:-100000} + - GENLAYER_STUDIO_RECEIPT_WRAPPER_BYTES=${GENLAYER_STUDIO_RECEIPT_WRAPPER_BYTES:-1024} + volumes: + - ./.env:/app/.env + - ./backend:/app/backend + - ${GENVM_CACHE_DIR:-genvm_cache}:/genvm-cache + depends_on: + database-migration: + condition: service_completed_successfully + webdriver: + condition: service_healthy + redis: + condition: service_healthy + ollama: + condition: service_started + required: false + jsonrpc: + condition: service_healthy + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:4001/health"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 180s + mem_limit: ${COMPOSE_WORKER_MEM_LIMIT:-8g} + mem_reservation: ${COMPOSE_WORKER_MEM_RESERVATION:-2g} + memswap_limit: ${COMPOSE_WORKER_MEM_SWAP_LIMIT:-8g} + oom_kill_disable: false + deploy: + replicas: ${CONSENSUS_WORKERS:-1} # Minimum 1 worker required for consensus processing + restart_policy: + condition: on-failure # Only restart on failure (not on clean exit) + delay: 5s + max_attempts: 0 + window: 120s + resources: + limits: + cpus: '${COMPOSE_WORKER_CPU_LIMIT:-2}' + memory: ${COMPOSE_WORKER_MEM_LIMIT:-8g} + reservations: + cpus: ${COMPOSE_WORKER_CPU_RESERVATION:-1} + memory: ${COMPOSE_WORKER_MEM_RESERVATION:-2g} + restart: unless-stopped + security_opt: + - "no-new-privileges=true" + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + + # hardhat: + # profiles: ["hardhat"] + # build: + # context: . + # dockerfile: docker/Dockerfile.hardhat + # ports: + # - "${HARDHAT_PORT:-8545}:8545" + # env_file: + # - .env + # volumes: + # - ./hardhat:/app/hardhat_src + # - hardhat_artifacts:/app/artifacts + # - hardhat_cache:/app/cache + # - hardhat_deployments:/app/deployments + # - hardhat_snapshots:/app/snapshots + # restart: always + # logging: + # driver: "json-file" + # options: + # max-size: "50m" + # max-file: "10" + # # For local dev, hardhat is accessed directly on its port + + redis: + image: redis:8-alpine + ports: + - "${REDISPORT:-6379}:6379" + volumes: + - redis_data:/data + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 3s + retries: 3 + restart: always + security_opt: + - "no-new-privileges=true" + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + + vector: + profiles: ["monitoring"] # Only run when monitoring is needed + image: timberio/vector:0.53.0-alpine + container_name: vector + environment: + - GOOGLE_APPLICATION_CREDENTIALS=/etc/vector/gcp_credentials.json + - VECTOR_LOG=info + - GCP_PROJECT_ID=${GCP_PROJECT_ID} + - SERVER_NAME=${SERVER_NAME} + volumes: + - ./vector.yaml:/etc/vector/vector.yaml:ro + - /var/run/docker.sock:/var/run/docker.sock:ro + - ./gcp_credentials.json:/etc/vector/gcp_credentials.json:ro + - /var/log:/var/log:ro # Mount the host's /var/log directory + # network_mode: host + restart: unless-stopped + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + labels: + org.label-schema.group: "monitoring" + +volumes: + # hardhat_artifacts: + # hardhat_cache: + # hardhat_deployments: + ignition_deployments: + # hardhat_snapshots: + genvm_cache: + postgres_data: + redis_data: