From 51e3f9751d02bad584b5aec939cbc293c5e12361 Mon Sep 17 00:00:00 2001 From: Alex Gartner Date: Wed, 8 Jan 2025 06:46:24 -0800 Subject: [PATCH 1/3] chore: remove main Dockerfile (#3329) --- .../build-docker-images-generic/action.yml | 71 ---- .../actions/build-docker-images/action.yml | 54 --- .github/workflows/docker-build-and-push.yml | 86 ----- Dockerfile | 66 ---- Makefile | 43 --- contrib/docker-scripts/download_binaries.py | 58 --- contrib/docker-scripts/install_cosmovisor.py | 69 ---- contrib/docker-scripts/start.sh | 335 ------------------ contrib/rpc/zetacored/docker-compose.yml | 36 -- contrib/rpc/zetacored/init_docker_compose.sh | 65 ---- contrib/rpc/zetacored/kill_docker_compose.sh | 14 - contrib/rpc/zetacored/networks/.athens3 | 14 - .../zetacored/networks/.athens3-localbuild | 14 - contrib/rpc/zetacored/networks/.mainnet | 14 - .../zetacored/networks/.mainnet-localbuild | 14 - 15 files changed, 953 deletions(-) delete mode 100644 .github/actions/build-docker-images-generic/action.yml delete mode 100644 .github/actions/build-docker-images/action.yml delete mode 100644 .github/workflows/docker-build-and-push.yml delete mode 100644 Dockerfile delete mode 100644 contrib/docker-scripts/download_binaries.py delete mode 100644 contrib/docker-scripts/install_cosmovisor.py delete mode 100644 contrib/docker-scripts/start.sh delete mode 100644 contrib/rpc/zetacored/docker-compose.yml delete mode 100644 contrib/rpc/zetacored/init_docker_compose.sh delete mode 100644 contrib/rpc/zetacored/kill_docker_compose.sh delete mode 100644 contrib/rpc/zetacored/networks/.athens3 delete mode 100644 contrib/rpc/zetacored/networks/.athens3-localbuild delete mode 100644 contrib/rpc/zetacored/networks/.mainnet delete mode 100644 contrib/rpc/zetacored/networks/.mainnet-localbuild diff --git a/.github/actions/build-docker-images-generic/action.yml b/.github/actions/build-docker-images-generic/action.yml deleted file mode 100644 index 245ac8a631..0000000000 --- a/.github/actions/build-docker-images-generic/action.yml +++ /dev/null @@ -1,71 +0,0 @@ -name: 'Build Docker Images' -description: 'Builds Docker images and pushes them to any repository.' -inputs: - DOCKER_FILENAME: - description: 'Name of the docker file to use for the build' - required: true - REPOSITORY_NAME: - description: 'Name of the Repository' - required: true - IMAGE_TAG: - description: 'Image Tag' - required: true - REGISTRY: - description: 'Docker or ORG you want to push to.' - required: true - DOCKER_ORG: - description: 'Docker ORG you want to push to.' - required: false - USERNAME: - description: 'Username for GitHub Container Registry' - required: true - TOKEN: - description: 'Token for GitHub Container Registry' - required: true - DOCKER_FILE_DIRECTORY: - description: 'Directory for your Dockerfile' - required: true - DOCKER_BUILD_KIT: - description: "whether or not to use docker build kit." - required: true - TAG_LATEST: - description: "should the pipeline tag latest" - required: true -runs: - using: "composite" - - steps: - - name: Set Environment Variables" - run: | - echo "DOCKER_BUILDKIT=${{ inputs.DOCKER_BUILD_KIT }}" >> $GITHUB_ENV - shell: bash - - - name: Log in to the Docker Registry - uses: docker/login-action@v2 - with: - registry: ${{ inputs.REGISTRY }} - username: ${{ inputs.USERNAME }} - password: ${{ inputs.TOKEN }} - - - name: Build, tag, and push images - shell: bash - working-directory: ${{ inputs.DOCKER_FILE_DIRECTORY }} - run: | - if [ ! -z "${{ inputs.DOCKER_ORG }}" ]; then - echo "DOCKER ORG SPECIFIED SO USE DOCKER HUB" - docker build -f ${{ inputs.DOCKER_FILENAME }} -t ${{ inputs.DOCKER_ORG }}/${{ inputs.REPOSITORY_NAME }}:${{ inputs.IMAGE_TAG }} . - docker push ${{ inputs.DOCKER_ORG }}/${{ inputs.REPOSITORY_NAME }}:${{ inputs.IMAGE_TAG }} - - if [ "${{ inputs.TAG_LATEST }}" == "true" ]; then - docker tag ${{ inputs.DOCKER_ORG }}/${{ inputs.REPOSITORY_NAME }}:${{ inputs.IMAGE_TAG }} ${{ inputs.DOCKER_ORG }}/${{ inputs.REPOSITORY_NAME }}:latest - docker push ${{ inputs.DOCKER_ORG }}/${{ inputs.REPOSITORY_NAME }}:latest - fi - else - echo "DOCKER REGISTRY SPECIFIED WITH NO DOCKER_ORG USE NON ORG REGISTRIES" - docker build -f ${{ inputs.DOCKER_FILENAME }} -t ${{ inputs.REGISTRY }}/${{ inputs.REPOSITORY_NAME }}:${{ inputs.IMAGE_TAG }} . - docker push ${{ inputs.REGISTRY }}/${{ inputs.REPOSITORY_NAME }}:${{ inputs.IMAGE_TAG }} - if [ "${{ inputs.TAG_LATEST }}" == "true" ]; then - docker tag ${{ inputs.REGISTRY }}/${{ inputs.REPOSITORY_NAME }}:${{ inputs.IMAGE_TAG }} ${{ inputs.REGISTRY }}/${{ inputs.REPOSITORY_NAME }}:latest - docker push ${{ inputs.REGISTRY }}/${{ inputs.REPOSITORY_NAME }}:latest - fi - fi diff --git a/.github/actions/build-docker-images/action.yml b/.github/actions/build-docker-images/action.yml deleted file mode 100644 index b68efe7cbb..0000000000 --- a/.github/actions/build-docker-images/action.yml +++ /dev/null @@ -1,54 +0,0 @@ -name: 'Build Docker Images' -description: 'Builds Docker images and pushes them to ECR and GHCR' -inputs: - DOCKER_FILENAME: - description: 'Name of the docker file to use for the build' - required: true - REPOSITORY_NAME: - description: 'Name of the Repository' - required: true - IMAGE_TAG: - description: 'Image Tag' - required: true - GHCR_USERNAME: - description: 'Username for GitHub Container Registry' - required: true - GHCR_TOKEN: - description: 'Token for GitHub Container Registry' - required: true - -runs: - using: "composite" - - steps: - - name: Set Environment Variables" - run: | - echo "DOCKER_FILENAME=${{ inputs.DOCKER_FILENAME }}" >> $GITHUB_ENV - echo "REPOSITORY_NAME=${{ inputs.REPOSITORY_NAME }}" >> $GITHUB_ENV - echo "IMAGE_TAG=${{ inputs.IMAGE_TAG }}" >> $GITHUB_ENV - echo "GHCR_USERNAME=${{ inputs.GHCR_USERNAME }}" >> $GITHUB_ENV - echo "GHCR_TOKEN=${{ inputs.GHCR_TOKEN }}" >> $GITHUB_ENV - echo "DOCKER_BUILDKIT=1" >> $GITHUB_ENV - shell: bash - - - name: Log in to the GitHub Container Registry - id: login-ghcr - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ env.GHCR_USERNAME }} - password: ${{ env.GHCR_TOKEN }} - - - name: Login to Amazon ECR - id: login-ecr - uses: aws-actions/amazon-ecr-login@v1 - - - name: Build, tag, and push images - shell: bash - env: - ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }} - GHCR_REGISTRY: ghcr.io/zeta-chain - run: | - docker build -f $DOCKER_FILENAME -t $ECR_REGISTRY/$REPOSITORY_NAME:$IMAGE_TAG -t $GHCR_REGISTRY/$REPOSITORY_NAME:$IMAGE_TAG . - # docker push $ECR_REGISTRY/$REPOSITORY_NAME:$IMAGE_TAG - docker push $GHCR_REGISTRY/$REPOSITORY_NAME:$IMAGE_TAG \ No newline at end of file diff --git a/.github/workflows/docker-build-and-push.yml b/.github/workflows/docker-build-and-push.yml deleted file mode 100644 index c2def3200d..0000000000 --- a/.github/workflows/docker-build-and-push.yml +++ /dev/null @@ -1,86 +0,0 @@ -name: Zetacored-Docker-Build - -on: - release: - types: - - created - workflow_dispatch: - inputs: - version: - description: 'Docker Tag Version For Manual Execution' - required: false - default: '' - -concurrency: - group: Zetacored-Docker-Build - cancel-in-progress: false - -env: - DOCKER_REPO: "zetacored" - DOCKER_ORG: "zetachain" - DOCKER_REGISTRY: "https://index.docker.io/v1/" - -jobs: - docker_build_ubuntu: - runs-on: ubuntu-22.04 - timeout-minutes: 30 - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Set Version from the release title. - if: github.event_name == 'workflow_dispatch' - run: | - echo "GITHUB_TAG_MAJOR_VERSION=${{ github.event.release.name }}" >> $GITHUB_ENV - - - name: Set Version for Hotfix Release from Input. - if: github.event_name == 'workflow_dispatch' - run: | - echo "GITHUB_TAG_MAJOR_VERSION=${{ github.event.inputs.version }}" >> ${GITHUB_ENV} - - - name: "BUILD:PUSH:MONITORING:DOCKER:IMAGE" - uses: ./.github/actions/build-docker-images-generic - with: - DOCKER_FILENAME: "Dockerfile" - REPOSITORY_NAME: "${{ env.DOCKER_REPO }}" - IMAGE_TAG: "ubuntu-${{ env.GITHUB_TAG_MAJOR_VERSION }}" - REGISTRY: "${{ env.DOCKER_REGISTRY }}" - DOCKER_ORG: "${{ env.DOCKER_ORG }}" - USERNAME: "${{ secrets.DOCKER_HUB_USERNAME }}" - TOKEN: "${{ secrets.DOCKERHUB_TOKEN }}" - DOCKER_FILE_DIRECTORY: "./" - DOCKER_BUILD_KIT: "0" - TAG_LATEST: "true" - - docker_build_arm: - runs-on: buildjet-4vcpu-ubuntu-2204-arm - timeout-minutes: 30 - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Set Version from the release title. - if: github.event_name == 'workflow_dispatch' - run: | - echo "GITHUB_TAG_MAJOR_VERSION=${{ github.event.release.name }}" >> $GITHUB_ENV - - - name: Set Version for Hotfix Release from Input. - if: github.event_name == 'workflow_dispatch' - run: | - echo "GITHUB_TAG_MAJOR_VERSION=${{ github.event.inputs.version }}" >> ${GITHUB_ENV} - - - name: "BUILD:PUSH:MONITORING:DOCKER:IMAGE" - uses: ./.github/actions/build-docker-images-generic - with: - DOCKER_FILENAME: "Dockerfile" - REPOSITORY_NAME: "${{ env.DOCKER_REPO }}" - IMAGE_TAG: "arm-${{ env.GITHUB_TAG_MAJOR_VERSION }}" - REGISTRY: "${{ env.DOCKER_REGISTRY }}" - DOCKER_ORG: "${{ env.DOCKER_ORG }}" - USERNAME: "${{ secrets.DOCKER_HUB_USERNAME }}" - TOKEN: "${{ secrets.DOCKERHUB_TOKEN }}" - DOCKER_FILE_DIRECTORY: "./" - DOCKER_BUILD_KIT: "0" - TAG_LATEST: "false" \ No newline at end of file diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 0f9804d087..0000000000 --- a/Dockerfile +++ /dev/null @@ -1,66 +0,0 @@ -# Build Stage -FROM golang:1.22-alpine3.18 AS builder - -ENV GOPATH /go -ENV GOOS=linux -ENV CGO_ENABLED=1 - -# Install build dependencies -RUN apk --no-cache add git make build-base jq openssh libusb-dev linux-headers bash curl python3 py3-pip - -# Set the working directory -WORKDIR /go/delivery/zeta-node - -# Copy module files and download dependencies -COPY go.mod . -COPY go.sum . - -RUN go mod download - -# Copy the rest of the source code and build the application -COPY . . - -RUN expected_major_version=$(grep 'const releaseVersion = ' app/setup_handlers.go | awk -F'"' '{print $2}') && \ - make install VERSION="${expected_major_version}" && \ - git_hash=$(git rev-parse --short HEAD) && \ - echo -n "${expected_major_version}-${git_hash}" > /go/delivery/zeta-node/expected_major_version - -# Run Stage -FROM alpine:3.18 - -ENV COSMOVISOR_CHECKSUM="626dfc58c266b85f84a7ed8e2fe0e2346c15be98cfb9f9b88576ba899ed78cdc" -ENV COSMOVISOR_VERSION="v1.5.0" -# Copy Start Script Helpers -COPY contrib/docker-scripts/* /scripts/ - -# Install runtime dependencies -RUN apk --no-cache add git jq bash curl nano vim tmux python3 libusb-dev linux-headers make build-base bind-tools psmisc coreutils wget py3-pip qemu-img qemu-system-x86_64 && \ - pip install requests && \ - chmod a+x -R /scripts && \ - wget https://github.com/sgerrand/alpine-pkg-glibc/releases/download/2.31-r0/glibc-2.31-r0.apk && \ - apk add --force-overwrite --allow-untrusted glibc-2.31-r0.apk && \ - curl https://dl.google.com/dl/cloudsdk/release/google-cloud-sdk.tar.gz > /tmp/google-cloud-sdk.tar.gz && \ - mkdir -p /usr/local/gcloud && \ - tar -C /usr/local/gcloud -xvf /tmp/google-cloud-sdk.tar.gz && \ - /usr/local/gcloud/google-cloud-sdk/install.sh --quiet && \ - ln -s /usr/local/gcloud/google-cloud-sdk/bin/gcloud /usr/bin/gcloud && \ - python /scripts/install_cosmovisor.py - -# Copy the binaries from the build stage -COPY --from=builder /go/bin/zetaclientd /usr/local/bin/zetaclientd -COPY --from=builder /go/bin/zetacored /usr/local/bin/zetacored -COPY --from=builder /go/delivery/zeta-node/expected_major_version /scripts/expected_major_version - -# Set the working directory -WORKDIR /usr/local/bin - -# Set the default shell -ENV SHELL /bin/bash - -EXPOSE 26656 -EXPOSE 1317 -EXPOSE 8545 -EXPOSE 8546 -EXPOSE 9090 -EXPOSE 26657 -EXPOSE 9091 \ No newline at end of file diff --git a/Makefile b/Makefile index 1ecd3bc599..344ae150e4 100644 --- a/Makefile +++ b/Makefile @@ -482,49 +482,6 @@ stop-eth-node-mainnet: clean-eth-node-mainnet: cd contrib/rpc/ethereum && DOCKER_TAG=$(DOCKER_TAG) docker-compose down -v -#ZETA - -#FULL-NODE-RPC-FROM-BUILT-IMAGE -start-zetacored-rpc-mainnet: - cd contrib/rpc/zetacored && bash init_docker_compose.sh mainnet image $(DOCKER_TAG) - -stop-zetacored-rpc-mainnet: - cd contrib/rpc/zetacored && bash kill_docker_compose.sh mainnet false - -clean-zetacored-rpc-mainnet: - cd contrib/rpc/zetacored && bash kill_docker_compose.sh mainnet true - -#FULL-NODE-RPC-FROM-BUILT-IMAGE -start-zetacored-rpc-testnet: - cd contrib/rpc/zetacored && bash init_docker_compose.sh athens3 image $(DOCKER_TAG) - -stop-zetacored-rpc-testnet: - cd contrib/rpc/zetacored && bash kill_docker_compose.sh athens3 false - -clean-zetacored-rpc-testnet: - cd contrib/rpc/zetacored && bash kill_docker_compose.sh athens3 true - -#FULL-NODE-RPC-FROM-LOCAL-BUILD -start-zetacored-rpc-mainnet-localbuild: - cd contrib/rpc/zetacored && bash init_docker_compose.sh mainnet localbuild $(DOCKER_TAG) - -stop-zetacored-rpc-mainnet-localbuild: - cd contrib/rpc/zetacored && bash kill_docker_compose.sh mainnet false - -clean-zetacored-rpc-mainnet-localbuild: - cd contrib/rpc/zetacored && bash kill_docker_compose.sh mainnet true - -#FULL-NODE-RPC-FROM-LOCAL-BUILD -start-zetacored-rpc-testnet-localbuild: - cd contrib/rpc/zetacored && bash init_docker_compose.sh athens3 localbuild $(DOCKER_TAG) - -stop-zetacored-rpc-testnet-localbuild: - cd contrib/rpc/zetacored && bash kill_docker_compose.sh athens3 false - -clean-zetacored-rpc-testnet-localbuild: - cd contrib/rpc/zetacored && bash kill_docker_compose.sh athens3 true - - ############################################################################### ### Debug Tools ### ############################################################################### diff --git a/contrib/docker-scripts/download_binaries.py b/contrib/docker-scripts/download_binaries.py deleted file mode 100644 index 99063a40f0..0000000000 --- a/contrib/docker-scripts/download_binaries.py +++ /dev/null @@ -1,58 +0,0 @@ -import requests -import os -import json -import logging -import sys - -# Logger class for easier logging setup -class Logger: - def __init__(self): - self.log = logging.getLogger() - self.log.setLevel(logging.INFO) - self.handler = logging.StreamHandler(sys.stdout) - self.handler.setLevel(logging.DEBUG) - self.formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') - self.handler.setFormatter(self.formatter) - self.log.addHandler(self.handler) - - -# Initialize logger instance -logger = Logger() - -# Parse JSON from an environment variable to get binary download information -info = json.loads(os.environ["DOWNLOAD_BINARIES"]) - -try: - # Iterate over binaries to download - for binary in info["binaries"]: - download_link = binary["download_url"] - binary_location = f'{os.environ["DAEMON_HOME"]}/{binary["binary_location"]}' - binary_directory = os.path.dirname(binary_location) - # Log download link - logger.log.info(f"DOWNLOAD LINK: {download_link}") - split_download_link = download_link.split("/") - # Log split download link parts - logger.log.info(f"SPLIT DOWNLOAD LINK: {split_download_link}") - # Extract binary name and version from the download link - binary_name = download_link.split("/")[8] - # Check if binary already exists - logger.log.info(f"CHECKING / DOWNLOADING {binary_location}") - - if os.path.exists(binary_location): - # If binary exists, log and do nothing - logger.log.info(f"BINARY EXISTS ALREADY: {binary_location}") - else: - # If binary doesn't exist, download and save it - logger.log.info("BINARY DOES NOT EXIST.") - os.makedirs(binary_directory, exist_ok=True) - response = requests.get(download_link) - if response.status_code == 200: - with open(binary_location, "wb") as f: - f.write(response.content) - os.chmod(binary_location, 0o755) - logger.log.info("BINARY DOWNLOADED SUCCESSFULLY.") - else: - logger.log.info("FAILED TO DOWNLOAD BINARY. Status code:", response.status_code) - logger.log.info("BINARIES DOWNLOAD FINISHED...") -except Exception as e: - logger.log.error(str(e)) diff --git a/contrib/docker-scripts/install_cosmovisor.py b/contrib/docker-scripts/install_cosmovisor.py deleted file mode 100644 index 568c9bbe8e..0000000000 --- a/contrib/docker-scripts/install_cosmovisor.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python3 -import hashlib -import logging -import os -import requests -import sys - -# Constants defining the binary name, version, expected checksum, download URL, and installation path -BINARY_NAME = "cosmovisor" -BINARY_VERSION = os.getenv("COSMOVISOR_VERSION") # Get the cosmovisor version from environment variable -EXPECTED_CHECKSUM = os.getenv("COSMOVISOR_CHECKSUM") # Get the expected checksum from environment variable -BINARY_URL = f"https://binary-pickup.zetachain.com/cosmovisor-{BINARY_VERSION}-linux-amd64" # Construct the binary download URL -INSTALL_PATH = f"/usr/local/bin/{BINARY_NAME}" # Define the installation path for the binary - -# Check if necessary environment variables are set; exit if not -if not BINARY_VERSION or not EXPECTED_CHECKSUM: - logging.error("Environment variables COSMOVISOR_VERSION and COSMOVISOR_CHECKSUM must be set.") - sys.exit(1) - -# Configure logging to both stdout and a file -logging.basicConfig( - level=logging.INFO, # Set logging level to INFO - format="%(levelname)s: %(message)s", # Define log message format - handlers=[ - logging.StreamHandler(sys.stdout), # Log to stdout - logging.FileHandler("/var/log/update_cosmovisor.log") # Log to a file - ] -) - - -# Function to calculate the SHA-256 checksum of the downloaded binary -def calculate_checksum(file_path): - sha256 = hashlib.sha256() # Create a new SHA-256 hash object - with open(file_path, "rb") as f: # Open the binary file in binary read mode - for byte_block in iter(lambda: f.read(4096), - b""): # Read the file in chunks to avoid loading it all into memory - sha256.update(byte_block) # Update the hash object with the chunk - return sha256.hexdigest() # Return the hexadecimal digest of the hash object - - -# Function to download the binary and update it if the checksum matches -def download_and_update_binary(): - try: - response = requests.get(BINARY_URL) # Attempt to download the binary - response.raise_for_status() # Check if the download was successful, raises exception on failure - logging.info("Binary downloaded successfully.") - except requests.exceptions.RequestException as e: - logging.error(f"Failed to download the binary: {e}") # Log any error during download - sys.exit(1) # Exit the script on download failure - - with open(INSTALL_PATH, "wb") as f: # Open the installation path file in binary write mode - f.write(response.content) # Write the downloaded binary content to the file - - actual_checksum = calculate_checksum(INSTALL_PATH) # Calculate the checksum of the downloaded binary - if actual_checksum == EXPECTED_CHECKSUM: # Compare the actual checksum with the expected checksum - logging.info("Cosmovisor binary checksum verified.") # Log success if checksums match - os.chmod(INSTALL_PATH, 0o755) # Make the binary executable - logging.info("Cosmovisor binary updated successfully.") - else: - logging.error( - "Checksums do not match. Possible corrupted download. Deleting the downloaded binary.") # Log failure if checksums do not match - os.remove(INSTALL_PATH) # Remove the potentially corrupted binary - sys.exit(1) # Exit the script due to checksum mismatch - - -# Main script execution starts here -logging.info( - f"Downloading the {BINARY_NAME} binary (version {BINARY_VERSION})...") # Log the start of the download process -download_and_update_binary() # Call the function to download and update the binary diff --git a/contrib/docker-scripts/start.sh b/contrib/docker-scripts/start.sh deleted file mode 100644 index bb151a49fe..0000000000 --- a/contrib/docker-scripts/start.sh +++ /dev/null @@ -1,335 +0,0 @@ -#!/bin/bash - -logt() { - echo "$(date '+%Y-%m-%d %H:%M:%S') $1" -} - - -function load_defaults { - #DEFAULT: Mainnet Statesync. - export DAEMON_HOME=${DAEMON_HOME:=/root/.zetacored} - export NETWORK=${NETWORK:=mainnet} - export RESTORE_TYPE=${RESTORE_TYPE:=statesync} - export SNAPSHOT_API=${SNAPSHOT_API:=https://snapshots.rpc.zetachain.com} - export TRUST_HEIGHT_DIFFERENCE_STATE_SYNC=${TRUST_HEIGHT_DIFFERENCE_STATE_SYNC:=40000} - export COSMOVISOR_VERSION=${COSMOVISOR_VERSION:=v1.5.0} - export CHAIN_ID=${CHAIN_ID:=zetachain_7000-1} - export COSMOVISOR_CHECKSUM=${COSMOVISOR_CHECKSUM:=626dfc58c266b85f84a7ed8e2fe0e2346c15be98cfb9f9b88576ba899ed78cdc} - export VISOR_NAME=${VISOR_NAME:=cosmovisor} - export DAEMON_NAME=${DAEMON_NAME:=zetacored} - export DAEMON_ALLOW_DOWNLOAD_BINARIES=${DAEMON_ALLOW_DOWNLOAD_BINARIES:=false} - export DAEMON_RESTART_AFTER_UPGRADE=${DAEMON_RESTART_AFTER_UPGRADE:=true} - export UNSAFE_SKIP_BACKUP=${UNSAFE_SKIP_BACKUP:=true} - export CLIENT_DAEMON_NAME=${CLIENT_DAEMON_NAME:=zetaclientd} - export CLIENT_DAEMON_ARGS=${CLIENT_DAEMON_ARGS:""} - export CLIENT_SKIP_UPGRADE=${CLIENT_SKIP_UPGRADE:=true} - export CLIENT_START_PROCESS=${CLIENT_START_PROCESS:=false} - export MONIKER=${MONIKER:=local-test} - export RE_DO_START_SEQUENCE=${RE_DO_START_SEQUENCE:=false} - - #ATHENS3 - export BINARY_LIST_ATHENS3=${BINARY_LIST_ATHENS3:=https://raw.githubusercontent.com/zeta-chain/network-config/main/athens3/binary_list.json} - export STATE_SYNC_RPC_NODE_FILE_ATHENS3=${STATE_SYNC_RPC_NODE_FILE_ATHENS3:=https://raw.githubusercontent.com/zeta-chain/network-config/main/athens3/state_sync_node} - export RPC_STATE_SYNC_RPC_LIST_FILE_ATHENS3=${RPC_STATE_SYNC_RPC_LIST_FILE_ATHENS3:=https://raw.githubusercontent.com/zeta-chain/network-config/main/athens3/rpc_state_sync_nodes} - export APP_TOML_FILE_ATHENS3=${APP_TOML_FILE_ATHENS3:=https://raw.githubusercontent.com/zeta-chain/network-config/main/athens3/app.toml} - export CONFIG_TOML_FILE_ATHENS3=${CONFIG_TOML_FILE_ATHENS3:=https://raw.githubusercontent.com/zeta-chain/network-config/main/athens3/config.toml} - export CLIENT_TOML_FILE_ATHENS3=${CLIENT_TOML_FILE_ATHENS3:=https://raw.githubusercontent.com/zeta-chain/network-config/main/athens3/client.toml} - export GENESIS_FILE_ATHENS3=${GENESIS_FILE_ATHENS3:=https://raw.githubusercontent.com/zeta-chain/network-config/main/athens3/genesis.json} - - #MAINNET - export BINARY_LIST_MAINNET=${BINARY_LIST_MAINNET:=https://raw.githubusercontent.com/zeta-chain/network-config/main/mainnet/binary_list.json} - export STATE_SYNC_RPC_NODE_FILE_MAINNET=${STATE_SYNC_RPC_NODE_FILE_MAINNET:=https://raw.githubusercontent.com/zeta-chain/network-config/main/mainnet/state_sync_node} - export RPC_STATE_SYNC_RPC_LIST_FILE_MAINNET=${RPC_STATE_SYNC_RPC_LIST_FILE_MAINNET:=https://raw.githubusercontent.com/zeta-chain/network-config/main/mainnet/rpc_state_sync_nodes} - export APP_TOML_FILE_MAINNET=${APP_TOML_FILE_MAINNET:=https://raw.githubusercontent.com/zeta-chain/network-config/main/mainnet/app.toml} - export CONFIG_TOML_FILE_MAINNET=${CONFIG_TOML_FILE_MAINNET:=https://raw.githubusercontent.com/zeta-chain/network-config/main/mainnet/config.toml} - export CLIENT_TOML_FILE_MAINNET=${CLIENT_TOML_FILE_MAINNET:=https://raw.githubusercontent.com/zeta-chain/network-config/main/mainnet/client.toml} - export GENESIS_FILE_MAINNET=${GENESIS_FILE_MAINNET:=https://raw.githubusercontent.com/zeta-chain/network-config/main/mainnet/genesis.json} - -} - -function init_chain { - if [ -d "${DAEMON_HOME}/config" ]; then - logt "${DAEMON_NAME} home directory already initialized." - else - logt "${DAEMON_NAME} home directory not initialized." - logt "MONIKER: ${MONIKER}" - logt "DAEMON_HOME: ${DAEMON_HOME}" - ${DAEMON_NAME} init ${MONIKER} --home ${DAEMON_HOME} --chain-id ${CHAIN_ID} - fi -} - -function download_configs { - if [ "${NETWORK}" == "mainnet" ]; then - wget -q ${APP_TOML_FILE_MAINNET} -O ${DAEMON_HOME}/config/app.toml - wget -q ${CONFIG_TOML_FILE_MAINNET} -O ${DAEMON_HOME}/config/config.toml - wget -q ${CLIENT_TOML_FILE_MAINNET} -O ${DAEMON_HOME}/config/client.toml - wget -q ${GENESIS_FILE_MAINNET} -O ${DAEMON_HOME}/config/genesis.json - wget -q ${BINARY_LIST_MAINNET} - export DOWNLOAD_BINARIES=$(cat binary_list.json | tr -d '\n') - rm -rf binary_list.json - logt "BINARY_LIST: ${DOWNLOAD_BINARIES}" - elif [ "${NETWORK}" == "athens3" ]; then - wget -q ${APP_TOML_FILE_ATHENS3} -O ${DAEMON_HOME}/config/app.toml - wget -q ${CONFIG_TOML_FILE_ATHENS3} -O ${DAEMON_HOME}/config/config.toml - wget -q ${CLIENT_TOML_FILE_ATHENS3} -O ${DAEMON_HOME}/config/client.toml - wget -q ${GENESIS_FILE_ATHENS3} -O ${DAEMON_HOME}/config/genesis.json - wget -q ${BINARY_LIST_ATHENS3} - export DOWNLOAD_BINARIES=$(cat binary_list.json | tr -d '\n') - rm -rf binary_list.json - logt "BINARY_LIST: ${DOWNLOAD_BINARIES}" - else - logt "Initialize for Localnet." - fi -} - -function setup_restore_type { - if [ "${RESTORE_TYPE}" == "statesync" ]; then - logt "Statesync restore. Download state sync rpc address from network-config" - if [ "${NETWORK}" == "mainnet" ]; then - logt "MAINNET STATE SYNC" - logt "STATE_SYNC_RPC_NODE_FILE_MAINNET: ${STATE_SYNC_RPC_NODE_FILE_MAINNET}" - logt "RPC_STATE_SYNC_RPC_LIST_FILE_MAINNET: ${RPC_STATE_SYNC_RPC_LIST_FILE_MAINNET}" - wget -q ${STATE_SYNC_RPC_NODE_FILE_MAINNET} - wget -q ${RPC_STATE_SYNC_RPC_LIST_FILE_MAINNET} - export STATE_SYNC_SERVER=$(cat state_sync_node) - export RPC_STATE_SYNC_SERVERS=$(cat rpc_state_sync_nodes) - rm -rf state_sync_node - rm -rf rpc_state_sync_nodes - elif [ "${NETWORK}" == "athens3" ]; then - logt "ATHENS STATE SYNC" - logt "STATE_SYNC_RPC_NODE_FILE_MAINNET: ${STATE_SYNC_RPC_NODE_FILE_ATHENS3}" - logt "RPC_STATE_SYNC_RPC_LIST_FILE_MAINNET: ${RPC_STATE_SYNC_RPC_LIST_FILE_ATHENS3}" - wget -q ${STATE_SYNC_RPC_NODE_FILE_ATHENS3} - wget -q ${RPC_STATE_SYNC_RPC_LIST_FILE_ATHENS3} - export STATE_SYNC_SERVER=$(cat state_sync_node) - export RPC_STATE_SYNC_SERVERS=$(cat rpc_state_sync_nodes) - rm -rf state_sync_node - rm -rf rpc_state_sync_nodes - fi - elif [ "${RESTORE_TYPE}" == "snapshot" ]; then - if [ "${NETWORK}" == "mainnet" ]; then - logt "Get Latest Snapshot URL" - SNAPSHOT_URL=$(curl -s ${SNAPSHOT_API}/mainnet/fullnode/latest.json | jq -r '.snapshots[0].link') - SNAPSHOT_FILENAME=$(curl -s ${SNAPSHOT_API}/mainnet/fullnode/latest.json | jq -r '.snapshots[0].filename') - SNAPSHOT_DIR=$(pwd) - logt "Download Snapshot from url: ${SNAPSHOT_URL}" - curl -o "${SNAPSHOT_FILENAME}" "${SNAPSHOT_URL}" - logt "Change to: ${DAEMON_HOME} and extract snapshot." - cd ${DAEMON_HOME} - tar xvf ${SNAPSHOT_DIR}/${SNAPSHOT_FILENAME} - logt " Cleanup Snapshot" - rm -rf ${SNAPSHOT_DIR}/${SNAPSHOT_FILENAME} - elif [ "${NETWORK}" == "athens3" ]; then - SNAPSHOT_URL=$(curl -s ${SNAPSHOT_API}/testnet/fullnode/latest.json | jq -r '.snapshots[0].link') - SNAPSHOT_FILENAME=$(curl -s ${SNAPSHOT_API}/testnet/fullnode/latest.json | jq -r '.snapshots[0].filename') - SNAPSHOT_DIR=$(pwd) - logt "Download Snapshot from url: ${SNAPSHOT_URL}" - curl -o "${SNAPSHOT_FILENAME}" "${SNAPSHOT_URL}" - logt "Change to: ${DAEMON_HOME} and extract snapshot." - cd ${DAEMON_HOME} - tar xvf ${SNAPSHOT_DIR}/${SNAPSHOT_FILENAME} - logt " Cleanup Snapshot" - rm -rf ${SNAPSHOT_DIR}/${SNAPSHOT_FILENAME} - fi - elif [ "${RESTORE_TYPE}" == "snapshot-archive" ]; then - if [ "${NETWORK}" == "mainnet" ]; then - logt "Get Latest Snapshot URL" - SNAPSHOT_URL=$(curl -s ${SNAPSHOT_API}/mainnet/archive/latest.json | jq -r '.snapshots[0].link') - SNAPSHOT_FILENAME=$(curl -s ${SNAPSHOT_API}/mainnet/archive/latest.json | jq -r '.snapshots[0].filename') - SNAPSHOT_DIR=$(pwd) - logt "Download Snapshot from url: ${SNAPSHOT_URL}" - curl -o "${SNAPSHOT_FILENAME}" "${SNAPSHOT_URL}" - logt "Change to: ${DAEMON_HOME} and extract snapshot." - cd ${DAEMON_HOME} - tar xvf ${SNAPSHOT_DIR}/${SNAPSHOT_FILENAME} - logt " Cleanup Snapshot" - rm -rf ${SNAPSHOT_DIR}/${SNAPSHOT_FILENAME} - elif [ "${NETWORK}" == "athens3" ]; then - SNAPSHOT_URL=$(curl -s ${SNAPSHOT_API}/testnet/archive/latest.json | jq -r '.snapshots[0].link') - SNAPSHOT_FILENAME=$(curl -s ${SNAPSHOT_API}/testnet/archive/latest.json | jq -r '.snapshots[0].filename') - SNAPSHOT_DIR=$(pwd) - logt "Download Snapshot from url: ${SNAPSHOT_URL}" - curl -o "${SNAPSHOT_FILENAME}" "${SNAPSHOT_URL}" - logt "Change to: ${DAEMON_HOME} and extract snapshot." - cd ${DAEMON_HOME} - tar xvf ${SNAPSHOT_DIR}/${SNAPSHOT_FILENAME} - logt " Cleanup Snapshot" - rm -rf ${SNAPSHOT_DIR}/${SNAPSHOT_FILENAME} - fi - else - logt "Initialize for Localnet." - fi -} - -function change_config_values { - if [ "${RESTORE_TYPE}" == "statesync" ]; then - export STATE_SYNC_SERVER="${STATE_SYNC_SERVER}" - export TRUST_HEIGHT=$(curl -s ${STATE_SYNC_SERVER}/block | jq -r '.result.block.header.height') - export HEIGHT=$((TRUST_HEIGHT-${TRUST_HEIGHT_DIFFERENCE_STATE_SYNC})) - export TRUST_HASH=$(curl -s "${STATE_SYNC_SERVER}/block?height=${HEIGHT}" | jq -r '.result.block_id.hash') - export RPC_STATE_SYNC_SERVERS="${RPC_STATE_SYNC_SERVERS}" - export EXTERNAL_IP=$(curl -4 icanhazip.com) - - logt "******* DEBUG STATE SYNC VALUES *******" - logt "STATE_SYNC_SERVER: ${STATE_SYNC_SERVER}" - logt "RPC_STATE_SYNC_SERVERS: ${RPC_STATE_SYNC_SERVERS}" - logt "TRUST_HEIGHT: ${TRUST_HEIGHT}" - logt "TRUST_HASH: ${TRUST_HASH}" - logt "HEIGHT: ${HEIGHT}" - logt "EXTERNAL_IP: ${EXTERNAL_IP}" - - logt "SED Change Config Files." - sed -i -e "s/^enable = .*/enable = \"true\"/" ${DAEMON_HOME}/config/config.toml - sed -i -e "s/^rpc_servers = .*/rpc_servers = \"${RPC_STATE_SYNC_SERVERS}\"/" ${DAEMON_HOME}/config/config.toml - sed -i -e "s/^trust_height = .*/trust_height = \"${HEIGHT}\"/" ${DAEMON_HOME}/config/config.toml - sed -i -e "s/^trust_hash = .*/trust_hash = \"${TRUST_HASH}\"/" ${DAEMON_HOME}/config/config.toml - sed -i -e "s/^moniker = .*/moniker = \"${MONIKER}\"/" ${DAEMON_HOME}/config/config.toml - sed -i -e "s/^external_address = .*/external_address = \"${EXTERNAL_IP}:26656\"/" ${DAEMON_HOME}/config/config.toml - else - export EXTERNAL_IP=$(curl -4 icanhazip.com) - logt "******* DEBUG STATE SYNC VALUES *******" - logt "EXTERNAL_IP: ${EXTERNAL_IP}" - logt "SED Change Config Files." - sed -i -e "s/^enable = .*/enable = \"true\"/" ${DAEMON_HOME}/config/config.toml - sed '/^\[statesync\]/,/^\[/ s/enable = "true"/enable = "false"/' ${DAEMON_HOME}/config/config.toml - sed -i -e "s/^moniker = .*/moniker = \"${MONIKER}\"/" ${DAEMON_HOME}/config/config.toml - sed -i -e "s/^external_address = .*/external_address = \"${EXTERNAL_IP}:26656\"/" ${DAEMON_HOME}/config/config.toml - fi -} - -function setup_basic_keyring { - if ${DAEMON_NAME} keys show "$MONIKER" --keyring-backend test > /dev/null 2>&1; then - echo "Key $MONIKER already exists." - else - ${DAEMON_NAME} keys add "$MONIKER" --keyring-backend test - echo "Key $MONIKER created." - fi -} - -function download_binary_version { - if [ "${NETWORK}" == "mainnet" ]; then - wget -q ${BINARY_LIST_MAINNET} - export DOWNLOAD_BINARIES=$(cat binary_list.json | tr -d '\n') - rm -rf binary_list.json - logt "BINARY_LIST: ${DOWNLOAD_BINARIES}" - elif [ "${NETWORK}" == "athens3" ]; then - wget -q ${BINARY_LIST_ATHENS3} - export DOWNLOAD_BINARIES=$(cat binary_list.json | tr -d '\n') - rm -rf binary_list.json - logt "BINARY_LIST: ${DOWNLOAD_BINARIES}" - fi - python3 /scripts/download_binaries.py -} - -function move_zetacored_binaries { - mkdir -p ${DAEMON_HOME}/cosmovisor || logt "Directory already exists ${DAEMON_HOME}/cosmovisor" - mkdir -p ${DAEMON_HOME}/cosmovisor/genesis || logt "Directory already exists ${DAEMON_HOME}/cosmovisor/genesis" - mkdir -p ${DAEMON_HOME}/cosmovisor/genesis/bin || logt "Directory already exists ${DAEMON_HOME}/cosmovisor/genesis/bin" - cp /usr/local/bin/zetacored ${DAEMON_HOME}/cosmovisor/genesis/bin/zetacored - - if [ "${RESTORE_TYPE}" == "statesync" ]; then - logt "Its statesync so cosmosvisor won't know which binary to start from so make sure it starts from the latest version reported in ABCI_INFO from statesync server rpc." - export VERSION_CHECK=$(curl -s ${STATE_SYNC_SERVER}/abci_info | jq -r '.result.response.version') - logt "CURRENT VERSION_CHECK: ${VERSION_CHECK}" - cp ${DAEMON_HOME}/cosmovisor/upgrades/v${VERSION_CHECK}/bin/zetacored ${DAEMON_HOME}/cosmovisor/genesis/bin/zetacored - fi -} - -function start_network { - if [ "${IS_LOCAL_DEVELOPMENT}" == "true" ]; then - cp /usr/local/bin/zetacored ${DAEMON_HOME}/cosmovisor/genesis/bin/zetacored - find /root/.zetacored/cosmovisor/upgrades/ -type f -path "*/bin/zetacored" -exec cp /usr/local/bin/zetacored {} \; - fi - expected_major_version=$(cat /scripts/expected_major_version | cut -d '-' -f 1) - VISOR_VERSION=v$(${VISOR_NAME} version | tail -n 1 | tr -d '(devel)' | tr -d '\n') - DAEMON_VERSION=$(${DAEMON_NAME} version) - VISOR_MAJOR_VERSION=$(echo $VISOR_VERSION | grep -o '^v[0-9]*') - DAEMON_MAJOR_VERSION=$(echo $DAEMON_VERSION | grep -o '^v[0-9]*') - - logt "EXPECTED_VERSION_WITH_HASH: $(cat /scripts/expected_major_version | cut -d '-' -f 1)" - logt "EXPECTED_MAJOR_VERSION: ${expected_major_version}" - logt "VISOR_VERSION: ${VISOR_VERSION}" - logt "DAEMON_VERSION: ${DAEMON_VERSION}" - logt "VISOR_MAJOR_VERSION: ${VISOR_MAJOR_VERSION}" - logt "DAEMON_MAJOR_VERSION: ${DAEMON_MAJOR_VERSION}" - - if [ "$VISOR_MAJOR_VERSION" != "$expected_major_version" ] || [ "$DAEMON_MAJOR_VERSION" != "$expected_major_version" ]; then - logt "One or both versions don't match the expected major release version: $expected_major_version" - else - logt "Both versions match the expected major release version: $expected_major_version" - fi - - if [ "$VISOR_VERSION" != "$DAEMON_VERSION" ]; then - logt "cosmovisor version doesn't appear to match your daemon version. Start ${DAEMON_NAME}" - else - logt "cosmovisor version match your daemon version. Start ${VISOR_NAME}" - fi - - ${VISOR_NAME} run start --home ${DAEMON_HOME} \ - --log_level info \ - --moniker ${MONIKER} \ - --rpc.laddr tcp://0.0.0.0:26657 \ - --minimum-gas-prices 1.0azeta "--grpc.enable=true" -} - -logt "Load Default Values for ENV Vars if not set." -load_defaults - -if [[ -f "${DAEMON_HOME}/start_sequence_status" ]] && grep -q "START_SEQUENCE_COMPLETE" "${DAEMON_HOME}/start_sequence_status" && [[ "$RE_DO_START_SEQUENCE" != "true" ]]; then - logt "The start sequence is complete and no redo is required." - - logt "Download Configs" - download_configs - - logt "Download Historical Binaries" - download_binary_version - - if [ "${RESTORE_TYPE}" == "statesync" ]; then - logt "Setup Restore Type: ${RESTORE_TYPE}" - logt "During restarts, we re-do this to ensure to update the configs with valid values. When you call change config the stuff that gets set in this function for statesync needs to be set. Doesn't effect to re-set this." - setup_restore_type - fi - - logt "Modify Chain Configs" - change_config_values - - logt "Move Zetacored Binaries." - move_zetacored_binaries - - logt "Start sequence has completed, echo into file so on restart it doesn't download snapshots again." - echo "START_SEQUENCE_COMPLETE" >> ${DAEMON_HOME}/start_sequence_status - - logt "Start Network" - start_network -else - logt "START_SEQUENCE_COMPLETE is not true, or RE_DO_START_SEQUENCE is set to true." - - if [[ "$RE_DO_START_SEQUENCE" == "true" ]]; then - logt "Clean any files that may exist in: ${DAEMON_HOME}" - rm -rf ${DAEMON_HOME}/* || logt "directory doesn't exist." - fi - - logt "Init Chain" - init_chain - - logt "Download Configs" - download_configs - - logt "Download Historical Binaries" - download_binary_version - - logt "Setup Restore Type: ${RESTORE_TYPE}" - setup_restore_type - - logt "Modify Chain Configs" - change_config_values - - logt "Move root binaries to current" - move_zetacored_binaries - - logt "Start sequence has completed, echo into file so on restart it doesn't download snapshots again." - echo "START_SEQUENCE_COMPLETE" >> ${DAEMON_HOME}/start_sequence_status - - logt "Start Network" - start_network -fi \ No newline at end of file diff --git a/contrib/rpc/zetacored/docker-compose.yml b/contrib/rpc/zetacored/docker-compose.yml deleted file mode 100644 index 50dbd0a731..0000000000 --- a/contrib/rpc/zetacored/docker-compose.yml +++ /dev/null @@ -1,36 +0,0 @@ -version: '3.8' -services: - -=name=-: - platform: linux/amd64 - -=image_block=- - container_name: "zetachain_${NETWORK:-mainnet}_rpc" - environment: - DAEMON_HOME: "${DAEMON_HOME:-/root/.zetacored}" - NETWORK: ${NETWORK:-mainnet} - RESTORE_TYPE: "${RESTORE_TYPE:-snapshot}" - SNAPSHOT_API: ${SNAPSHOT_API:-https://snapshots.rpc.zetachain.com} - TRUST_HEIGHT_DIFFERENCE_STATE_SYNC: ${TRUST_HEIGHT_DIFFERENCE_STATE_SYNC:-40000} - CHAIN_ID: "${CHAIN_ID:-zetachain_7000-1}" - VISOR_NAME: "${VISOR_NAME:-cosmovisor}" - DAEMON_NAME: "${DAEMON_NAME:-zetacored}" - DAEMON_ALLOW_DOWNLOAD_BINARIES: "${DAEMON_ALLOW_DOWNLOAD_BINARIES:-false}" - DAEMON_RESTART_AFTER_UPGRADE: "${DAEMON_RESTART_AFTER_UPGRADE:-true}" - UNSAFE_SKIP_BACKUP: "${UNSAFE_SKIP_BACKUP:-true}" - MONIKER: ${MONIKER:-mainnet-docker-rpc} - #If this is true it will erase everything and start over from scratch. - RE_DO_START_SEQUENCE: "${RE_DO_START_SEQUENCE:-false}" - #If this is true it will build the dockerfile and use binary from built docker file instead of remote docker image for local development testing on non-governance upgrades. - IS_LOCAL_DEVELOPMENT: "${IS_LOCAL_DEVELOPMENT:-false}" - ports: - - "26656:26656" - - "1317:1317" - - "8545:8545" - - "8546:8546" - - "26657:26657" - - "9090:9090" - - "9091:9091" - volumes: - - -=name=-:/root/.zetacored/ - entrypoint: bash /scripts/start.sh -volumes: - -=name=-: diff --git a/contrib/rpc/zetacored/init_docker_compose.sh b/contrib/rpc/zetacored/init_docker_compose.sh deleted file mode 100644 index 04e9f6857c..0000000000 --- a/contrib/rpc/zetacored/init_docker_compose.sh +++ /dev/null @@ -1,65 +0,0 @@ -#!/bin/bash - -NETWORK=${1} -TYPE=${2} -DOCKER_TAG=${3} - -if [ "$TYPE" == "image" ]; then - echo "Source Environment File." - SOURCE_FILE_NAME="networks/.${NETWORK}" - if [ ! -f "$SOURCE_FILE_NAME" ]; then - echo "Environment file $SOURCE_FILE_NAME does not exist." - exit 1 - fi - source ${SOURCE_FILE_NAME} -elif [ "$TYPE" == "localbuild" ]; then - echo "Source Environment File." - SOURCE_FILE_NAME="networks/.${NETWORK}-localbuild" - if [ ! -f "$SOURCE_FILE_NAME" ]; then - echo "Environment file $SOURCE_FILE_NAME does not exist." - exit 1 - fi - source ${SOURCE_FILE_NAME} -fi - -# Define the path to the Docker Compose file -FILE_PATH="${NETWORK}-docker-compose.yml" -cp docker-compose.yml ${FILE_PATH} - -# Determine the appropriate Docker Compose configuration based on TYPE -if [ "$TYPE" == "image" ]; then - IMAGE_BLOCK="image: zetachain/zetacored:\${DOCKER_TAG:-ubuntu-v14.0.1.0}" - NAME="zetacored-rpc-${NETWORK}" -elif [ "$TYPE" == "localbuild" ]; then - IMAGE_BLOCK=$(cat << 'EOF' -build: - context: ../../.. - dockerfile: Dockerfile -EOF -) - NAME="zetacored-rpc-${NETWORK}-localbuild" -else - echo "Invalid TYPE. Please specify 'image' or 'localbuild'." - exit 1 -fi - -IMAGE_BLOCK_ESCAPED=$(echo "$IMAGE_BLOCK" | sed 's/[&/]/\\&/g; s/$/\\/') -IMAGE_BLOCK_ESCAPED=${IMAGE_BLOCK_ESCAPED%?} - -# Replace placeholders in the Docker Compose file -sed -i '' "s|-=name=-|$NAME|g" $FILE_PATH -sed -i '' "s|-=image_block=-|$IMAGE_BLOCK_ESCAPED|g" $FILE_PATH - -echo "DEBUG ENV VARS" -printenv -echo "================" - -echo "Placeholders have been replaced in $FILE_PATH." -cat $FILE_PATH -echo "================" - -if [ "$TYPE" == "image" ]; then - docker-compose -f ${FILE_PATH} up -elif [ "$TYPE" == "localbuild" ]; then - docker-compose -f ${FILE_PATH} up --build -fi diff --git a/contrib/rpc/zetacored/kill_docker_compose.sh b/contrib/rpc/zetacored/kill_docker_compose.sh deleted file mode 100644 index 5d6a2c192d..0000000000 --- a/contrib/rpc/zetacored/kill_docker_compose.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -NETWORK=${1} -CLEAN=${2} -FILE_PATH="${NETWORK}-docker-compose.yml" - -if [ "${CLEAN}" == "true" ]; then - docker-compose -f ${FILE_PATH} down -v - rm -rf ${FILE_PATH} -else - docker-compose -f ${FILE_PATH} down - rm -rf ${FILE_PATH} -fi - diff --git a/contrib/rpc/zetacored/networks/.athens3 b/contrib/rpc/zetacored/networks/.athens3 deleted file mode 100644 index 7de4cede3b..0000000000 --- a/contrib/rpc/zetacored/networks/.athens3 +++ /dev/null @@ -1,14 +0,0 @@ -export DAEMON_HOME="/root/.zetacored" -export NETWORK=athens3 -export RESTORE_TYPE="snapshot" -export SNAPSHOT_API=https://snapshots.rpc.zetachain.com -export TRUST_HEIGHT_DIFFERENCE_STATE_SYNC=40000 -export CHAIN_ID="athens_7001-1" -export VISOR_NAME="cosmovisor" -export DAEMON_NAME="zetacored" -export DAEMON_ALLOW_DOWNLOAD_BINARIES="false" -export DAEMON_RESTART_AFTER_UPGRADE="true" -export UNSAFE_SKIP_BACKUP="true" -export MONIKER=testnet-docker-rpc -export RE_DO_START_SEQUENCE="false" -export IS_LOCAL_DEVELOPMENT="false" diff --git a/contrib/rpc/zetacored/networks/.athens3-localbuild b/contrib/rpc/zetacored/networks/.athens3-localbuild deleted file mode 100644 index b79c14c220..0000000000 --- a/contrib/rpc/zetacored/networks/.athens3-localbuild +++ /dev/null @@ -1,14 +0,0 @@ -export DAEMON_HOME="/root/.zetacored" -export NETWORK=athens3 -export RESTORE_TYPE="snapshot" -export SNAPSHOT_API=https://snapshots.rpc.zetachain.com -export TRUST_HEIGHT_DIFFERENCE_STATE_SYNC=40000 -export CHAIN_ID="athens_7001-1" -export VISOR_NAME="cosmovisor" -export DAEMON_NAME="zetacored" -export DAEMON_ALLOW_DOWNLOAD_BINARIES="false" -export DAEMON_RESTART_AFTER_UPGRADE="false" -export UNSAFE_SKIP_BACKUP="true" -export MONIKER=testnet-docker-rpc -export RE_DO_START_SEQUENCE="false" -export IS_LOCAL_DEVELOPMENT="true" diff --git a/contrib/rpc/zetacored/networks/.mainnet b/contrib/rpc/zetacored/networks/.mainnet deleted file mode 100644 index ff260bb5ca..0000000000 --- a/contrib/rpc/zetacored/networks/.mainnet +++ /dev/null @@ -1,14 +0,0 @@ -export DAEMON_HOME="/root/.zetacored" -export NETWORK=mainnet -export RESTORE_TYPE="snapshot" -export SNAPSHOT_API=https://snapshots.rpc.zetachain.com -export TRUST_HEIGHT_DIFFERENCE_STATE_SYNC=40000 -export CHAIN_ID="zetachain_7000-1" -export VISOR_NAME="cosmovisor" -export DAEMON_NAME="zetacored" -export DAEMON_ALLOW_DOWNLOAD_BINARIES="false" -export DAEMON_RESTART_AFTER_UPGRADE="true" -export UNSAFE_SKIP_BACKUP="true" -export MONIKER=mainnet-docker-rpc -export RE_DO_START_SEQUENCE="false" -export IS_LOCAL_DEVELOPMENT="false" diff --git a/contrib/rpc/zetacored/networks/.mainnet-localbuild b/contrib/rpc/zetacored/networks/.mainnet-localbuild deleted file mode 100644 index 381c34bd6d..0000000000 --- a/contrib/rpc/zetacored/networks/.mainnet-localbuild +++ /dev/null @@ -1,14 +0,0 @@ -export DAEMON_HOME="/root/.zetacored" -export NETWORK=mainnet -export RESTORE_TYPE="snapshot" -export SNAPSHOT_API=https://snapshots.rpc.zetachain.com -export TRUST_HEIGHT_DIFFERENCE_STATE_SYNC=40000 -export CHAIN_ID="zetachain_7000-1" -export VISOR_NAME="cosmovisor" -export DAEMON_NAME="zetacored" -export DAEMON_ALLOW_DOWNLOAD_BINARIES="false" -export DAEMON_RESTART_AFTER_UPGRADE="false" -export UNSAFE_SKIP_BACKUP="true" -export MONIKER=mainnet-docker-rpc -export RE_DO_START_SEQUENCE="false" -export IS_LOCAL_DEVELOPMENT="true" From 148935c27a5d70a9402b2f5b103d1853b2c7a31f Mon Sep 17 00:00:00 2001 From: Lucas Bertrand Date: Wed, 8 Jan 2025 18:15:58 +0100 Subject: [PATCH 2/3] chore: prepare v25 (#3338) * disable precompiles * complete changelog * set v24 as base for upgrade tests * lint error --- Makefile | 4 ++-- changelog.md | 5 ++--- cmd/zetae2e/local/local.go | 28 +++++++++++++++------------- precompiles/precompiles.go | 6 +++--- 4 files changed, 22 insertions(+), 21 deletions(-) diff --git a/Makefile b/Makefile index 344ae150e4..02ac397d51 100644 --- a/Makefile +++ b/Makefile @@ -327,7 +327,7 @@ ifdef UPGRADE_TEST_FROM_SOURCE zetanode-upgrade: e2e-images @echo "Building zetanode-upgrade from source" $(DOCKER) build -t zetanode:old -f Dockerfile-localnet --target old-runtime-source \ - --build-arg OLD_VERSION='release/v23' \ + --build-arg OLD_VERSION='release/v24' \ --build-arg NODE_VERSION=$(NODE_VERSION) \ --build-arg NODE_COMMIT=$(NODE_COMMIT) . @@ -336,7 +336,7 @@ else zetanode-upgrade: e2e-images @echo "Building zetanode-upgrade from binaries" $(DOCKER) build -t zetanode:old -f Dockerfile-localnet --target old-runtime \ - --build-arg OLD_VERSION='https://github.com/zeta-chain/node/releases/download/v23.1.5' \ + --build-arg OLD_VERSION='https://github.com/zeta-chain/node/releases/download/v24.0.0' \ --build-arg NODE_VERSION=$(NODE_VERSION) \ --build-arg NODE_COMMIT=$(NODE_COMMIT) \ . diff --git a/changelog.md b/changelog.md index 5bb11d40cf..f878b67b3c 100644 --- a/changelog.md +++ b/changelog.md @@ -1,13 +1,12 @@ # CHANGELOG -## Unreleased +## v25.0.0 ### Features * [3235](https://github.com/zeta-chain/node/pull/3235) - add /systemtime telemetry endpoint (zetaclient) * [3317](https://github.com/zeta-chain/node/pull/3317) - add configurable signer latency correction (zetaclient) - ### Tests * [3205](https://github.com/zeta-chain/node/issues/3205) - move Bitcoin revert address test to advanced group to avoid upgrade test failure @@ -15,7 +14,7 @@ * [3095](https://github.com/zeta-chain/node/pull/3095) - initialize simulation tests for custom zetachain modules * [3276](https://github.com/zeta-chain/node/pull/3276) - add Solana E2E performance tests and improve Solana outbounds performance -## Refactor +### Refactor * [3170](https://github.com/zeta-chain/node/pull/3170) - revamp TSS package in zetaclient * [3291](https://github.com/zeta-chain/node/pull/3291) - revamp zetaclient initialization (+ graceful shutdown) diff --git a/cmd/zetae2e/local/local.go b/cmd/zetae2e/local/local.go index 8368e0d0bc..e32bfc0d77 100644 --- a/cmd/zetae2e/local/local.go +++ b/cmd/zetae2e/local/local.go @@ -338,23 +338,25 @@ func localE2ETest(cmd *cobra.Command, _ []string) { if !skipPrecompiles { precompiledContractTests := []string{ - e2etests.TestPrecompilesPrototypeName, - e2etests.TestPrecompilesPrototypeThroughContractName, - // Disabled until further notice, check https://github.com/zeta-chain/node/issues/3005. - // e2etests.TestPrecompilesStakingThroughContractName, - e2etests.TestPrecompilesBankName, - e2etests.TestPrecompilesBankFailName, - e2etests.TestPrecompilesBankThroughContractName, + //e2etests.TestPrecompilesPrototypeName, + //e2etests.TestPrecompilesPrototypeThroughContractName, + //// Disabled until further notice, check https://github.com/zeta-chain/node/issues/3005. + //// e2etests.TestPrecompilesStakingThroughContractName, + //e2etests.TestPrecompilesBankName, + //e2etests.TestPrecompilesBankFailName, + //e2etests.TestPrecompilesBankThroughContractName, } if e2eStartHeight < 100 { // these tests require a clean system // since unstaking has an unbonding period - precompiledContractTests = append(precompiledContractTests, - e2etests.TestPrecompilesStakingName, - e2etests.TestPrecompilesDistributeName, - e2etests.TestPrecompilesDistributeNonZRC20Name, - e2etests.TestPrecompilesDistributeThroughContractName, - ) + //precompiledContractTests = append(precompiledContractTests, + // e2etests.TestPrecompilesStakingName, + // e2etests.TestPrecompilesDistributeName, + // e2etests.TestPrecompilesDistributeNonZRC20Name, + // e2etests.TestPrecompilesDistributeThroughContractName, + //) + // prevent lint error + _ = precompiledContractTests } else { logger.Print("⚠️ partial precompiled run (unclean state)") } diff --git a/precompiles/precompiles.go b/precompiles/precompiles.go index 3c9a066812..557d880ab4 100644 --- a/precompiles/precompiles.go +++ b/precompiles/precompiles.go @@ -22,9 +22,9 @@ import ( // This is useful for listing and reading from other packages, such as BlockedAddrs() function. // Setting to false a contract here will disable it, not being included in the blockchain. var EnabledStatefulContracts = map[common.Address]bool{ - prototype.ContractAddress: true, - staking.ContractAddress: true, - bank.ContractAddress: true, + prototype.ContractAddress: false, + staking.ContractAddress: false, + bank.ContractAddress: false, } // StatefulContracts returns all the registered precompiled contracts. From 47c9444bbd115176a2736f31be8cb7d23b0059e7 Mon Sep 17 00:00:00 2001 From: Alex Gartner Date: Wed, 8 Jan 2025 09:45:22 -0800 Subject: [PATCH 3/3] feat: add zetaclient minimum version check (#3320) * feat: add minimum version check * review feedback * changelog --- changelog.md | 1 + cmd/zetaclientd/start.go | 27 ++++-- docs/openapi/openapi.swagger.yaml | 6 ++ .../zetacore/observer/operational.proto | 5 + .../zetacore/observer/operational_pb.d.ts | 9 ++ x/observer/types/errors.go | 5 + x/observer/types/operational.go | 4 + x/observer/types/operational.pb.go | 94 +++++++++++++++---- x/observer/types/operational_test.go | 18 ++++ zetaclient/maintenance/shutdown_listener.go | 65 +++++++++++-- .../maintenance/shutdown_listener_test.go | 59 +++++++++++- 11 files changed, 256 insertions(+), 37 deletions(-) diff --git a/changelog.md b/changelog.md index f878b67b3c..4442a0cbba 100644 --- a/changelog.md +++ b/changelog.md @@ -6,6 +6,7 @@ * [3235](https://github.com/zeta-chain/node/pull/3235) - add /systemtime telemetry endpoint (zetaclient) * [3317](https://github.com/zeta-chain/node/pull/3317) - add configurable signer latency correction (zetaclient) +* [3320](https://github.com/zeta-chain/node/pull/3320) - add zetaclient minimum version check ### Tests diff --git a/cmd/zetaclientd/start.go b/cmd/zetaclientd/start.go index 2a46dabdbd..ae7da7e6ac 100644 --- a/cmd/zetaclientd/start.go +++ b/cmd/zetaclientd/start.go @@ -83,6 +83,20 @@ func Start(_ *cobra.Command, _ []string) error { return errors.Wrap(err, "unable to resolve observer pub key bech32") } + isObserver, err := isObserverNode(ctx, zetacoreClient) + switch { + case err != nil: + return errors.Wrap(err, "unable to check if observer node") + case !isObserver: + logger.Std.Warn().Msg("This node is not an observer node. Exit 0") + return nil + } + + shutdownListener := maintenance.NewShutdownListener(zetacoreClient, logger.Std) + if err := shutdownListener.RunPreStartCheck(ctx); err != nil { + return errors.Wrap(err, "pre start check failed") + } + tssSetupProps := zetatss.SetupProps{ Config: cfg, Zetacore: zetacoreClient, @@ -94,20 +108,13 @@ func Start(_ *cobra.Command, _ []string) error { Telemetry: telemetry, } + // This will start p2p communication so it should only happen after + // preflight checks have completed tss, err := zetatss.Setup(ctx, tssSetupProps, logger.Std) if err != nil { return errors.Wrap(err, "unable to setup TSS service") } - isObserver, err := isObserverNode(ctx, zetacoreClient) - switch { - case err != nil: - return errors.Wrap(err, "unable to check if observer node") - case !isObserver: - logger.Std.Warn().Msg("This node is not an observer node. Exit 0") - return nil - } - // Starts various background TSS listeners. // Shuts down zetaclientd if any is triggered. maintenance.NewTSSListener(zetacoreClient, logger.Std).Listen(ctx, func() { @@ -115,7 +122,7 @@ func Start(_ *cobra.Command, _ []string) error { graceful.ShutdownNow() }) - maintenance.NewShutdownListener(zetacoreClient, logger.Std).Listen(ctx, func() { + shutdownListener.Listen(ctx, func() { logger.Std.Info().Msg("Shutdown listener received an action to shutdown zetaclientd.") graceful.ShutdownNow() }) diff --git a/docs/openapi/openapi.swagger.yaml b/docs/openapi/openapi.swagger.yaml index 694f839db6..11756a1c7b 100644 --- a/docs/openapi/openapi.swagger.yaml +++ b/docs/openapi/openapi.swagger.yaml @@ -58115,6 +58115,12 @@ definitions: description: |- Offset from the zetacore block time to initiate signing. Should be calculated and set based on max(zetaclient_core_block_latency). + minimum_version: + type: string + description: |- + Minimum version of zetaclient that is allowed to run. This must be either + a valid semver string (v23.0.1) or empty. If empty, all versions are + allowed. description: Flags for the top-level operation of zetaclient. observerPendingNonces: type: object diff --git a/proto/zetachain/zetacore/observer/operational.proto b/proto/zetachain/zetacore/observer/operational.proto index 62ff737074..05096a57c3 100644 --- a/proto/zetachain/zetacore/observer/operational.proto +++ b/proto/zetachain/zetacore/observer/operational.proto @@ -16,4 +16,9 @@ message OperationalFlags { // Should be calculated and set based on max(zetaclient_core_block_latency). google.protobuf.Duration signer_block_time_offset = 2 [ (gogoproto.stdduration) = true ]; + + // Minimum version of zetaclient that is allowed to run. This must be either + // a valid semver string (v23.0.1) or empty. If empty, all versions are + // allowed. + string minimum_version = 3; } \ No newline at end of file diff --git a/typescript/zetachain/zetacore/observer/operational_pb.d.ts b/typescript/zetachain/zetacore/observer/operational_pb.d.ts index c9fc213927..4f18ce91a0 100644 --- a/typescript/zetachain/zetacore/observer/operational_pb.d.ts +++ b/typescript/zetachain/zetacore/observer/operational_pb.d.ts @@ -28,6 +28,15 @@ export declare class OperationalFlags extends Message { */ signerBlockTimeOffset?: Duration; + /** + * Minimum version of zetaclient that is allowed to run. This must be either + * a valid semver string (v23.0.1) or empty. If empty, all versions are + * allowed. + * + * @generated from field: string minimum_version = 3; + */ + minimumVersion: string; + constructor(data?: PartialMessage); static readonly runtime: typeof proto3; diff --git a/x/observer/types/errors.go b/x/observer/types/errors.go index fbc6261d76..aaebb297b4 100644 --- a/x/observer/types/errors.go +++ b/x/observer/types/errors.go @@ -71,4 +71,9 @@ var ( 1140, "signer block time offset exceeds limit", ) + ErrOperationalFlagsInvalidMinimumVersion = errorsmod.Register( + ModuleName, + 1141, + "minimum version is not a valid semver string", + ) ) diff --git a/x/observer/types/operational.go b/x/observer/types/operational.go index 4da766c53a..e90415acdf 100644 --- a/x/observer/types/operational.go +++ b/x/observer/types/operational.go @@ -4,6 +4,7 @@ import ( "time" cosmoserrors "cosmossdk.io/errors" + "golang.org/x/mod/semver" ) const ( @@ -23,5 +24,8 @@ func (f *OperationalFlags) Validate() error { return cosmoserrors.Wrapf(ErrOperationalFlagsSignerBlockTimeOffsetLimit, "(%s)", signerBlockTimeOffset) } } + if f.MinimumVersion != "" && !semver.IsValid(f.MinimumVersion) { + return ErrOperationalFlagsInvalidMinimumVersion + } return nil } diff --git a/x/observer/types/operational.pb.go b/x/observer/types/operational.pb.go index e5fb9c3281..a23aed758b 100644 --- a/x/observer/types/operational.pb.go +++ b/x/observer/types/operational.pb.go @@ -35,6 +35,10 @@ type OperationalFlags struct { // Offset from the zetacore block time to initiate signing. // Should be calculated and set based on max(zetaclient_core_block_latency). SignerBlockTimeOffset *time.Duration `protobuf:"bytes,2,opt,name=signer_block_time_offset,json=signerBlockTimeOffset,proto3,stdduration" json:"signer_block_time_offset,omitempty"` + // Minimum version of zetaclient that is allowed to run. This must be either + // a valid semver string (v23.0.1) or empty. If empty, all versions are + // allowed. + MinimumVersion string `protobuf:"bytes,3,opt,name=minimum_version,json=minimumVersion,proto3" json:"minimum_version,omitempty"` } func (m *OperationalFlags) Reset() { *m = OperationalFlags{} } @@ -84,6 +88,13 @@ func (m *OperationalFlags) GetSignerBlockTimeOffset() *time.Duration { return nil } +func (m *OperationalFlags) GetMinimumVersion() string { + if m != nil { + return m.MinimumVersion + } + return "" +} + func init() { proto.RegisterType((*OperationalFlags)(nil), "zetachain.zetacore.observer.OperationalFlags") } @@ -93,25 +104,27 @@ func init() { } var fileDescriptor_ea3eed2ec55093b5 = []byte{ - // 282 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x44, 0x90, 0xc1, 0x4a, 0xec, 0x30, - 0x14, 0x86, 0x27, 0xf7, 0x8a, 0x8b, 0x8a, 0x22, 0x83, 0x42, 0x1d, 0x21, 0x0e, 0x82, 0x30, 0x20, - 0x93, 0x80, 0xbe, 0x41, 0x51, 0x71, 0x37, 0x30, 0xb8, 0x10, 0x37, 0x25, 0xed, 0x9c, 0xa6, 0xc1, - 0xb6, 0xa7, 0x24, 0xa9, 0xa8, 0x4f, 0x21, 0xb8, 0xf1, 0x91, 0x5c, 0xce, 0xd2, 0x9d, 0xd2, 0xbe, - 0x88, 0x4c, 0x32, 0x75, 0x76, 0x27, 0x27, 0xdf, 0x7f, 0x3e, 0xf8, 0x83, 0xe9, 0x2b, 0x58, 0x91, - 0xe6, 0x42, 0x55, 0xdc, 0x4d, 0xa8, 0x81, 0x63, 0x62, 0x40, 0x3f, 0x81, 0xe6, 0x58, 0x83, 0x16, - 0x56, 0x61, 0x25, 0x0a, 0x56, 0x6b, 0xb4, 0x38, 0x3c, 0xfe, 0xc3, 0x59, 0x8f, 0xb3, 0x1e, 0x1f, - 0x1d, 0x48, 0x94, 0xe8, 0x38, 0xbe, 0x9a, 0x7c, 0x64, 0x44, 0x25, 0xa2, 0x2c, 0x80, 0xbb, 0x57, - 0xd2, 0x64, 0x7c, 0xd1, 0xf8, 0xa3, 0xfe, 0xff, 0xf4, 0x9d, 0x04, 0xfb, 0xb3, 0x8d, 0xe8, 0xa6, - 0x10, 0xd2, 0x0c, 0xcf, 0x82, 0x3d, 0x0d, 0xc6, 0x0a, 0x6d, 0xe3, 0x1c, 0x94, 0xcc, 0x6d, 0x48, - 0xc6, 0x64, 0xf2, 0x7f, 0xbe, 0xbb, 0xde, 0xde, 0xba, 0xe5, 0xf0, 0x3e, 0x08, 0x8d, 0x92, 0x15, - 0xe8, 0x38, 0x29, 0x30, 0x7d, 0x8c, 0xad, 0x2a, 0x21, 0xc6, 0x2c, 0x33, 0x60, 0xc3, 0x7f, 0x63, - 0x32, 0xd9, 0xb9, 0x38, 0x62, 0x5e, 0xcf, 0x7a, 0x3d, 0xbb, 0x5a, 0xeb, 0xa3, 0xad, 0x8f, 0xef, - 0x13, 0x32, 0x3f, 0xf4, 0x07, 0xa2, 0x55, 0xfe, 0x4e, 0x95, 0x30, 0x73, 0xe9, 0xe8, 0xfa, 0xb3, - 0xa5, 0x64, 0xd9, 0x52, 0xf2, 0xd3, 0x52, 0xf2, 0xd6, 0xd1, 0xc1, 0xb2, 0xa3, 0x83, 0xaf, 0x8e, - 0x0e, 0x1e, 0xce, 0xa5, 0xb2, 0x79, 0x93, 0xb0, 0x14, 0x4b, 0x57, 0xd9, 0xd4, 0xb7, 0x57, 0xe1, - 0x02, 0xf8, 0xf3, 0xa6, 0x3b, 0xfb, 0x52, 0x83, 0x49, 0xb6, 0x9d, 0xf6, 0xf2, 0x37, 0x00, 0x00, - 0xff, 0xff, 0xf0, 0xe0, 0x3c, 0x60, 0x67, 0x01, 0x00, 0x00, + // 308 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x44, 0x90, 0x41, 0x4a, 0x03, 0x31, + 0x14, 0x86, 0x1b, 0x2b, 0x82, 0x23, 0x56, 0x19, 0x14, 0xc6, 0x0a, 0xb1, 0x08, 0x62, 0x41, 0x9a, + 0x80, 0xde, 0xa0, 0xa8, 0xb8, 0x2b, 0x14, 0x11, 0x71, 0x33, 0xcc, 0xb4, 0xaf, 0x99, 0xe0, 0x24, + 0xaf, 0x24, 0x99, 0xa2, 0x9e, 0xc2, 0xa5, 0x87, 0xf1, 0x00, 0x2e, 0xbb, 0x74, 0xa7, 0xb4, 0x17, + 0x91, 0x26, 0xad, 0xdd, 0xbd, 0xfc, 0xf9, 0xff, 0xf7, 0x3d, 0xfe, 0xa8, 0xf3, 0x06, 0x2e, 0x1b, + 0x14, 0x99, 0xd4, 0xdc, 0x4f, 0x68, 0x80, 0x63, 0x6e, 0xc1, 0x4c, 0xc0, 0x70, 0x1c, 0x83, 0xc9, + 0x9c, 0x44, 0x9d, 0x95, 0x6c, 0x6c, 0xd0, 0x61, 0x7c, 0xfc, 0x6f, 0x67, 0x2b, 0x3b, 0x5b, 0xd9, + 0x9b, 0x07, 0x02, 0x05, 0x7a, 0x1f, 0x5f, 0x4c, 0x21, 0xd2, 0xa4, 0x02, 0x51, 0x94, 0xc0, 0xfd, + 0x2b, 0xaf, 0x46, 0x7c, 0x58, 0x85, 0xa5, 0xe1, 0xff, 0xf4, 0x93, 0x44, 0xfb, 0xbd, 0x35, 0xe8, + 0xb6, 0xcc, 0x84, 0x8d, 0xcf, 0xa2, 0x86, 0x01, 0xeb, 0x32, 0xe3, 0xd2, 0x02, 0xa4, 0x28, 0x5c, + 0x42, 0x5a, 0xa4, 0x5d, 0xef, 0xef, 0x2e, 0xd5, 0x3b, 0x2f, 0xc6, 0x8f, 0x51, 0x62, 0xa5, 0xd0, + 0x60, 0xd2, 0xbc, 0xc4, 0xc1, 0x73, 0xea, 0xa4, 0x82, 0x14, 0x47, 0x23, 0x0b, 0x2e, 0xd9, 0x68, + 0x91, 0xf6, 0xce, 0xe5, 0x11, 0x0b, 0x78, 0xb6, 0xc2, 0xb3, 0xeb, 0x25, 0xbe, 0xbb, 0xf9, 0xf1, + 0x73, 0x42, 0xfa, 0x87, 0x61, 0x41, 0x77, 0x91, 0xbf, 0x97, 0x0a, 0x7a, 0x3e, 0x1d, 0x9f, 0x47, + 0x7b, 0x4a, 0x6a, 0xa9, 0x2a, 0x95, 0x4e, 0xc0, 0x58, 0x89, 0x3a, 0xa9, 0xb7, 0x48, 0x7b, 0xbb, + 0xdf, 0x58, 0xca, 0x0f, 0x41, 0xed, 0xde, 0x7c, 0xcd, 0x28, 0x99, 0xce, 0x28, 0xf9, 0x9d, 0x51, + 0xf2, 0x3e, 0xa7, 0xb5, 0xe9, 0x9c, 0xd6, 0xbe, 0xe7, 0xb4, 0xf6, 0x74, 0x21, 0xa4, 0x2b, 0xaa, + 0x9c, 0x0d, 0x50, 0xf9, 0x6e, 0x3b, 0xa1, 0x66, 0x8d, 0x43, 0xe0, 0x2f, 0xeb, 0x92, 0xdd, 0xeb, + 0x18, 0x6c, 0xbe, 0xe5, 0xef, 0xbb, 0xfa, 0x0b, 0x00, 0x00, 0xff, 0xff, 0xe9, 0x88, 0xe2, 0xfd, + 0x90, 0x01, 0x00, 0x00, } func (m *OperationalFlags) Marshal() (dAtA []byte, err error) { @@ -134,6 +147,13 @@ func (m *OperationalFlags) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.MinimumVersion) > 0 { + i -= len(m.MinimumVersion) + copy(dAtA[i:], m.MinimumVersion) + i = encodeVarintOperational(dAtA, i, uint64(len(m.MinimumVersion))) + i-- + dAtA[i] = 0x1a + } if m.SignerBlockTimeOffset != nil { n1, err1 := github_com_cosmos_gogoproto_types.StdDurationMarshalTo(*m.SignerBlockTimeOffset, dAtA[i-github_com_cosmos_gogoproto_types.SizeOfStdDuration(*m.SignerBlockTimeOffset):]) if err1 != nil { @@ -176,6 +196,10 @@ func (m *OperationalFlags) Size() (n int) { l = github_com_cosmos_gogoproto_types.SizeOfStdDuration(*m.SignerBlockTimeOffset) n += 1 + l + sovOperational(uint64(l)) } + l = len(m.MinimumVersion) + if l > 0 { + n += 1 + l + sovOperational(uint64(l)) + } return n } @@ -269,6 +293,38 @@ func (m *OperationalFlags) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field MinimumVersion", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowOperational + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthOperational + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthOperational + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.MinimumVersion = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipOperational(dAtA[iNdEx:]) diff --git a/x/observer/types/operational_test.go b/x/observer/types/operational_test.go index 79c8caf0dc..ca0e6056b8 100644 --- a/x/observer/types/operational_test.go +++ b/x/observer/types/operational_test.go @@ -15,6 +15,10 @@ func TestOperationalFlags_Validate(t *testing.T) { of types.OperationalFlags errContains string }{ + { + name: "empty is valid", + of: types.OperationalFlags{}, + }, { name: "invalid restart height", of: types.OperationalFlags{ @@ -48,11 +52,25 @@ func TestOperationalFlags_Validate(t *testing.T) { }, errContains: types.ErrOperationalFlagsSignerBlockTimeOffsetLimit.Error(), }, + { + name: "minimum version valid", + of: types.OperationalFlags{ + MinimumVersion: "v1.1.1", + }, + }, + { + name: "minimum version invalid", + of: types.OperationalFlags{ + MinimumVersion: "asdf", + }, + errContains: types.ErrOperationalFlagsInvalidMinimumVersion.Error(), + }, { name: "all flags valid", of: types.OperationalFlags{ RestartHeight: 1, SignerBlockTimeOffset: ptr.Ptr(time.Second), + MinimumVersion: "v1.1.1", }, }, } diff --git a/zetaclient/maintenance/shutdown_listener.go b/zetaclient/maintenance/shutdown_listener.go index 0ac3b18d75..edbd93bedd 100644 --- a/zetaclient/maintenance/shutdown_listener.go +++ b/zetaclient/maintenance/shutdown_listener.go @@ -2,12 +2,16 @@ package maintenance import ( "context" + "fmt" + "strings" "time" "cosmossdk.io/errors" "github.com/rs/zerolog" + "golang.org/x/mod/semver" "github.com/zeta-chain/node/pkg/bg" + "github.com/zeta-chain/node/pkg/constant" "github.com/zeta-chain/node/pkg/retry" observertypes "github.com/zeta-chain/node/x/observer/types" "github.com/zeta-chain/node/zetaclient/chains/interfaces" @@ -22,17 +26,30 @@ type ShutdownListener struct { logger zerolog.Logger lastRestartHeightMissed int64 + // get the current version of zetaclient + getVersion func() string } // NewShutdownListener creates a new ShutdownListener. func NewShutdownListener(client interfaces.ZetacoreClient, logger zerolog.Logger) *ShutdownListener { log := logger.With().Str("module", "shutdown_listener").Logger() return &ShutdownListener{ - client: client, - logger: log, + client: client, + logger: log, + getVersion: getVersionDefault, } } +// RunPreStartCheck runs any checks that must run before fully starting zetaclient. +// Specifically this should be run before any TSS P2P is started. +func (o *ShutdownListener) RunPreStartCheck(ctx context.Context) error { + operationalFlags, err := o.getOperationalFlagsWithRetry(ctx) + if err != nil { + return errors.Wrap(err, "unable to get initial operational flags") + } + return o.checkMinimumVersion(operationalFlags) +} + func (o *ShutdownListener) Listen(ctx context.Context, action func()) { var ( withLogger = bg.WithLogger(o.logger) @@ -43,12 +60,9 @@ func (o *ShutdownListener) Listen(ctx context.Context, action func()) { } func (o *ShutdownListener) waitForUpdate(ctx context.Context) error { - operationalFlags, err := retry.DoTypedWithBackoffAndRetry( - func() (observertypes.OperationalFlags, error) { return o.client.GetOperationalFlags(ctx) }, - retry.DefaultConstantBackoff(), - ) + operationalFlags, err := o.getOperationalFlagsWithRetry(ctx) if err != nil { - return errors.Wrap(err, "unable to get initial operational flags") + return errors.Wrap(err, "get initial operational flags") } if o.handleNewFlags(ctx, operationalFlags) { return nil @@ -74,8 +88,19 @@ func (o *ShutdownListener) waitForUpdate(ctx context.Context) error { } } +func (o *ShutdownListener) getOperationalFlagsWithRetry(ctx context.Context) (observertypes.OperationalFlags, error) { + return retry.DoTypedWithBackoffAndRetry( + func() (observertypes.OperationalFlags, error) { return o.client.GetOperationalFlags(ctx) }, + retry.DefaultConstantBackoff(), + ) +} + // handleNewFlags processes the flags and returns true if a shutdown should be signaled func (o *ShutdownListener) handleNewFlags(ctx context.Context, f observertypes.OperationalFlags) bool { + if err := o.checkMinimumVersion(f); err != nil { + o.logger.Error().Err(err).Any("operational_flags", f).Msg("minimum version check") + return true + } if f.RestartHeight < 1 { return false } @@ -123,3 +148,29 @@ func (o *ShutdownListener) handleNewFlags(ctx context.Context, f observertypes.O } } } + +func (o *ShutdownListener) checkMinimumVersion(f observertypes.OperationalFlags) error { + if f.MinimumVersion != "" { + // we typically store the version without the required v prefix + currentVersion := ensurePrefix(o.getVersion(), "v") + if semver.Compare(currentVersion, f.MinimumVersion) == -1 { + return fmt.Errorf( + "current version (%s) is less than minimum version (%s)", + currentVersion, + f.MinimumVersion, + ) + } + } + return nil +} + +func getVersionDefault() string { + return constant.Version +} + +func ensurePrefix(s, prefix string) string { + if !strings.HasPrefix(s, prefix) { + return prefix + s + } + return s +} diff --git a/zetaclient/maintenance/shutdown_listener_test.go b/zetaclient/maintenance/shutdown_listener_test.go index 2b2c9128d1..c85c70cde0 100644 --- a/zetaclient/maintenance/shutdown_listener_test.go +++ b/zetaclient/maintenance/shutdown_listener_test.go @@ -100,8 +100,65 @@ func TestShutdownListener(t *testing.T) { return len(client.Calls) == 2 }, time.Second, time.Millisecond) assertChannelNotClosed(t, complete) - cancel() }) + + t.Run("minimum version ok", func(t *testing.T) { + client := mocks.NewZetacoreClient(t) + + listener := NewShutdownListener(client, logger) + listener.getVersion = func() string { + return "1.1.2" + } + + client.Mock.On("GetOperationalFlags", ctx).Return(observertypes.OperationalFlags{ + MinimumVersion: "v1.1.1", + }, nil) + + // pre start checks passed + err := listener.RunPreStartCheck(ctx) + require.NoError(t, err) + + // listener also does not shutdown + complete := make(chan interface{}) + listener.Listen(ctx, func() { + close(complete) + }) + + require.Eventually(t, func() bool { + return len(client.Calls) == 2 + }, time.Second, time.Millisecond) + assertChannelNotClosed(t, complete) + }) + + t.Run("minimum version failed", func(t *testing.T) { + client := mocks.NewZetacoreClient(t) + + listener := NewShutdownListener(client, logger) + listener.getVersion = func() string { + return "1.1.1" + } + + client.Mock.On("GetOperationalFlags", ctx).Return(observertypes.OperationalFlags{ + MinimumVersion: "v1.1.2", + }, nil) + + // pre start checks would return error + err := listener.RunPreStartCheck(ctx) + require.Error(t, err) + + // listener would also shutdown + complete := make(chan interface{}) + listener.Listen(ctx, func() { + close(complete) + }) + + require.Eventually(t, func() bool { + return len(client.Calls) == 2 + }, time.Second, time.Millisecond) + <-complete + }) + // avoid Log in goroutine after TestShutdownListener has completed + cancel() time.Sleep(time.Millisecond * 100) }