diff --git a/.env.example b/.env.example index 2d18a8b..22e0680 100644 --- a/.env.example +++ b/.env.example @@ -8,9 +8,12 @@ SKIP_DEPLOYMENT_CHECK=false # SEQUENCER_MODE: 'true' enables sequencer, runs op-batcher/op-proposer; 'false' disables them. Default: true. SEQUENCER_MODE=true -# CELESTIA_MODE: 'true' runs celestia-da service; 'false' disables it. Default: true. +# CELESTIA_MODE: 'true' runs celestia-da service; 'false' disables it. Default: false. CELESTIA_MODE=false +# SIGNER_PROXY: 'true' runs signer-proxy service; 'false' disables it. Default: false. +SIGNER_PROXY=false + ################################################## # Cloning Configuration # ################################################## diff --git a/Dockerfile.services b/Dockerfile.services index 2b888a0..d39fdf4 100644 --- a/Dockerfile.services +++ b/Dockerfile.services @@ -21,6 +21,7 @@ RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2 # Define work directory WORKDIR /app +COPY scripts/utils.sh /app/utils.sh COPY ./entrypoints/${ENTRYPOINT_SCRIPT} /app/entrypoint.sh RUN chmod +x /app/entrypoint.sh diff --git a/Dockerfile.signer-proxy b/Dockerfile.signer-proxy new file mode 100644 index 0000000..9edba2b --- /dev/null +++ b/Dockerfile.signer-proxy @@ -0,0 +1,22 @@ +FROM rust:1.80.1 as builder + +ARG REPO_URL +ARG TAG + +WORKDIR /app + +RUN git clone -b ${TAG} --depth 1 ${REPO_URL} . && \ + cargo build --release --no-default-features + +FROM debian:bookworm-slim + +WORKDIR /app + +RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/* + +COPY --from=builder /app/target/release/signer-proxy /usr/local/bin/signer-proxy + +COPY ./entrypoints/signer-proxy.sh /app/entrypoint.sh +RUN chmod +x /app/entrypoint.sh + +ENTRYPOINT ["/app/entrypoint.sh"] diff --git a/docker-compose.yml b/docker-compose.yml index 84834ff..0f1d624 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -51,6 +51,27 @@ services: - "host.docker.internal:host-gateway" profiles: ["celestia"] + signer-proxy: + build: + context: . + dockerfile: Dockerfile.signer-proxy + args: + REPO_URL: https://github.com/quertc/signer-proxy.git + TAG: v1.0.0-rc.1 + env_file: + - .env + - signer-proxy.env + expose: + - 4000 + healthcheck: + test: ["CMD-SHELL", "curl -f http://localhost:4000/ping || exit 1"] + interval: 30s + timeout: 10s + retries: 5 + stop_grace_period: 10m + restart: always + profiles: ["signer-proxy"] + op-geth: build: context: . @@ -130,9 +151,13 @@ services: condition: service_healthy op-node: condition: service_healthy + signer-proxy: + condition: service_healthy + required: false env_file: - .env - paths.env + - signer-proxy.env - opbatcher.env ports: - "8548:8548" @@ -157,9 +182,13 @@ services: condition: service_healthy op-node: condition: service_healthy + signer-proxy: + condition: service_healthy + required: false env_file: - .env - paths.env + - signer-proxy.env - opproposer.env ports: - "8560:8560" diff --git a/entrypoints/op-batcher.sh b/entrypoints/op-batcher.sh index 2be6a13..3da2813 100644 --- a/entrypoints/op-batcher.sh +++ b/entrypoints/op-batcher.sh @@ -1,4 +1,23 @@ -#!/bin/sh +#!/bin/bash + +# Check if SIGNER_PROXY environment variable is set to false +if [ "$SIGNER_PROXY" != "true" ]; then + unset OP_BATCHER_SIGNER_ENDPOINT + unset OP_BATCHER_SIGNER_TLS_CA + unset OP_BATCHER_SIGNER_TLS_CERT + unset OP_BATCHER_SIGNER_TLS_KEY +else + # shellcheck disable=SC1091 + . /app/utils.sh + + batcher_address=$(get_address "$OP_BATCHER_SIGNER_ENDPOINT") + if [ -z "$OP_BATCHER_SIGNER_ADDRESS" ]; then + export OP_BATCHER_SIGNER_ADDRESS=$batcher_address + elif [ "$OP_BATCHER_SIGNER_ADDRESS" != "$batcher_address" ]; then + echo "Error: OP_BATCHER_SIGNER_ADDRESS does not match the fetched address." + exit 1 + fi +fi # Check if OP_BATCHER_PRIVATE_KEY environment variable is set if [ -z "$OP_BATCHER_PRIVATE_KEY" ]; then diff --git a/entrypoints/op-geth.sh b/entrypoints/op-geth.sh index 9b511d4..630b569 100644 --- a/entrypoints/op-geth.sh +++ b/entrypoints/op-geth.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Initialize op-geth if datadir is empty if [ -d "$DATADIR_DIR" ] && [ -z "$(ls -A "$DATADIR_DIR")" ]; then diff --git a/entrypoints/op-node.sh b/entrypoints/op-node.sh index b54b27a..afbb37e 100644 --- a/entrypoints/op-node.sh +++ b/entrypoints/op-node.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Check if SEQUENCER_MODE environment variable is set to false if [ "$SEQUENCER_MODE" != "true" ]; then diff --git a/entrypoints/op-proposer.sh b/entrypoints/op-proposer.sh index a5e33f2..2149b9c 100644 --- a/entrypoints/op-proposer.sh +++ b/entrypoints/op-proposer.sh @@ -1,4 +1,23 @@ -#!/bin/sh +#!/bin/bash + +# Check if SIGNER_PROXY environment variable is set to false +if [ "$SIGNER_PROXY" != "true" ]; then + unset OP_PROPOSER_SIGNER_ENDPOINT + unset OP_PROPOSER_SIGNER_TLS_CA + unset OP_PROPOSER_SIGNER_TLS_CERT + unset OP_PROPOSER_SIGNER_TLS_KEY +else + # shellcheck disable=SC1091 + . /app/utils.sh + + proposer_address=$(get_address "$OP_PROPOSER_SIGNER_ENDPOINT") + if [ -z "$OP_PROPOSER_SIGNER_ADDRESS" ]; then + export OP_PROPOSER_SIGNER_ADDRESS="$proposer_address" + elif [ "$OP_PROPOSER_SIGNER_ADDRESS" != "$proposer_address" ]; then + echo "Error: OP_PROPOSER_SIGNER_ADDRESS does not match the fetched address." + exit 1 + fi +fi # Check if OP_PROPOSER_PRIVATE_KEY environment variable is set if [ -z "$OP_PROPOSER_PRIVATE_KEY" ]; then diff --git a/entrypoints/signer-proxy.sh b/entrypoints/signer-proxy.sh new file mode 100644 index 0000000..9907cd5 --- /dev/null +++ b/entrypoints/signer-proxy.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +reqenv() { + if [ -z "${!1}" ]; then + echo "Error: environment variable '$1' is undefined" + exit 1 + fi +} + +reqenv "SIGNER_PROXY_MODE" +reqenv "OP_BATCHER_SIGNER_KEY_ID" +reqenv "OP_PROPOSER_SIGNER_KEY_ID" + +exec signer-proxy "${SIGNER_PROXY_MODE}" serve diff --git a/opbatcher.env b/opbatcher.env index d5b32af..48a2be6 100644 --- a/opbatcher.env +++ b/opbatcher.env @@ -21,3 +21,12 @@ OP_BATCHER_DATA_AVAILABILITY_TYPE=calldata OP_BATCHER_METRICS_ENABLED=true OP_BATCHER_METRICS_ADDR=0.0.0.0 OP_BATCHER_METRICS_PORT=7301 + +# --------------------------------------------------------------------------- +# Signer proxy service configuration +# --------------------------------------------------------------------------- + +OP_BATCHER_SIGNER_ENDPOINT=http://signer-proxy:4000/key/$OP_BATCHER_SIGNER_KEY_ID # You can safely omit OP_BATCHER_SIGNER_ADDRESS +OP_BATCHER_SIGNER_TLS_CA= +OP_BATCHER_SIGNER_TLS_CERT= +OP_BATCHER_SIGNER_TLS_KEY= diff --git a/opproposer.env b/opproposer.env index 6bb4f16..5380d67 100644 --- a/opproposer.env +++ b/opproposer.env @@ -13,3 +13,12 @@ OP_PROPOSER_L1_ETH_RPC=$L1_RPC_URL OP_PROPOSER_METRICS_ENABLED=true OP_PROPOSER_METRICS_ADDR=0.0.0.0 OP_PROPOSER_METRICS_PORT=7302 + +# --------------------------------------------------------------------------- +# Signer proxy service configuration +# --------------------------------------------------------------------------- + +OP_PROPOSER_SIGNER_ENDPOINT=http://signer-proxy:4000/key/$OP_PROPOSER_SIGNER_KEY_ID # You can safely omit OP_PROPOSER_SIGNER_ADDRESS +OP_PROPOSER_SIGNER_TLS_CA= +OP_PROPOSER_SIGNER_TLS_CERT= +OP_PROPOSER_SIGNER_TLS_KEY= diff --git a/run b/run index 36380ca..e6169d2 100755 --- a/run +++ b/run @@ -33,10 +33,14 @@ source .env # Initialize the command command="docker compose" -# Add profiles based on SEQUENCER_MODE and Celestia support +# Add profiles based on SEQUENCER_MODE, SIGNER_PROXY and Celestia support [ "$SEQUENCER_MODE" = "true" ] && command+=" --profile sequencer" [ "$CELESTIA_MODE" = "true" ] && command+=" --profile celestia" +if [ "$SEQUENCER_MODE" = "true" ] && [ "$SIGNER_PROXY" = "true" ]; then + command+=" --profile signer-proxy" +fi + if [ "$SKIP_DEPLOYMENT_CHECK" = "true" ]; then echo -e "${ORANGE}NOTE${NC}: Only genesis.json and rollup.json will be checked (SKIP_DEPLOYMENT_CHECK=$SKIP_DEPLOYMENT_CHECK)." fi @@ -49,7 +53,7 @@ fi command+=" up --build -d" # Confirm before running the command -echo -ne "About to run: ${BLUE}$command${NC} (SEQUENCER_MODE: $SEQUENCER_MODE, CELESTIA_MODE: $CELESTIA_MODE). Do you want to continue? (yes/no): " +echo -ne "About to run: ${BLUE}$command${NC} (SEQUENCER_MODE: $SEQUENCER_MODE, CELESTIA_MODE: $CELESTIA_MODE, SIGNER_PROXY: $SIGNER_PROXY). Do you want to continue? (yes/no): " read -r confirm if [[ "$confirm" =~ ^(yes|y)$ ]]; then eval "$command" diff --git a/scripts/utils.sh b/scripts/utils.sh index 7878b9f..6795a49 100644 --- a/scripts/utils.sh +++ b/scripts/utils.sh @@ -20,3 +20,19 @@ derive_and_check() { export "$addr_var_name"="$derived_address" fi } + +get_address() { + local endpoint=$1 + local response + response=$(curl -s "${endpoint}/address") + + local address + address=$(echo "$response" | jq -r '.address') + + if [ -z "$address" ]; then + echo "Error: Unable to fetch address from ${endpoint}/address" + exit 1 + fi + + echo "$address" +} diff --git a/signer-proxy.env b/signer-proxy.env new file mode 100644 index 0000000..74639cc --- /dev/null +++ b/signer-proxy.env @@ -0,0 +1,55 @@ +############################################################################### +# SIGNER PROXY CONFIGURATION # +############################################################################### + +# Operational mode for the signer proxy: "yubihsm" or "aws-kms" +SIGNER_PROXY_MODE=yubihsm + +# Key id used for op-batcher +OP_BATCHER_SIGNER_KEY_ID= + +# Key id used for op-proposer +OP_PROPOSER_SIGNER_KEY_ID= + +############################################################################### +# ↓ YUBIHSM MODE ↓ # +############################################################################### + +# Connection mode for YubiHSM: "usb" or "http" +YUBIHSM_MODE=usb + +# --------------------------------------------------------------------------- +# Required YubiHSM Settings (for both "usb" and "http" modes) +# --------------------------------------------------------------------------- + +# YubiHSM authentication key ID +YUBIHSM_AUTH_KEY_ID= + +# YubiHSM authentication key password +YUBIHSM_PASSWORD= + +# --------------------------------------------------------------------------- +# USB Mode Settings (only required for "usb" mode) +# --------------------------------------------------------------------------- + +# YubiHSM device serial ID +YUBIHSM_DEVICE_SERIAL_ID= + +# --------------------------------------------------------------------------- +# HTTP Mode Settings (only required for "http" mode) +# --------------------------------------------------------------------------- + +# YubiHSM HTTP address +# YUBIHSM_HTTP_ADDRESS= + +# YubiHSM HTTP port +# YUBIHSM_HTTP_PORT= + +############################################################################### +# ↓ AWS-KMS MODE ↓ # +############################################################################### + +# UNDER WORK +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= +AWS_REGION=