diff --git a/Dockerfile b/Dockerfile index f0cfa9a..4caeb33 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,38 +5,14 @@ FROM ubuntu:20.04 RUN apt-get update && apt-get install -y --no-install-recommends \ curl \ jq \ + sudo \ ca-certificates \ tini \ && rm -rf /var/lib/apt/lists/* -# Set default environment variables -ENV ROOT_PATH=/opt/mev-commit -ENV BINARY_PATH=${ROOT_PATH}/mev-commit -ENV DOMAIN=${DOMAIN} -ENV ARTIFACTS_URL=https://github.com/primev/mev-commit/releases/latest/download -ENV VERSION=${MEV_COMMIT_VERSION} -ENV ARTIFACTS_BASE_URL=https://github.com/primev/mev-commit/releases -ENV AUTO_DEPOSIT_VALUE=${AUTO_DEPOSIT_VALUE} -# Create the directory for mev-commit -RUN mkdir -p ${ROOT_PATH} -WORKDIR ${ROOT_PATH} - -# Download and install the latest mev-commit binary -RUN VERSION=$(curl -sIL -o /dev/null -w %{url_effective} https://github.com/primev/mev-commit/releases/latest | sed 's:.*/::' | sed 's/^v//') \ - && echo "Latest version: $VERSION" \ - && FILE="mev-commit_${VERSION}_Linux_x86_64.tar.gz" \ - && echo "Downloading $FILE" \ - && curl -sL "${ARTIFACTS_URL}/${FILE}" -o "${FILE}" \ - && tar -xzf "${FILE}" -C "${ROOT_PATH}" \ - && chmod +x ${BINARY_PATH} \ - && echo "export MEV_COMMIT_VERSION=${VERSION}" >> /etc/environment - -# Expose http port. Not sure if actuallly needed -EXPOSE 13523 - # Copy the entrypoint script into the image COPY entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh # Use tini as the init system -ENTRYPOINT ["/usr/bin/tini", "--", "/entrypoint.sh"] +ENTRYPOINT ["/usr/bin/tini", "--", "/entrypoint.sh"] \ No newline at end of file diff --git a/entrypoint.sh b/entrypoint.sh old mode 100644 new mode 100755 index 78f8a40..60637a8 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -2,116 +2,248 @@ set -e -# Load the mev-commit version from environment -source /etc/environment +############################################################################### +# 1) Source .env if it exists +############################################################################### +load_env_file() { + local env_file="$1" + if [ -f "$env_file" ]; then + echo "Loading environment variables from $env_file" + # shellcheck disable=SC1090,SC1091 + set -o allexport + source "$env_file" + set +o allexport + fi +} + +# Load .env from same directory as the script +load_env_file "$(dirname "$(realpath "$0")")/.env" -# Configuration Variables +############################################################################### +# 2) Set defaults +############################################################################### APP_NAME="mev-commit" ENVIRONMENT="${ENVIRONMENT:-production}" -VERSION="${MEV_COMMIT_VERSION:-unknown}" -LOG_FORMAT="${MEV_COMMIT_LOG_FMT:-json}" -LOG_LEVEL_INFO="INFO" -LOG_LEVEL_ERROR="ERROR" - -# Log Functions -log_info() { - echo '{ - "timestamp": "'"$(date --iso-8601=seconds)"'", - "level": "'"$LOG_LEVEL_INFO"'", - "app": "'"$APP_NAME"'", - "environment": "'"$ENVIRONMENT"'", - "version": "'"$VERSION"'", - "message": "'"$1"'" - }' -} +MEV_COMMIT_VERSION="${MEV_COMMIT_VERSION:-unknown}" +DOMAIN="${DOMAIN:-testnet.mev-commit.xyz}" +AUTO_DEPOSIT_VALUE="${AUTO_DEPOSIT_VALUE:-300000000000000000}" # Default 0.3 ETH +BINARY_PATH="${BINARY_PATH:-/usr/local/bin/mev-commit}" +ARTIFACTS_BASE_URL="https://github.com/primev/mev-commit/releases" +RPC_URL="${RPC_URL:-wss://chainrpc-wss.${DOMAIN}}" + +# Logging +LOG_FMT="${LOG_FMT:-json}" +LOG_LEVEL="${LOG_LEVEL:-info}" + +# For mev-commit >= v0.8.0, we must pass a file to --priv-key-file. +# We'll use an in-memory file descriptor so the key never touches disk. +PRIV_KEY_FD="/proc/self/fd/3" + +echo "Using RPC_URL=${RPC_URL}" + +############################################################################### +# 3) (Optional) Download mev-commit if needed +############################################################################### +INSTALLED_VERSION="" +if command -v "${BINARY_PATH}" &> /dev/null; then + INSTALLED_VERSION=$("${BINARY_PATH}" --version 2>/dev/null | awk '{print $3}') + echo "Installed mev-commit version: ${INSTALLED_VERSION}" +fi -log_error() { - echo '{ - "timestamp": "'"$(date --iso-8601=seconds)"'", - "level": "'"$LOG_LEVEL_ERROR"'", - "app": "'"$APP_NAME"'", - "environment": "'"$ENVIRONMENT"'", - "version": "'"$VERSION"'", - "message": "'"$1"'" - }' >&2 -} +if [ "${MEV_COMMIT_VERSION}" = "unknown" ]; then + LATEST_VERSION=$(curl -sIL -o /dev/null -w %{url_effective} \ + https://github.com/primev/mev-commit/releases/latest \ + | sed 's:.*/::' | sed 's/^v//') + echo "Latest mev-commit version: ${LATEST_VERSION}" +else + LATEST_VERSION=${MEV_COMMIT_VERSION} + echo "Using mev-commit version: ${LATEST_VERSION}" +fi -# Print the mev-commit version -log_info "Running mev-commit version: ${MEV_COMMIT_VERSION}" +# Download if not installed or if the version is out of date +if [ -z "${INSTALLED_VERSION}" ] || [ "${INSTALLED_VERSION}" != "${LATEST_VERSION}" ]; then + echo "Downloading mev-commit ${LATEST_VERSION}..." + FILE="mev-commit_${LATEST_VERSION}_Linux_x86_64.tar.gz" + DOWNLOAD_URL="${ARTIFACTS_BASE_URL}/download/v${LATEST_VERSION}/${FILE}" + TEMP_DIR=$(mktemp -d) -# Set variables based on DOMAIN -RPC_URL="wss://chainrpc-wss.${DOMAIN}" -BOOTNODE="/dnsaddr/bootnode.${DOMAIN}" -CONTRACTS_URL="https://contracts.${DOMAIN}" + curl -sL "${DOWNLOAD_URL}" -o "${TEMP_DIR}/${FILE}" + echo "Extracting ${FILE} to ${TEMP_DIR}..." + tar -xzf "${TEMP_DIR}/${FILE}" -C "${TEMP_DIR}" -# Fetch contracts.json and export necessary environment variables -contracts_json=$(curl -sL "${CONTRACTS_URL}") -if ! echo "${contracts_json}" | jq . > /dev/null 2>&1; then - log_error "Failed to fetch contracts from ${CONTRACTS_URL}" - exit 1 + echo "Installing mev-commit to ${BINARY_PATH}..." + sudo mv "${TEMP_DIR}/mev-commit" "${BINARY_PATH}" + sudo chmod +x "${BINARY_PATH}" + + rm -rf "${TEMP_DIR}" + echo "mev-commit downloaded and installed to ${BINARY_PATH}" +else + echo "Using existing mev-commit binary found at ${BINARY_PATH}" fi -export MEV_COMMIT_BLOCK_TRACKER_ADDR=$(echo "${contracts_json}" | jq -r '.BlockTracker') -export MEV_COMMIT_BIDDER_REGISTRY_ADDR=$(echo "${contracts_json}" | jq -r '.BidderRegistry') -export MEV_COMMIT_PRECONF_ADDR=$(echo "${contracts_json}" | jq -r '.PreconfManager') -export MEV_COMMIT_LOG_FMT="${MEV_COMMIT_LOG_FMT:-json}" +############################################################################### +# 4) Print usage/info +############################################################################### +echo "**********************************************************************" +echo " Starting up the mev-commit Bidder Node (v0.8.0) " +echo "**********************************************************************" +echo "" +echo "Configuration variables (current defaults):" +echo " PRIVATE_KEY_BIDDER (required) - your Ethereum private key" +echo " DOMAIN: ${DOMAIN}" +echo " AUTO_DEPOSIT_VALUE: ${AUTO_DEPOSIT_VALUE} (Wei)" +echo " ENVIRONMENT: ${ENVIRONMENT}" +echo " MEV_COMMIT_VERSION: ${MEV_COMMIT_VERSION}" +echo " BINARY_PATH: ${BINARY_PATH}" +echo " RPC_URL: ${RPC_URL}" +echo "" +echo "You can set these in a .env file or pass CLI args. Example usage:" +echo " ./entrypoint.sh --private-key --auto-deposit 1000000000000000000" +echo "" + +############################################################################### +# 5) Parse CLI arguments +############################################################################### +while [[ $# -gt 0 ]]; do + case "$1" in + --domain) + DOMAIN="$2" + shift 2 + ;; + --private-key) + PRIVATE_KEY_BIDDER="$2" + shift 2 + ;; + --auto-deposit) + AUTO_DEPOSIT_VALUE="$2" + shift 2 + ;; + --binary-path) + BINARY_PATH="$2" + shift 2 + ;; + --environment) + ENVIRONMENT="$2" + shift 2 + ;; + --mev-commit-version) + MEV_COMMIT_VERSION="$2" + shift 2 + ;; + --rpc-url) + RPC_URL="$2" + shift 2 + ;; + --log-fmt) + LOG_FMT="$2" + shift 2 + ;; + --log-level) + LOG_LEVEL="$2" + shift 2 + ;; + *) + echo "Unknown parameter: $1" + exit 1 + ;; + esac +done + +############################################################################### +# 6) Ensure private key is set (prompt only if missing) +############################################################################### +if [ -z "${PRIVATE_KEY_BIDDER}" ]; then + echo "No PRIVATE_KEY_BIDDER environment variable found." + read -r -s -p "Enter your private key (hex, no 0x): " PRIVATE_KEY_BIDDER + echo "" +fi -# Check if PRIVATE_KEY_BIDDER is set if [ -z "${PRIVATE_KEY_BIDDER}" ]; then - log_error "PRIVATE_KEY_BIDDER environment variable is not set" + echo "Error: No private key provided!" exit 1 +fi + +############################################################################### +# 7) Decide on auto-deposit (skip prompt if AUTO_DEPOSIT_VALUE is already set) +############################################################################### +# If user didn't override AUTO_DEPOSIT_VALUE, ask if they want the default +if [ "${AUTO_DEPOSIT_VALUE}" = "300000000000000000" ]; then + # It's still the default. Confirm if user wants to override + echo "Current auto-deposit: ${AUTO_DEPOSIT_VALUE} (default 0.3 ETH)." + read -r -p "Use the default auto-deposit value? (y/n): " USE_DEFAULT_DEPOSIT + if [[ ! "${USE_DEFAULT_DEPOSIT,,}" =~ ^(y|yes)$ ]]; then + read -r -p "Enter custom auto-deposit value (in Wei): " AUTO_DEPOSIT_VALUE + fi else - log_info "PRIVATE_KEY_BIDDER is set." - # Write the private key to key - echo "${PRIVATE_KEY_BIDDER}" > "${ROOT_PATH}/key" - # Secure the key file by restricting permissions - chmod 600 "${ROOT_PATH}/key" - # Export MEV_COMMIT_PRIVKEY_FILE to point to the key file - export MEV_COMMIT_PRIVKEY_FILE="${ROOT_PATH}/key" + # If the user specified a custom value in ENV or CLI, skip the prompt + echo "Using auto-deposit value from environment: ${AUTO_DEPOSIT_VALUE}" fi -# Define flags for mev-commit +# For a bidder node, we enable auto-deposit by default +AUTO_DEPOSIT_ENABLED="true" + +############################################################################### +# 8) Fetch contract addresses from ${CONTRACTS_URL} +############################################################################### +BOOTNODE="/dnsaddr/bootnode.${DOMAIN}" +CONTRACTS_URL="https://contracts.${DOMAIN}" + +contracts_json=$(curl -sL "${CONTRACTS_URL}") +if ! echo "${contracts_json}" | jq . > /dev/null 2>&1; then + echo "Failed to fetch contracts from ${CONTRACTS_URL}" + exit 1 +fi + +BIDDER_REGISTRY_ADDR=$(echo "${contracts_json}" | jq -r '.BidderRegistry') +PROVIDER_REGISTRY_ADDR=$(echo "${contracts_json}" | jq -r '.ProviderRegistry') +BLOCK_TRACKER_ADDR=$(echo "${contracts_json}" | jq -r '.BlockTracker') +PRECONF_ADDR=$(echo "${contracts_json}" | jq -r '.PreconfManager') + +############################################################################### +# 9) Build CLI flags for mev-commit 0.8.0 +############################################################################### FLAGS=( - --settlement-ws-rpc-endpoint "${RPC_URL}" - --peer-type "bidder" - --bootnodes "${BOOTNODE}" - --log-tags "service:docker-mev-commit-bidder" - --bidder-bid-timeout "15s" # Override timeout here -) + --peer-type "bidder" -# Start mev-commit in the background -${BINARY_PATH} "${FLAGS[@]}" & + # Settlement RPC (WebSocket) + --settlement-ws-rpc-endpoint "${RPC_URL}" -PID=$! + # Logging + --log-fmt "${LOG_FMT}" + --log-level "${LOG_LEVEL}" -# Function to wait for mev-commit to be ready -wait_for_health() { - log_info "Waiting for mev-commit to be ready..." - until curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:13523/health | grep -q 200; do - sleep 1 - done - log_info "mev-commit is ready." -} + # Bootnodes + --bootnodes "${BOOTNODE}" -# Function to send auto deposit request -send_auto_deposit() { - log_info "Sending auto deposit request..." - response=$(curl --silent --show-error --output /dev/null --write-out "%{http_code}" --request POST "http://127.0.0.1:13523/v1/bidder/auto_deposit/${AUTO_DEPOSIT_VALUE}") - if [ "${response}" -ne 200 ]; then - log_error "Failed to send auto deposit request, status code: ${response}" - else - log_info "Auto deposit request sent successfully" - fi -} + # Key file is read from an in-memory FD + --priv-key-file "${PRIV_KEY_FD}" -# Wait for mev-commit to be ready -wait_for_health + # Bidder-specific + --bidder-bid-timeout "15s" -# Send auto deposit request once -send_auto_deposit + # Contracts + --bidder-registry-contract "${BIDDER_REGISTRY_ADDR}" + --provider-registry-contract "${PROVIDER_REGISTRY_ADDR}" + --block-tracker-contract "${BLOCK_TRACKER_ADDR}" + --preconf-contract "${PRECONF_ADDR}" -# Trap to handle script termination and clean up background jobs -trap "log_info 'Received termination signal. Exiting...'; kill ${PID}; kill 0; exit 0" SIGINT SIGTERM + # Auto-deposit + --autodeposit-enabled="${AUTO_DEPOSIT_ENABLED}" + --autodeposit-amount "${AUTO_DEPOSIT_VALUE}" +) -# Wait for mev-commit process to exit -wait ${PID} +############################################################################### +# 10) Start mev-commit without writing key to disk +############################################################################### +echo "" +echo "Starting mev-commit with the following flags:" +for f in "${FLAGS[@]}"; do + echo " $f" +done +echo "" + +# We open a file descriptor (FD #3) containing the private key in memory. +# mev-commit reads that FD as if it were a file, but nothing is written to disk. +exec 3<<< "${PRIVATE_KEY_BIDDER}" + +exec "${BINARY_PATH}" "${FLAGS[@]}"