├── .github └── workflows │ ├── build-images.yml │ └── promote-latest.yml ├── .gitignore ├── Dockerfile ├── LICENSE ├── README.md ├── SECURITY.md ├── build.sh ├── cleanup.sh ├── entrypoint.sh ├── install.sh ├── run.sh ├── scan-vuln.sh ├── scripts ├── build-network.sh ├── configs │ ├── mainnet.sh │ ├── stagenet.sh │ └── testnet.sh ├── operator-cli.sh ├── set-password.sh ├── shell.sh └── upgrade.sh └── tag.sh /.github/workflows/build-images.yml: -------------------------------------------------------------------------------- 1 | name: Build Docker Images 2 | 3 | # Add permissions configuration 4 | permissions: 5 | contents: read 6 | packages: write 7 | 8 | env: 9 | REGISTRY: ghcr.io 10 | IMAGE_NAME: ${{ github.repository }} 11 | 12 | on: 13 | workflow_dispatch: 14 | inputs: 15 | network: 16 | description: 'Network to build for' 17 | required: true 18 | type: choice 19 | options: 20 | - mainnet 21 | - stagenet 22 | - testnet 23 | default: 'testnet' 24 | validator_branch: 25 | description: 'Validator branch to use' 26 | type: string 27 | cli_branch: 28 | description: 'CLI branch to use' 29 | type: string 30 | gui_branch: 31 | description: 'GUI branch to use' 32 | type: string 33 | tag: 34 | description: 'Tag for the Docker images' 35 | required: true 36 | type: string 37 | 38 | jobs: 39 | build: 40 | strategy: 41 | matrix: 42 | arch: [amd64, arm64] 43 | include: 44 | - arch: amd64 45 | runner: [self-hosted, Linux, X64] 46 | - arch: arm64 47 | runner: [self-hosted, Linux, ARM64] 48 | runs-on: ${{ matrix.runner }} 49 | 50 | steps: 51 | - uses: actions/checkout@v3 52 | 53 | - name: Login to GitHub Container Registry 54 | uses: docker/login-action@v2 55 | with: 56 | registry: ${{ env.REGISTRY }} 57 | username: ${{ github.actor }} 58 | password: ${{ secrets.GITHUB_TOKEN }} 59 | 60 | - name: Override branch variables in config 61 | run: | 62 | CONFIG="scripts/configs/${{ inputs.network }}.sh" 63 | if [ -n "${{ inputs.validator_branch }}" ]; then 64 | sed -i 's/^export VALIDATOR_BRANCH=.*/export VALIDATOR_BRANCH="${{ inputs.validator_branch }}"/' "$CONFIG" 65 | fi 66 | if [ -n "${{ inputs.cli_branch }}" ]; then 67 | sed -i 's/^export CLI_BRANCH=.*/export CLI_BRANCH="${{ inputs.cli_branch }}"/' "$CONFIG" 68 | fi 69 | if [ -n "${{ inputs.gui_branch }}" ]; then 70 | sed -i 's/^export GUI_BRANCH=.*/export GUI_BRANCH="${{ inputs.gui_branch }}"/' "$CONFIG" 71 | fi 72 | 73 | - name: Build Docker image using script 74 | run: | 75 | ./scripts/build-network.sh ${{ inputs.network }} ${{ inputs.tag }} ${{ matrix.arch }} ${{ env.REGISTRY }} 76 | 77 | - name: Push Docker image and cleanup 78 | run: | 79 | # Construct the image name exactly as the script does 80 | IMAGE_NAME_FULL="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-${{ matrix.arch }}:${{ inputs.network }}-${{ inputs.tag }}" 81 | echo "Pushing: $IMAGE_NAME_FULL" 82 | docker push "$IMAGE_NAME_FULL" 83 | echo "Removing: $IMAGE_NAME_FULL" 84 | docker rmi "$IMAGE_NAME_FULL" 85 | 86 | create-manifest: 87 | needs: build 88 | runs-on: ubuntu-latest 89 | steps: 90 | - name: Login to GitHub Container Registry 91 | uses: docker/login-action@v2 92 | with: 93 | registry: ${{ env.REGISTRY }} 94 | username: ${{ github.actor }} 95 | password: ${{ secrets.GITHUB_TOKEN }} 96 | 97 | - name: Create and push manifest per network and capture digest 98 | id: push_network_manifest 99 | run: | 100 | MANIFEST_NAME="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ inputs.network }}-${{ inputs.tag }}" 101 | IMG_AMD64="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-amd64:${{ inputs.network }}-${{ inputs.tag }}" 102 | IMG_ARM64="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-arm64:${{ inputs.network }}-${{ inputs.tag }}" 103 | echo "Creating manifest: $MANIFEST_NAME from $IMG_AMD64 and $IMG_ARM64" 104 | docker manifest create "$MANIFEST_NAME" \ 105 | "$IMG_AMD64" \ 106 | "$IMG_ARM64" 107 | echo "Pushing manifest: $MANIFEST_NAME" 108 | MANIFEST_DIGEST=$(docker manifest push "$MANIFEST_NAME") 109 | echo "Pushed manifest digest for ${MANIFEST_NAME}: $MANIFEST_DIGEST" 110 | echo "digest=$MANIFEST_DIGEST" >> $GITHUB_OUTPUT 111 | 112 | 113 | - name: Send Slack notification for image build 114 | if: success() # Only run this step if previous steps succeed 115 | uses: slackapi/slack-github-action@v2.1.0 116 | with: 117 | webhook: ${{ secrets.SLACK_WEBHOOK_URL }} 118 | webhook-type: incoming-webhook 119 | payload: | 120 | text: | 121 | *:hammer_and_wrench: New Image Build Completed* 122 | Repository: `${{ github.repository }}` 123 | Network: `${{ inputs.network }}` 124 | Tag: `${{ inputs.tag }}` 125 | Full Tag: `${{ inputs.network }}-${{ inputs.tag }}` 126 | Image URL: `${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ inputs.network }}-${{ inputs.tag }}` 127 | Validator Branch: `${{ inputs.validator_branch }}` 128 | CLI Branch: `${{ inputs.cli_branch }}` 129 | GUI Branch: `${{ inputs.gui_branch }}` 130 | Manifest Digest: `${{ steps.push_network_manifest.outputs.digest }}` 131 | Triggered by: `${{ github.actor }}` 132 | 133 | blocks: 134 | - type: header 135 | text: 136 | type: plain_text 137 | text: ":hammer_and_wrench: New Image Build Completed" 138 | - type: section 139 | fields: 140 | - type: mrkdwn 141 | text: "*Repository:* `${{ github.repository }}`" 142 | - type: mrkdwn 143 | text: "*Network:* `${{ inputs.network }}`" 144 | - type: mrkdwn 145 | text: "*Tag:* `${{ inputs.tag }}`" 146 | - type: mrkdwn 147 | text: "*Full Tag:* `${{ inputs.network }}-${{ inputs.tag }}`" 148 | - type: mrkdwn 149 | text: "*Image URL:* `${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ inputs.network }}-${{ inputs.tag }}`" 150 | - type: mrkdwn 151 | text: "*Validator Branch:* `${{ inputs.validator_branch }}`" 152 | - type: mrkdwn 153 | text: "*CLI Branch:* `${{ inputs.cli_branch }}`" 154 | - type: mrkdwn 155 | text: "*GUI Branch:* `${{ inputs.gui_branch }}`" 156 | - type: section 157 | text: 158 | type: mrkdwn 159 | text: "*Manifest Digest (${{ inputs.network }}-${{ inputs.tag }}):* `${{ steps.push_network_manifest.outputs.digest }}`" 160 | - type: context 161 | elements: 162 | - type: mrkdwn 163 | text: "Triggered by `${{ github.actor }}`. " 164 | -------------------------------------------------------------------------------- /.github/workflows/promote-latest.yml: -------------------------------------------------------------------------------- 1 | name: Promote Docker Tag to Latest 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | tag: 7 | description: 'Tag to promote to latest (e.g., mainnet-v1.2.3)' 8 | required: true 9 | type: string 10 | 11 | env: 12 | REGISTRY: ghcr.io 13 | IMAGE_NAME: ${{ github.repository }} 14 | 15 | permissions: 16 | contents: read 17 | packages: write 18 | 19 | jobs: 20 | promote-latest: 21 | runs-on: ubuntu-latest 22 | steps: 23 | - name: Log in to GitHub Container Registry 24 | uses: docker/login-action@v2 25 | with: 26 | registry: ${{ env.REGISTRY }} 27 | username: ${{ github.actor }} 28 | password: ${{ secrets.GITHUB_TOKEN }} 29 | 30 | - name: Tag and push amd64 image as latest 31 | run: | 32 | docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-amd64:${{ inputs.tag }} 33 | docker tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-amd64:${{ inputs.tag }} ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-amd64:latest 34 | docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-amd64:latest 35 | 36 | - name: Tag and push arm64 image as latest 37 | run: | 38 | docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-arm64:${{ inputs.tag }} 39 | docker tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-arm64:${{ inputs.tag }} ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-arm64:latest 40 | docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-arm64:latest 41 | 42 | - name: Create and push latest manifest and capture digest 43 | id: push_manifest 44 | run: | 45 | docker manifest create ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest \ 46 | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-amd64:latest \ 47 | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-arm64:latest 48 | 49 | # The docker manifest push command outputs the digest directly to stdout 50 | # e.g., sha256:0123456789abcdef... 51 | MANIFEST_DIGEST=$(docker manifest push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest) 52 | echo "Pushed manifest digest: $MANIFEST_DIGEST" # Log for verification during workflow run 53 | echo "digest=$MANIFEST_DIGEST" >> $GITHUB_OUTPUT 54 | 55 | - name: Send Slack notification on success 56 | if: success() # Only run this step if previous steps succeed 57 | uses: slackapi/slack-github-action@v2.1.0 58 | with: 59 | webhook: ${{ secrets.SLACK_WEBHOOK_URL }} 60 | webhook-type: incoming-webhook 61 | payload: | 62 | text: | 63 | *:rocket: New Image Promoted to Latest* 64 | Repository: `${{ github.repository }}` 65 | Input Tag: `${{ inputs.tag }}` 66 | Full Tag: `latest` 67 | Image URL: `${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest` 68 | Manifest Digest: `${{ steps.push_manifest.outputs.digest }}` 69 | Triggered by: `${{ github.actor }}` 70 | 71 | blocks: 72 | - type: header 73 | text: 74 | type: plain_text 75 | text: ":rocket: New Image Promoted to Latest" 76 | - type: section 77 | fields: 78 | - type: mrkdwn 79 | text: "*Repository:* `${{ github.repository }}`" 80 | - type: mrkdwn 81 | text: "*Input Tag:* `${{ inputs.tag }}`" 82 | - type: mrkdwn 83 | text: "*Full Tag:* `latest`" 84 | - type: mrkdwn 85 | text: "*Image URL:* `${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest`" 86 | - type: mrkdwn 87 | text: "*Manifest Digest:* `${{ steps.push_manifest.outputs.digest }}`" 88 | - type: context 89 | elements: 90 | - type: mrkdwn 91 | text: "Triggered by `${{ github.actor }}`. " -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | shardeum 2 | 3 | LLMNOTES* 4 | **/*/LLMNOTES* 5 | config/ -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ################################################################################### 2 | # Set the branch to build from the command line with --build-arg, for example: 3 | # $ docker build --build-arg VALIDATOR_BRANCH=itn4 . 4 | ################################################################################### 5 | 6 | ARG VALIDATOR_BRANCH 7 | ARG CLI_BRANCH 8 | ARG GUI_BRANCH 9 | ARG CHAIN_ID 10 | 11 | ## Network details 12 | ARG APP_MONITOR 13 | ARG RPC_SERVER_URL 14 | ARG EXISTING_ARCHIVERS 15 | ARG NEXT_PUBLIC_RPC_URL 16 | ARG NEXT_PUBLIC_EXPLORER_URL 17 | ARG SHMEXT=9001 18 | ARG SHMINT=10001 19 | ARG DASHPORT=8080 20 | ARG RUNDASHBOARD="y" 21 | ARG INT_IP="auto" 22 | ARG LOCALLANIP="auto" 23 | ARG EXT_IP="auto" 24 | ARG SERVERIP="auto" 25 | ARG NEXT_PUBLIC_CHAIN_ID 26 | 27 | ## These should not be changed often or easily without thourough testing 28 | ## 6 Gigabytes of memory for the node process for the validator to deal with the large amount of data it has to be able to handle 29 | ARG NODE_OPTIONS="--max-old-space-size=6144" 30 | ARG minNodes 31 | ARG baselineNodes 32 | ARG nodesPerConsensusGroup 33 | ARG maxNodes 34 | 35 | ## Define what Docker Node version image to use for the build & final image 36 | ARG NODE_VERSION=18.19.1 37 | 38 | ################################################################################### 39 | ### Build the Shardeum Validator image from https://github.com/shardeum/shardeum 40 | ################################################################################### 41 | FROM node:${NODE_VERSION} AS validator 42 | 43 | ARG VALIDATOR_BRANCH 44 | ARG CLI_BRANCH 45 | ARG GUI_BRANCH 46 | ARG APP_MONITOR 47 | ARG RPC_SERVER_URL 48 | ARG EXISTING_ARCHIVERS 49 | ARG NEXT_PUBLIC_RPC_URL 50 | ARG NEXT_PUBLIC_EXPLORER_URL 51 | ARG SHMEXT 52 | ARG SHMINT 53 | ARG DASHPORT 54 | ARG RUNDASHBOARD 55 | ARG INT_IP 56 | ARG EXT_IP 57 | ARG LOCALLANIP 58 | ARG SERVERIP 59 | ARG NODE_OPTIONS 60 | ARG NEXT_PUBLIC_CHAIN_ID 61 | ARG CHAIN_ID 62 | ARG LOAD_JSON_CONFIGS 63 | ARG LOAD_JSON_GENESIS_SECURE_ACCOUNTS 64 | ARG LOAD_JSON_MULTISIG_PERMISSION 65 | ARG LOAD_JSON_GENESIS 66 | 67 | ## Inherit the ARGs from the to level and expose them in the final image 68 | ENV APP_MONITOR=$APP_MONITOR 69 | ENV RPC_SERVER_URL=$RPC_SERVER_URL 70 | ENV EXISTING_ARCHIVERS=$EXISTING_ARCHIVERS 71 | ENV NEXT_PUBLIC_RPC_URL=$NEXT_PUBLIC_RPC_URL 72 | ENV NEXT_PUBLIC_EXPLORER_URL=$NEXT_PUBLIC_EXPLORER_URL 73 | ENV SHMEXT=$SHMEXT 74 | ENV SHMINT=$SHMINT 75 | ENV DASHPORT=$DASHPORT 76 | ENV RUNDASHBOARD=$RUNDASHBOARD 77 | ENV INT_IP=$INT_IP 78 | ENV EXT_IP=$EXT_IP 79 | ENV LOCALLANIP=$LOCALLANIP 80 | ENV SERVERIP=$SERVERIP 81 | ENV NODE_OPTIONS=$NODE_OPTIONS 82 | ENV NEXT_PUBLIC_CHAIN_ID=$CHAIN_ID 83 | ENV CHAIN_ID=$CHAIN_ID 84 | ENV LOAD_JSON_CONFIGS=$LOAD_JSON_CONFIGS 85 | ENV LOAD_JSON_GENESIS_SECURE_ACCOUNTS=$LOAD_JSON_GENESIS_SECURE_ACCOUNTS 86 | ENV LOAD_JSON_MULTISIG_PERMISSION=$LOAD_JSON_MULTISIG_PERMISSION 87 | ENV LOAD_JSON_GENESIS=$LOAD_JSON_GENESIS 88 | 89 | # Install build dependencies 90 | RUN apt-get update && apt-get install -y \ 91 | build-essential curl logrotate iproute2 nano git openssl 92 | 93 | ## Create CLI and GUI target directories as root & set permissions 94 | RUN mkdir -p /usr/src/app && chown -R node:node /usr/src/app && chmod 2775 -R /usr/src/app 95 | RUN mkdir -p /home/node/app/cli && chown -R node:node /home/node/app && chmod 2775 -R /home/node/app 96 | RUN mkdir -p /home/node/app/gui && chown -R node:node /home/node/app/gui && chmod 2775 -R /home/node/app/gui 97 | 98 | ## Install Rust for the validator build 99 | USER node 100 | WORKDIR /home/node 101 | RUN curl https://sh.rustup.rs -sSf | bash -s -- -y 102 | RUN . /home/node/.cargo/env 103 | ENV PATH="/home/node/.cargo/bin:${PATH}" 104 | RUN rustup install 1.74.1 && rustup default 1.74.1 105 | ENV NPM_CONFIG_loglevel=error 106 | 107 | WORKDIR /usr/src/app 108 | ENV VALIDATOR_BRANCH=${VALIDATOR_BRANCH} 109 | RUN git clone https://github.com/shardeum/shardeum.git . && \ 110 | git checkout ${VALIDATOR_BRANCH} 111 | RUN npm ci 112 | RUN npm run compile 113 | 114 | 115 | ################################################################################### 116 | ### Build the CLI image from https://github.com/shardeum/validator-cli 117 | ################################################################################### 118 | FROM node:${NODE_VERSION} AS cli 119 | 120 | ARG VALIDATOR_BRANCH 121 | ARG CLI_BRANCH 122 | ARG GUI_BRANCH 123 | ARG APP_MONITOR 124 | ARG RPC_SERVER_URL 125 | ARG EXISTING_ARCHIVERS 126 | ARG NEXT_PUBLIC_RPC_URL 127 | ARG NEXT_PUBLIC_EXPLORER_URL 128 | ARG SHMEXT 129 | ARG SHMINT 130 | ARG DASHPORT 131 | ARG RUNDASHBOARD 132 | ARG INT_IP 133 | ARG EXT_IP 134 | ARG LOCALLANIP 135 | ARG SERVERIP 136 | ARG NODE_OPTIONS 137 | ARG NEXT_PUBLIC_CHAIN_ID 138 | ARG CHAIN_ID 139 | 140 | ## Inherit the ARGs from the to level and expose them in the final image 141 | ENV APP_MONITOR=$APP_MONITOR 142 | ENV RPC_SERVER_URL=$RPC_SERVER_URL 143 | ENV EXISTING_ARCHIVERS=$EXISTING_ARCHIVERS 144 | ENV NEXT_PUBLIC_RPC_URL=$NEXT_PUBLIC_RPC_URL 145 | ENV NEXT_PUBLIC_EXPLORER_URL=$NEXT_PUBLIC_EXPLORER_URL 146 | ENV SHMEXT=$SHMEXT 147 | ENV SHMINT=$SHMINT 148 | ENV DASHPORT=$DASHPORT 149 | ENV RUNDASHBOARD=$RUNDASHBOARD 150 | ENV INT_IP=$INT_IP 151 | ENV EXT_IP=$EXT_IP 152 | ENV LOCALLANIP=$LOCALLANIP 153 | ENV SERVERIP=$SERVERIP 154 | ENV NODE_OPTIONS=$NODE_OPTIONS 155 | ENV NPM_CONFIG_loglevel=error 156 | ENV NEXT_PUBLIC_CHAIN_ID=$CHAIN_ID 157 | ENV CHAIN_ID=$CHAIN_ID 158 | 159 | # Install build dependencies 160 | RUN apt-get update && apt-get install -y \ 161 | build-essential curl iproute2 git 162 | 163 | ## Create CLI and GUI target directories as root & set permissions 164 | RUN mkdir -p /usr/src/app && chown -R node:node /usr/src/app && chmod 2775 -R /usr/src/app 165 | RUN mkdir -p /home/node/app/cli && chown -R node:node /home/node/app && chmod 2775 -R /home/node/app 166 | RUN mkdir -p /home/node/app/gui && chown -R node:node /home/node/app/gui && chmod 2775 -R /home/node/app/gui 167 | USER node 168 | WORKDIR /home/node/app 169 | ENV CLI_BRANCH=${CLI_BRANCH} 170 | RUN git clone https://github.com/shardeum/validator-cli.git cli && cd cli && \ 171 | git checkout ${CLI_BRANCH} 172 | WORKDIR /home/node/app/cli 173 | RUN npm ci 174 | RUN npm run compile 175 | 176 | 177 | ################################################################################### 178 | ### Build the GUI image from https://github.com/shardeum/validator-gui 179 | ################################################################################### 180 | FROM node:${NODE_VERSION} AS gui 181 | 182 | ARG VALIDATOR_BRANCH 183 | ARG CLI_BRANCH 184 | ARG GUI_BRANCH 185 | ARG APP_MONITOR 186 | ARG RPC_SERVER_URL 187 | ARG EXISTING_ARCHIVERS 188 | ARG NEXT_PUBLIC_RPC_URL 189 | ARG NEXT_PUBLIC_EXPLORER_URL 190 | ARG SHMEXT 191 | ARG SHMINT 192 | ARG DASHPORT 193 | ARG RUNDASHBOARD 194 | ARG INT_IP 195 | ARG EXT_IP 196 | ARG LOCALLANIP 197 | ARG SERVERIP 198 | ARG NODE_OPTIONS 199 | ARG NEXT_PUBLIC_CHAIN_ID 200 | ARG CHAIN_ID 201 | 202 | ## Inherit the ARGs from the to level and expose them in the final image 203 | ENV APP_MONITOR=$APP_MONITOR 204 | ENV RPC_SERVER_URL=$RPC_SERVER_URL 205 | ENV EXISTING_ARCHIVERS=$EXISTING_ARCHIVERS 206 | ENV NEXT_PUBLIC_RPC_URL=$NEXT_PUBLIC_RPC_URL 207 | ENV NEXT_PUBLIC_EXPLORER_URL=$NEXT_PUBLIC_EXPLORER_URL 208 | ENV SHMEXT=$SHMEXT 209 | ENV SHMINT=$SHMINT 210 | ENV DASHPORT=$DASHPORT 211 | ENV RUNDASHBOARD=$RUNDASHBOARD 212 | ENV INT_IP=$INT_IP 213 | ENV EXT_IP=$EXT_IP 214 | ENV LOCALLANIP=$LOCALLANIP 215 | ENV SERVERIP=$SERVERIP 216 | ENV NODE_OPTIONS=$NODE_OPTIONS 217 | ENV NPM_CONFIG_loglevel=error 218 | ENV NEXT_PUBLIC_CHAIN_ID=$CHAIN_ID 219 | ENV CHAIN_ID=$CHAIN_ID 220 | 221 | # Install build dependencies 222 | RUN apt-get update && apt-get install -y \ 223 | build-essential curl iproute2 git 224 | 225 | ## Create CLI and GUI target directories as root & set permissions 226 | RUN mkdir -p /usr/src/app && chown -R node:node /usr/src/app && chmod 2775 -R /usr/src/app 227 | RUN mkdir -p /home/node/app/cli && chown -R node:node /home/node/app && chmod 2775 -R /home/node/app 228 | RUN mkdir -p /home/node/app/gui && chown -R node:node /home/node/app/gui && chmod 2775 -R /home/node/app/gui 229 | USER node 230 | WORKDIR /home/node/app 231 | ENV GUI_BRANCH=${GUI_BRANCH} 232 | RUN git clone https://github.com/shardeum/validator-gui.git gui && cd gui && \ 233 | git checkout ${GUI_BRANCH} 234 | WORKDIR /home/node/app/gui 235 | RUN npm ci 236 | RUN npm run build 237 | 238 | 239 | ################################################################################### 240 | ### Build the final image 241 | ################################################################################### 242 | # FROM node:${NODE_VERSION}-slim AS final 243 | FROM node:${NODE_VERSION}-slim AS final 244 | 245 | # Link this Dockerfile to the image in the GHCR 246 | LABEL "org.opencontainers.image.source"="https://github.com/shardeum/shardeum-validator" 247 | LABEL "org.opencontainers.image.description"="Shardeum Validator" 248 | 249 | ARG APP_MONITOR 250 | ARG RPC_SERVER_URL 251 | ARG EXISTING_ARCHIVERS 252 | ARG NEXT_PUBLIC_RPC_URL 253 | ARG NEXT_PUBLIC_EXPLORER_URL 254 | ARG SHMEXT 255 | ARG SHMINT 256 | ARG DASHPORT 257 | ARG RUNDASHBOARD 258 | ARG INT_IP 259 | ARG EXT_IP 260 | ARG LOCALLANIP 261 | ARG SERVERIP 262 | ARG NODE_OPTIONS 263 | ARG minNodes 264 | ARG baselineNodes 265 | ARG nodesPerConsensusGroup 266 | ARG maxNodes 267 | ARG NEXT_PUBLIC_CHAIN_ID 268 | ARG CHAIN_ID 269 | ARG LOAD_JSON_CONFIGS 270 | ARG LOAD_JSON_GENESIS_SECURE_ACCOUNTS 271 | ARG LOAD_JSON_MULTISIG_PERMISSION 272 | ARG LOAD_JSON_GENESIS 273 | 274 | ## Inherit the ARGs from the to level and expose them in the final image 275 | ENV APP_MONITOR=$APP_MONITOR 276 | ENV RPC_SERVER_URL=$RPC_SERVER_URL 277 | ENV EXISTING_ARCHIVERS=$EXISTING_ARCHIVERS 278 | ENV NEXT_PUBLIC_RPC_URL=$NEXT_PUBLIC_RPC_URL 279 | ENV NEXT_PUBLIC_EXPLORER_URL=$NEXT_PUBLIC_EXPLORER_URL 280 | ENV SHMEXT=$SHMEXT 281 | ENV SHMINT=$SHMINT 282 | ENV DASHPORT=$DASHPORT 283 | ENV RUNDASHBOARD=$RUNDASHBOARD 284 | ENV INT_IP=$INT_IP 285 | ENV EXT_IP=$EXT_IP 286 | ENV LOCALLANIP=$LOCALLANIP 287 | ENV SERVERIP=$SERVERIP 288 | ENV NODE_OPTIONS=$NODE_OPTIONS 289 | ENV minNodes=$minNodes 290 | ENV baselineNodes=$baselineNodes 291 | ENV nodesPerConsensusGroup=$nodesPerConsensusGroup 292 | ENV maxNodes=$maxNodes 293 | ENV NEXT_PUBLIC_CHAIN_ID=$CHAIN_ID 294 | ENV CHAIN_ID=$CHAIN_ID 295 | ENV LOAD_JSON_CONFIGS=$LOAD_JSON_CONFIGS 296 | ENV LOAD_JSON_GENESIS_SECURE_ACCOUNTS=$LOAD_JSON_GENESIS_SECURE_ACCOUNTS 297 | ENV LOAD_JSON_MULTISIG_PERMISSION=$LOAD_JSON_MULTISIG_PERMISSION 298 | ENV LOAD_JSON_GENESIS=$LOAD_JSON_GENESIS 299 | 300 | RUN apt-get update 301 | RUN apt-get install -y logrotate iproute2 nano git openssl curl procps && \ 302 | apt-get clean && \ 303 | rm -rf /var/lib/apt/lists/* 304 | 305 | RUN mkdir -p /home/node/app /home/node/config /usr/src/app && \ 306 | chown -R node:node /home/node/app /home/node/config /usr/src/app && \ 307 | chmod 2777 -R /home/node/app /home/node/config /usr/src/app 308 | 309 | ## Shardeum Validator 310 | # Copy all necessary files from the validator stage 311 | COPY --from=validator --chown=node:node /usr/src/app/src/config ./config 312 | COPY --from=validator --chown=node:node /usr/src/app/environments /usr/src/app/environments 313 | COPY --from=validator --chown=node:node /usr/src/app/dist /usr/src/app/dist 314 | COPY --from=validator --chown=node:node /usr/src/app/node_modules /usr/src/app/node_modules 315 | COPY --from=validator --chown=node:node /usr/src/app/config.json /usr/src/app/config.json 316 | COPY --from=validator --chown=node:node /usr/src/app/package.json /usr/src/app/package.json 317 | COPY --from=validator --chown=node:node /usr/src/app/package-lock.json /usr/src/app/package-lock.json 318 | ### CLI 319 | COPY --from=cli --chown=node:node /home/node/app/cli /home/node/app/cli 320 | ## GUI 321 | COPY --from=gui --chown=node:node /home/node/app/gui /home/node/app/gui 322 | ## Misc scripts 323 | COPY --chown=node:node entrypoint.sh /home/node/app/ 324 | COPY --chown=node:node scripts/*.sh /home/node/app/ 325 | 326 | ## Map the GUIs certificates to the config directory, these will be broken links until the first time entry.sh is run & they'e auto-generated 327 | RUN cd /home/node/app/gui && \ 328 | ln -s /home/node/config/CA.cnf && \ 329 | ln -s /home/node/config/CA_cert.pem && \ 330 | ln -s /home/node/config/CA_cert.srl && \ 331 | ln -s /home/node/config/CA_key.pem && \ 332 | ln -s /home/node/config/selfsigned.cnf && \ 333 | ln -s /home/node/config/selfsigned.csr && \ 334 | ln -s /home/node/config/selfsigned.key && \ 335 | ln -s /home/node/config/selfsigned_node.crt && \ 336 | ln -s /home/node/config/selfsigned.crt 337 | 338 | ## Map the CLI's cli-secrets.json from the config directory 339 | RUN cd /home/node/app/cli/build/ && \ 340 | touch /home/node/config/cli-secrets.json && \ 341 | chown node:node /home/node/config/cli-secrets.json && \ 342 | ln -s /home/node/config/cli-secrets.json secrets.json 343 | 344 | RUN cd /home/node/app/cli && npm link 345 | RUN ln -s /usr/src/app /home/node/app/validator 346 | 347 | ## Install PM2 globally 348 | RUN npm install -g pm2 349 | 350 | RUN echo '/home/node/.pm2/logs/*.log /home/node/app/cli/build/logs/*.log {\n\ 351 | daily\n\ 352 | rotate 7\n\ 353 | compress\n\ 354 | delaycompress\n\ 355 | missingok\n\ 356 | notifempty\n\ 357 | create 0640 user group\n\ 358 | sharedscripts\n\ 359 | postrotate\n\ 360 | pm2 reloadLogs\n\ 361 | endscript\n\ 362 | }' > /etc/logrotate.d/pm2 363 | 364 | ## Link the env file to the various app directories so they're automatically loaded by the apps 365 | RUN ln -s /home/node/env /home/node/app/cli/build/.env 366 | RUN ln -s /home/node/env /home/node/app/cli/.env 367 | RUN ln -s /home/node/env /home/node/app/gui/build/.env 368 | RUN ln -s /home/node/env /home/node/app/gui/.env 369 | RUN ln -s /home/node/env /usr/src/app/dist/src/.env 370 | RUN ln -s /home/node/env /usr/src/app/.env 371 | 372 | USER node 373 | WORKDIR /home/node/app 374 | CMD [ "./entrypoint.sh" ] 375 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Shardeum Validator 2 | The validator which allows you to participate in the Shardeum network and earn SHM 3 | 4 | To run the Shardeum Validator you'll need to have Docker installed on your machine. You can find instructions on how to install Docker [here](https://docs.docker.com/get-docker/). Then run the following command to start the validator: 5 | 6 | ```bash 7 | docker pull ghcr.io/shardeum/shardeum-validator 8 | docker run \ 9 | --name shardeum-validator \ 10 | -p 8080:8080 \ 11 | -p 9001:9001 \ 12 | -p 10001:10001 \ 13 | -v $(pwd)/shardeum:/home/node/config \ 14 | --restart=always \ 15 | --detach \ 16 | ghcr.io/shardeum/shardeum-validator 17 | ``` 18 | 19 | This will start the validator with the default ports, 8080 for the dashboard GUI, and 9001 and 10001 for the validator P2P ports. The validator will store its data in the `~/shardeum` directory on your machine. You can change this to any directory you like by changing the `-v` argument. 20 | 21 | You can set the password for the dashboard GUI using the set-password.sh script in the ~/shardeum folder: 22 | ```bash 23 | cd ~/shardeum 24 | ./set-password.sh 25 | ``` 26 | 27 | 28 | ## Important 29 | You'll have to open the ports used on your firewall to allow incoming connections to the validator and/or redirect these ports to your machine on your home router. 30 | 31 | # Configuring ports and other settings 32 | 33 | You can change the ports the validator uses by setting the following environment variables & adjusting your docker run command accordingly ,this example would change the ports to 10080 for the dashboard GUI, and use 11001, 12002 for the validator P2P ports: 34 | 35 | ```bash 36 | docker run \ 37 | --name validator-dashboard \ 38 | -p 10080:10080 \ 39 | -p 11001:11001 \ 40 | -p 12002:12002 \ 41 | -e SHMINT=11001 \ 42 | -e SHMEXT=12002 \ 43 | -e DASHPORT=10080 \ 44 | -v $(pwd)/shardeum-2:/home/node/config \ 45 | --restart=always \ 46 | --detach \ 47 | ghcr.io/shardeum/shardeum-validator 48 | ``` 49 | 50 | ### Important 51 | If you run this as root, create and `chown 1000:1000 shardeum-2` the folder specified before running as the node user in the docker process needs to be able to write to it. 52 | If you dont have permissions to change the owner, change the permissions instead: `chmod -R 777 shardeum-2` 53 | 54 | 55 | These are the environment variables used by the validator: 56 | 57 | ```bash 58 | APP_MONITOR RPC_SERVER_URL EXISTING_ARCHIVERS NEXT_PUBLIC_RPC_URL NEXT_PUBLIC_EXPLORER_URL INT_IP SHMINT SHMEXT DASHPORT RUNDASHBOARD EXT_IP SERVERIP LOCALLANIP NEXT_PUBLIC_CHAIN_ID 59 | ``` 60 | 61 | So you could, for example, run the validator without starting the dashboard by specifying `-e RUNDASHBOARD=n` in the docker run command. 62 | 63 | # Chain ID 64 | 65 | To build the image for the test net use `-e NEXT_PUBLIC_CHAIN_ID=8083` for main net use `-e NEXT_PUBLIC_CHAIN_ID=8118` 66 | 67 | # Running the validator on other networks 68 | 69 | You can override the network configs the image was build with by setting the following environment variables: 70 | 71 | ```bash 72 | docker run \ 73 | --name shardeum-validator \ 74 | -p 8080:8080 \ 75 | -p 9001:9001 \ 76 | -p 10001:10001 \ 77 | -v $(pwd)/shardeum:/home/node/config \ 78 | -e RPC_SERVER_URL='http://localhost:123' \ 79 | -e APP_MONITOR='http://localhost:456' \ 80 | -e EXISTING_ARCHIVERS='[{"ip":"127.0.0.1","port":4000,"publicKey":"somekeygoeshere"}]' \ 81 | -e EXT_IP='192.168.0.1' \ 82 | ghcr.io/shardeum/shardeum-validator 83 | ``` 84 | 85 | ## Running on other platforms 86 | The end user experience is kept as closely to the old installer as possible, The command looks similar but does has a different url. Make sure to use this new one: 87 | 88 | curl -O https://raw.githubusercontent.com/shardeum/shardeum-validator/refs/heads/dev/install.sh && chmod +x install.sh && ./install.sh 89 | 90 | Because the new build system is fully Docker based, the install.sh script is really only there to make it easier to enter ports and other preferences, however it's just as effective to run it directly as docker command, ie: 91 | 92 | ``` 93 | docker pull ghcr.io/shardeum/shardeum-validator 94 | docker run \ 95 | --name shardeum-validator \ 96 | -p 8080:8080 \ 97 | -p 9001:9001 \ 98 | -p 10001:10001 \ 99 | -v $(pwd)/shardeum:/home/node/config \ 100 | --restart=always \ 101 | --detach \ 102 | ghcr.io/shardeum/shardeum-validator:latest 103 | docker exec -it shardeum-validator operator-cli gui set password "YOUR_NEW_PASSWORD" 104 | ``` 105 | 106 | This same command will work on Windows, Mac and Linux on both X86_64 and ARM64 platforms. 107 | 108 | There's additional info on how to specify different ports and other settings, that can all be controlled through ENV vars, in the shardeum-validator README: 109 | https://github.com/shardeum/shardeum-validator?tab=readme-ov-file#shardeum-validator 110 | 111 | ## Changing Validator, CLI and GUI branches to build 112 | 113 | 114 | The build script parses which branches to build through env variables, update these to the correct branch for the network: 115 | https://github.com/shardeum/shardeum-validator/blob/dev/build.sh 116 | 117 | The example in `build.sh` will build the `mainnet-launch` branch of the validator, validator CLI and GUI: 118 | 119 | ``` 120 | ./build.sh custom-my-tag 121 | ``` 122 | 123 | ## Changing network settings 124 | 125 | 126 | The defaults used by the build are specified in the `scripts/build-network.sh`, this includes the archivers, explorer, rpc and monitor. You can customize these in a custom build using `build.sh`. Make sure to update the default environment variables before building: 127 | https://github.com/shardeum/shardeum-validator/blob/dev/build.sh 128 | 129 | ``` 130 | # Required Environment Variables (values here are from testnet) 131 | CHAIN_ID=8083 132 | NEXT_PUBLIC_CHAIN_ID=${CHAIN_ID} 133 | APP_MONITOR="34.56.47.170" 134 | RPC_SERVER_URL="https://api-testnet.shardeum.org" 135 | EXISTING_ARCHIVERS='[{"ip":"104.197.117.164","port":4000,"publicKey":"d831bb7c09db45d47338af23ab50cac5d29ef8f3a2cd274dd741370aa472d6c1"},{"ip":"34.139.3.222","port":4000,"publicKey":"1c42a7f9cca36e13e590ae00c1124c5a1f696c879da210ffcdccb312d08c8214"},{"ip":"35.233.192.167","port":4000,"publicKey":"d1721c924394ae1ff3e9ea22af15962e045511fde05ed0b56f0a8c36eb161d75"}]' 136 | NEXT_PUBLIC_RPC_URL="https://api-testnet.shardeum.org" 137 | NEXT_PUBLIC_EXPLORER_URL="https://explorer-testnet.shardeum.org" 138 | minNodes=256 139 | baselineNodes=256 140 | nodesPerConsensusGroup=128 141 | maxNodes=1280 142 | enableProblematicNodeRemoval=true 143 | enableProblematicNodeRemovalOnCycle=0 144 | flexibleRotationDelta=4 145 | VALIDATOR_BRANCH=mainnet-launch 146 | CLI_BRANCH=mainnet-launch 147 | GUI_BRANCH=mainnet-launch 148 | ``` 149 | 150 | ## Building 151 | 152 | For each build that is to be published use a new tag, currently I'm using itn4-{build number} ie itn-7, this will result in an image that can be pulled with docker pull ghcr.io/shardeum/shardeum-validator:itn4-7 153 | 154 | Each build has to be done on both an x86_64 and arm64 linux platform. Docker desktop for mac and windows add an extra layer to the image that makes it unusable in the next step of publishing a manifest for both architectures 155 | 156 | On both build systems run the following commands to build and publish the new version. The build script will auto-detect wether its an amd64 or arm64 system so this doesn't have to be specified: 157 | https://github.com/shardeum/shardeum-validator/blob/dev/build.sh 158 | ``` 159 | gh repo clone shardeum/shardeum-validator 160 | cd shardeum-validator 161 | ./build.sh itn4-10 162 | ``` 163 | If the build completes successfully it will push the image to the github container registry, ghcr.io. If you are not authenticated to the ghcr you can do so by running (replacing USERNAME with your github username, and TOKEN with a personal access token that has all the required permissions to publish packages): 164 | ``` 165 | echo "TOKEN" | docker login ghcr.io -u USERNAME --password-stdin 166 | ``` 167 | Once the builds have completed & pushed the builds to ghcr.io on both the amd64 and arm64 systems, the next step is to create a manifest 168 | 169 | The manifest is where the separate platform images, ie ghcr.io/shardeum/shardeum-validator-arm64:itn4-10 and ghcr.io/shardeum/shardeum-validator-amd:itn4-10 are combined into one image where docker will automatically pull the correct OS/ARCH version for the platform it's run on. See https://github.com/shardeum/shardeum-validator/pkgs/container/shardeum-validator for the manifest listings. This manifest based image name is used by the installer, which uses the :latest version by default 170 | 171 | Creating the manifests and tagging it and the images as :latest is a bunch of commands, so you can use the tag.sh script to perform all these actions for you 172 | https://github.com/shardeum/shardeum-validator/blob/dev/tag.sh 173 | ``` 174 | ./tag.sh itn4-10 175 | ``` 176 | 177 | Run this on a system where you are authenticated to ghcr.io, however it does not have to be one of the build systems it'll download the amd64 and arm64 images for you 178 | 179 | Once it's completed the latest build is available in https://github.com/shardeum/shardeum-validator/pkgs/container/shardeum-validator tagged as :latest and can be pulled with 180 | ``` 181 | docker pull ghcr.io/shardeum/shardeum-validator:latest 182 | ``` 183 | 184 | 185 | ### Github Actions building 186 | 187 | The github actions builds using `build-network.sh`. It can be configured ONLY for `testnet`, `stagenet`, and `mainnet`. If you want to make a custom network build you can use `build.sh` with your own environment variables. You can see them all enumerated in `build-network.sh`. 188 | 189 | #### Tagging Structure 190 | 191 | ``` 192 | ghcr.io/shardeum/shardeum-validator:{environment}-{your tag} 193 | ``` 194 | 195 | expanded: 196 | ``` 197 | ghcr.io/shardeum/shardeum-validator:mainnet-{your tag} 198 | ghcr.io/shardeum/shardeum-validator-amd64:mainnet-{your tag} 199 | ghcr.io/shardeum/shardeum-validator-arm64:mainnet-{your tag} 200 | 201 | ghcr.io/shardeum/shardeum-validator:stagenet-{your tag} 202 | ghcr.io/shardeum/shardeum-validator-amd64:stagenet-{your tag} 203 | ghcr.io/shardeum/shardeum-validator-arm64:stagenet-{your tag} 204 | 205 | ghcr.io/shardeum/shardeum-validator:testnet-{your tag} 206 | ghcr.io/shardeum/shardeum-validator-amd64:testnet-{your tag} 207 | ghcr.io/shardeum/shardeum-validator-arm64:testnet-{your tag} 208 | ``` 209 | 210 | ![image](https://github.com/user-attachments/assets/6804c453-f16e-46bd-b3f7-afdecbbd51e2) 211 | 212 | 213 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting a Vulnerability 4 | 5 | If you believe you’ve found a security vulnerability in this project, we strongly encourage responsible disclosure and will work with you to resolve the issue promptly. 6 | 7 | Please **do not** create a public issue or discuss the vulnerability in public forums. 8 | 9 | ### 🔒 Preferred Methods of Disclosure 10 | 11 | You have two options to report security issues: 12 | 13 | 1. **Private Disclosure via GitHub (Recommended)** 14 | 15 | - Use the **"Report a vulnerability"** button in the GitHub repository's **/security/advisories** page. 16 | - This will privately notify the maintainers through GitHub’s security advisory workflow. 17 | 18 | 2. **Email** 19 | - Send a detailed report to: **security at shardeum dot org** 20 | 21 | ### What to Include 22 | 23 | To help us understand and resolve the issue quickly, please include (where possible): 24 | 25 | - A detailed description of the vulnerability 26 | - Steps to reproduce it 27 | - Any relevant proof-of-concept code 28 | - The potential impact or affected components 29 | 30 | ### What to Expect 31 | 32 | - We will acknowledge your report within **3 business days**. 33 | - We will investigate and confirm the issue. 34 | - If a fix is needed, we’ll prepare a patch and may issue a **GitHub Security Advisory** (and CVE if applicable). 35 | - We’ll keep you informed throughout the process and credit you if appropriate. 36 | 37 | We appreciate your efforts in keeping our project and its users safe. 38 | 39 | ### Responsible Disclosure Guidelines 40 | 41 | When conducting security research and reporting vulnerabilities, we request that you: 42 | 43 | - Make every effort to avoid privacy violations, degradation of user experience, disruption to production systems, and destruction or manipulation of data. 44 | - Only interact with accounts or data that you own or have explicit permission to access. 45 | - Limit the amount of data you access or download to the minimum necessary to demonstrate the vulnerability. 46 | - Do not use a vulnerability to gain persistent access to systems or exfiltrate sensitive information. 47 | - Report the vulnerability to us as soon as you discover it. 48 | - Allow us a reasonable timeframe to investigate, fix, and announce the vulnerability before making it public. 49 | 50 | ## Supported Versions 51 | 52 | We only provide security updates for the **latest stable release**. Make sure you're up-to-date. 53 | 54 | ### 🛡️ Safe Harbor 55 | 56 | We consider security research conducted in accordance with this policy to be authorized. If you make a good faith effort to discover and report vulnerabilities by following these guidelines, we will not initiate legal action against you or ask law enforcement to investigate you. If any third party initiates legal action against you related to research conducted under this policy, we will make it known that your actions were authorized by us. 57 | 58 | --- 59 | 60 | Thank you for helping improve the security of this project! 61 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Required Environment Variables (values here are from testnet) 4 | CHAIN_ID=8083 5 | NEXT_PUBLIC_CHAIN_ID=${CHAIN_ID} 6 | APP_MONITOR="34.56.47.170" 7 | RPC_SERVER_URL="https://api-testnet.shardeum.org" 8 | EXISTING_ARCHIVERS='[{"ip":"104.197.117.164","port":4000,"publicKey":"d831bb7c09db45d47338af23ab50cac5d29ef8f3a2cd274dd741370aa472d6c1"},{"ip":"34.139.3.222","port":4000,"publicKey":"1c42a7f9cca36e13e590ae00c1124c5a1f696c879da210ffcdccb312d08c8214"},{"ip":"35.233.192.167","port":4000,"publicKey":"d1721c924394ae1ff3e9ea22af15962e045511fde05ed0b56f0a8c36eb161d75"}]' 9 | NEXT_PUBLIC_RPC_URL="https://api-testnet.shardeum.org" 10 | NEXT_PUBLIC_EXPLORER_URL="https://explorer-testnet.shardeum.org" 11 | minNodes=256 12 | baselineNodes=256 13 | nodesPerConsensusGroup=128 14 | maxNodes=1280 15 | enableProblematicNodeRemoval=true 16 | enableProblematicNodeRemovalOnCycle=0 17 | flexibleRotationDelta=4 18 | VALIDATOR_BRANCH=mainnet-launch 19 | CLI_BRANCH=mainnet-launch 20 | GUI_BRANCH=mainnet-launch 21 | 22 | if [ -z "$1" ]; then 23 | echo "No tag provided. Exiting." 24 | exit 1 25 | fi 26 | TAG=$1 27 | 28 | # Determine the architecture 29 | ARCH=$(uname -m) 30 | if [ "$ARCH" == "aarch64" ]; then 31 | ARCH_TAG="arm64" 32 | elif [ "$ARCH" == "arm64" ]; then 33 | ARCH_TAG="arm64" 34 | elif [ "$ARCH" == "x86_64" ]; then 35 | ARCH_TAG="amd64" 36 | else 37 | echo "Unsupported architecture: $ARCH. Exiting." 38 | exit 1 39 | fi 40 | 41 | # Check for required environment variables 42 | required_vars=( 43 | VALIDATOR_BRANCH 44 | CLI_BRANCH 45 | GUI_BRANCH 46 | CHAIN_ID 47 | NEXT_PUBLIC_CHAIN_ID 48 | APP_MONITOR 49 | RPC_SERVER_URL 50 | EXISTING_ARCHIVERS 51 | NEXT_PUBLIC_RPC_URL 52 | NEXT_PUBLIC_EXPLORER_URL 53 | minNodes 54 | baselineNodes 55 | nodesPerConsensusGroup 56 | maxNodes 57 | enableProblematicNodeRemoval 58 | enableProblematicNodeRemovalOnCycle 59 | flexibleRotationDelta 60 | ) 61 | 62 | missing_vars=() 63 | for var in "${required_vars[@]}"; do 64 | if [ -z "${!var}" ]; then 65 | missing_vars+=("$var") 66 | fi 67 | done 68 | 69 | if [ ${#missing_vars[@]} -gt 0 ]; then 70 | echo "ERROR: Missing required environment variables:" 71 | printf '%s\n' "${missing_vars[@]}" 72 | exit 1 73 | fi 74 | 75 | # Build and tag the image 76 | docker build . \ 77 | --push \ 78 | --no-cache \ 79 | --build-arg VALIDATOR_BRANCH=${VALIDATOR_BRANCH} \ 80 | --build-arg CLI_BRANCH=${CLI_BRANCH} \ 81 | --build-arg GUI_BRANCH=${GUI_BRANCH} \ 82 | --build-arg CHAIN_ID="${CHAIN_ID}" \ 83 | --build-arg NEXT_PUBLIC_CHAIN_ID="${NEXT_PUBLIC_CHAIN_ID}" \ 84 | --build-arg APP_MONITOR="${APP_MONITOR}" \ 85 | --build-arg RPC_SERVER_URL="${RPC_SERVER_URL}" \ 86 | --build-arg EXISTING_ARCHIVERS="${EXISTING_ARCHIVERS}" \ 87 | --build-arg NEXT_PUBLIC_RPC_URL="${NEXT_PUBLIC_RPC_URL}" \ 88 | --build-arg NEXT_PUBLIC_EXPLORER_URL="${NEXT_PUBLIC_EXPLORER_URL}" \ 89 | --build-arg minNodes="${minNodes}" \ 90 | --build-arg baselineNodes="${baselineNodes}" \ 91 | --build-arg nodesPerConsensusGroup="${nodesPerConsensusGroup}" \ 92 | --build-arg maxNodes="${maxNodes}" \ 93 | --build-arg enableProblematicNodeRemoval="${enableProblematicNodeRemoval}" \ 94 | --build-arg enableProblematicNodeRemovalOnCycle="${enableProblematicNodeRemovalOnCycle}" \ 95 | --build-arg flexibleRotationDelta="${flexibleRotationDelta}" \ 96 | -t ghcr.io/shardeum/shardeum-validator-${ARCH_TAG}:${TAG} 97 | 98 | echo "Build complete: ghcr.io/shardeum/shardeum-validator-${ARCH_TAG}:${TAG}" 99 | -------------------------------------------------------------------------------- /cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | docker stop shardeum-validator 3 | docker rm shardeum-validator 4 | ## TODO reenable this on release 5 | #rm -rf shardeum 6 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ## Pick up existing environment variables if already set 4 | if [ -f /home/node/env ]; then 5 | echo "Loading existing env" 6 | . /home/node/env 7 | echo "New env:" 8 | export 9 | fi 10 | 11 | get_net_ip() { 12 | local ip 13 | if command -v ip >/dev/null; then 14 | ip=$(ip addr show $(ip route | awk '/default/ {print $5}') | awk '/inet/ {print $2}' | cut -d/ -f1 | head -n1) 15 | elif command -v netstat >/dev/null; then 16 | # Get the default route interface 17 | interface=$(netstat -rn | awk '/default/{print $4}' | head -n1) 18 | # Get the IP address for the default interface 19 | ip=$(ifconfig "$interface" | awk '/inet /{print $2}') 20 | else 21 | echo "Error: neither 'ip' nor 'ifconfig' command found. Submit a bug for your OS." 22 | return 1 23 | fi 24 | echo -n $ip 25 | } 26 | 27 | 28 | get_external_ip() { 29 | external_ip='' 30 | external_ip=$(curl -s https://api.ipify.org) 31 | if [[ -z "$external_ip" ]]; then 32 | external_ip=$(curl -s http://checkip.dyndns.org | grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b") 33 | fi 34 | if [[ -z "$external_ip" ]]; then 35 | external_ip=$(curl -s http://ipecho.net/plain) 36 | fi 37 | if [[ -z "$external_ip" ]]; then 38 | external_ip=$(curl -s https://icanhazip.com/) 39 | fi 40 | if [[ -z "$external_ip" ]]; then 41 | external_ip=$(curl --header "Host: icanhazip.com" -s 104.18.114.97) 42 | fi 43 | if [[ -z "$external_ip" ]]; then 44 | external_ip=$(get_net_ip) 45 | if [ $? -eq 0 ]; then 46 | echo -n "$IP" 47 | else 48 | external_ip="localhost" 49 | fi 50 | fi 51 | echo $external_ip 52 | } 53 | 54 | 55 | ## Autodetect the external IP address if none is provided or set to "auto", which is the Dockerfile default 56 | if [ -z "$EXT_IP" ] || [ "$EXT_IP" = "auto" ]; then 57 | EXT_IP=$(get_external_ip) 58 | fi 59 | SERVERIP=$EXT_IP 60 | 61 | if [ -z "$INT_IP" ] || [ "$INT_IP" = "auto" ]; then 62 | INT_IP=$EXT_IP 63 | fi 64 | LOCALLANIP=$INT_IP 65 | 66 | 67 | ## If the env file does not exist, create it so they're loaded automatically next time the container is started 68 | if [ ! -f /home/node/env ]; then 69 | echo "Creating env file" 70 | cat >/home/node/env < CA.cnf 110 | 111 | openssl req -nodes -new -x509 -keyout CA_key.pem -out CA_cert.pem -days 1825 -config CA.cnf > /dev/null 112 | 113 | echo "[ req ] 114 | default_bits = 4096 115 | distinguished_name = req_distinguished_name 116 | req_extensions = req_ext 117 | x509_extensions = v3_req 118 | prompt = no 119 | 120 | [req_distinguished_name] 121 | countryName = XX 122 | stateOrProvinceName = Localzone 123 | localityName = Localhost 124 | organizationName = Shardeum Atomium 1.x Validator Cert. 125 | commonName = localhost 126 | 127 | [req_ext] 128 | subjectAltName = @alt_names 129 | 130 | [v3_req] 131 | subjectAltName = @alt_names 132 | 133 | [alt_names] 134 | IP.1 = $SERVERIP 135 | IP.2 = $LOCALLANIP 136 | DNS.1 = localhost" > selfsigned.cnf 137 | 138 | openssl req -sha256 -nodes -newkey rsa:4096 -keyout selfsigned.key -out selfsigned.csr -config selfsigned.cnf > /dev/null 139 | 140 | openssl x509 -req -days 398 -in selfsigned.csr -CA CA_cert.pem -CAkey CA_key.pem -CAcreateserial -out selfsigned_node.crt -extensions req_ext -extfile selfsigned.cnf > /dev/null 141 | 142 | cat selfsigned_node.crt CA_cert.pem > selfsigned.crt 143 | fi 144 | 145 | 146 | ## Start the GUI if enabled 147 | if [ "$RUNDASHBOARD" = "y" ]; then 148 | echo "Starting validator GUI" 149 | operator-cli gui set port $DASHPORT 150 | operator-cli gui start 151 | fi 152 | 153 | ## Keep the container running 154 | cd /home/node/app 155 | pm2 logs 156 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Check if a tag was specified as a command-line argument 4 | TAG=${1:-latest} 5 | echo "Using Docker image tag: $TAG" 6 | 7 | read -p "By participating in the network your node can be selected at random for a duration to validate transactions, and earn SHM by doing so. 8 | 9 | If your node is too slow to validate, it risks being removed from the active list reducing or entirely eliminating earnings, 10 | so we recommend making sure your VPS meets the minimum specifications and runs on a reliable hosting company. 11 | 12 | Do you agree (Y/n)?:" WARNING_AGREE 13 | 14 | set -e 15 | USE_SUDO=0 16 | 17 | # Echo user's response, or indicate if no response was provided 18 | if [ -z "$WARNING_AGREE" ]; then 19 | echo "No response provided." 20 | echo "Defaulting to y" 21 | WARNING_AGREE=y 22 | else 23 | echo "You entered: $WARNING_AGREE" 24 | fi 25 | 26 | WARNING_AGREE=$(echo "$WARNING_AGREE" | tr '[:upper:]' '[:lower:]') 27 | 28 | if [ $WARNING_AGREE != "y" ]; 29 | then 30 | echo "Node performance agreement not accepted. Exiting installer." 31 | exit 32 | fi 33 | 34 | echo "If you are upgrading from a previous version, please specify the directory where it was installed." 35 | read -p "What base directory should the node use (default ~/shardeum): " input 36 | 37 | # Set default value if input is empty 38 | input=${input:-~/shardeum} 39 | 40 | # Reprompt if not alphanumeric characters, tilde, forward slash, underscore, period, hyphen, or contains spaces 41 | while [[ ! $input =~ ^[[:alnum:]_.~/-]+$ || $input =~ [[:space:]] ]]; do 42 | echo "Error: The directory name contains invalid characters or spaces." 43 | echo "Allowed characters are alphanumeric characters, tilde (~), forward slash (/), underscore (_), period (.), and hyphen (-)." 44 | read -p "Please enter a valid base directory (default ~/shardeum): " input 45 | # Set default if input is empty 46 | input=${input:-~/shardeum} 47 | done 48 | 49 | # Echo the final directory used (with ~ if present) 50 | echo "The base directory is set to: $input" 51 | 52 | # Expand the tilde (~) using a subshell 53 | expanded_input=$(bash -c "echo $input") 54 | 55 | # Create the directory if it doesn't exist 56 | mkdir -p "$expanded_input" 57 | 58 | # Get the real (absolute) path of the directory 59 | NODEHOME=$(realpath "$expanded_input") 60 | 61 | # Check if realpath was successful 62 | if [[ $? -ne 0 ]]; then 63 | echo "Error: Unable to resolve the real path for '$expanded_input'." 64 | exit 1 65 | fi 66 | 67 | echo "Real path for directory is: $NODEHOME" 68 | 69 | command -v docker >/dev/null 2>&1 || { echo >&2 "Docker is not installed on this machine but is required to run the shardeum validator. Please install docker before continuing."; exit 1; } 70 | 71 | docker-safe() { 72 | if ! command -v docker &>/dev/null; then 73 | echo "docker is not installed on this machine" 74 | exit 1 75 | fi 76 | 77 | if ! docker "$@"; then 78 | echo "Trying again with sudo..." >&2 79 | USE_SUDO=1 80 | sudo docker "$@" 81 | fi 82 | } 83 | 84 | if [[ $(docker-safe info 2>&1) == *"Cannot connect to the Docker daemon"* ]]; then 85 | echo "Docker daemon is not running, please staert the Docker daemon and try again" 86 | exit 1 87 | else 88 | echo "Docker daemon is running" 89 | fi 90 | 91 | DASHPORT_DEFAULT=8080 92 | EXTERNALIP_DEFAULT=auto 93 | INTERNALIP_DEFAULT=auto 94 | SHMEXT_DEFAULT=9001 95 | SHMINT_DEFAULT=10001 96 | 97 | read -p "Do you want to run the web based Dashboard? (Y/n): " RUNDASHBOARD 98 | RUNDASHBOARD=$(echo "$RUNDASHBOARD" | tr '[:upper:]' '[:lower:]') 99 | RUNDASHBOARD=${RUNDASHBOARD:-y} 100 | 101 | echo # New line after inputs. 102 | 103 | while :; do 104 | read -p "Enter the port (1025-65536) to access the web based Dashboard (default $DASHPORT_DEFAULT): " DASHPORT 105 | DASHPORT=${DASHPORT:-$DASHPORT_DEFAULT} 106 | [[ $DASHPORT =~ ^[0-9]+$ ]] || { echo "Enter a valid port"; continue; } 107 | if ((DASHPORT >= 1025 && DASHPORT <= 65536)); then 108 | DASHPORT=${DASHPORT:-$DASHPORT_DEFAULT} 109 | break 110 | else 111 | echo "Port out of range, try again" 112 | fi 113 | done 114 | 115 | while :; do 116 | read -p "If you wish to set an explicit external IP, enter an IPv4 address (default=$EXTERNALIP_DEFAULT): " EXTERNALIP 117 | EXTERNALIP=${EXTERNALIP:-$EXTERNALIP_DEFAULT} 118 | 119 | if [ "$EXTERNALIP" == "auto" ]; then 120 | break 121 | fi 122 | # Use regex to check if the input is a valid IPv4 address 123 | if [[ $EXTERNALIP =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then 124 | # Check that each number in the IP address is between 0-255 125 | valid_ip=true 126 | IFS='.' read -ra ip_nums <<< "$EXTERNALIP" 127 | for num in "${ip_nums[@]}" 128 | do 129 | if (( num < 0 || num > 255 )); then 130 | valid_ip=false 131 | fi 132 | done 133 | if [ $valid_ip == true ]; then 134 | break 135 | else 136 | echo "Invalid IPv4 address. Please try again." 137 | fi 138 | else 139 | echo "Invalid IPv4 address. Please try again." 140 | fi 141 | done 142 | 143 | while :; do 144 | read -p "If you wish to set an explicit internal IP, enter an IPv4 address (default=$INTERNALIP_DEFAULT): " INTERNALIP 145 | INTERNALIP=${INTERNALIP:-$INTERNALIP_DEFAULT} 146 | if [ "$INTERNALIP" == "auto" ]; then 147 | break 148 | fi 149 | # Use regex to check if the input is a valid IPv4 address 150 | if [[ $INTERNALIP =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then 151 | # Check that each number in the IP address is between 0-255 152 | valid_ip=true 153 | IFS='.' read -ra ip_nums <<< "$INTERNALIP" 154 | for num in "${ip_nums[@]}" 155 | do 156 | if (( num < 0 || num > 255 )); then 157 | valid_ip=false 158 | fi 159 | done 160 | if [ $valid_ip == true ]; then 161 | break 162 | else 163 | echo "Invalid IPv4 address. Please try again." 164 | fi 165 | else 166 | echo "Invalid IPv4 address. Please try again." 167 | fi 168 | done 169 | 170 | 171 | get_net_ip() { 172 | local ip 173 | if command -v ip >/dev/null; then 174 | ip=$(ip addr show $(ip route | awk '/default/ {print $5}') | awk '/inet/ {print $2}' | cut -d/ -f1 | head -n1) 175 | elif command -v netstat >/dev/null; then 176 | # Get the default route interface 177 | interface=$(netstat -rn | awk '/default/{print $4}' | head -n1) 178 | # Get the IP address for the default interface 179 | ip=$(ifconfig "$interface" | awk '/inet /{print $2}') 180 | else 181 | echo "Error: neither 'ip' nor 'ifconfig' command found. Submit a bug for your OS." 182 | return 1 183 | fi 184 | echo -n $ip 185 | } 186 | 187 | get_external_ip() { 188 | external_ip='' 189 | external_ip=$(curl -s https://api.ipify.org) 190 | if [[ -z "$external_ip" ]]; then 191 | external_ip=$(curl -s http://checkip.dyndns.org | grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b") 192 | fi 193 | if [[ -z "$external_ip" ]]; then 194 | external_ip=$(curl -s http://ipecho.net/plain) 195 | fi 196 | if [[ -z "$external_ip" ]]; then 197 | external_ip=$(curl -s https://icanhazip.com/) 198 | fi 199 | if [[ -z "$external_ip" ]]; then 200 | external_ip=$(curl --header "Host: icanhazip.com" -s 104.18.114.97) 201 | fi 202 | if [[ -z "$external_ip" ]]; then 203 | external_ip=$(get_net_ip) 204 | if [ $? -eq 0 ]; then 205 | echo -n "$IP" 206 | else 207 | external_ip="localhost" 208 | fi 209 | fi 210 | echo $external_ip 211 | } 212 | 213 | if [ -z "$EXTERNALIP" ] || [ "$EXTERNALIP" = "auto" ]; then 214 | EXTERNALIP=$(get_external_ip) 215 | fi 216 | EXT_IP=$EXTERNALIP 217 | SERVERIP=$EXT_IP 218 | 219 | if [ -z "$INTERNALIP" ] || [ "$INTERNALIP" = "auto" ]; then 220 | INTERNALIP=$EXT_IP 221 | fi 222 | INT_IP=$INTERNALIP 223 | LOCALLANIP=$INTERNALIP 224 | 225 | 226 | while :; do 227 | echo "To run a validator on the Shardeum network, you will need to open two ports in your firewall." 228 | read -p "This allows p2p communication between nodes. Enter the first port (1025-65536) for p2p communication (default $SHMEXT_DEFAULT): " SHMEXT 229 | SHMEXT=${SHMEXT:-$SHMEXT_DEFAULT} 230 | [[ $SHMEXT =~ ^[0-9]+$ ]] || { echo "Enter a valid port"; continue; } 231 | if ((SHMEXT >= 1025 && SHMEXT <= 65536)); then 232 | SHMEXT=${SHMEXT:-9001} 233 | else 234 | echo "Port out of range, try again" 235 | fi 236 | read -p "Enter the second port (1025-65536) for p2p communication (default $SHMINT_DEFAULT): " SHMINT 237 | SHMINT=${SHMINT:-$SHMINT_DEFAULT} 238 | [[ $SHMINT =~ ^[0-9]+$ ]] || { echo "Enter a valid port"; continue; } 239 | if ((SHMINT >= 1025 && SHMINT <= 65536)); then 240 | SHMINT=${SHMINT:-10001} 241 | break 242 | else 243 | echo "Port out of range, try again" 244 | fi 245 | done 246 | 247 | 248 | 249 | # Find all container IDs (running or stopped) that use the pre-ITN4 installer image 250 | OLD_IMAGE="ghcr.io/shardeum/server:latest" 251 | CONTAINER_IDS=$(docker-safe ps -aq --filter "ancestor=$OLD_IMAGE") 252 | if [ -z "$CONTAINER_IDS" ]; then 253 | echo "No deprecated containers found. Proceeding with the installation." 254 | else 255 | set +e 256 | echo "Stopping and removing the following containers: $CONTAINER_IDS" 257 | # Stop all matching containers 258 | docker-safe stop $CONTAINER_IDS 1>/dev/null 259 | # Remove all matching containers 260 | docker-safe rm $CONTAINER_IDS 1>/dev/null 261 | echo "Containers have been stopped and removed successfully." 262 | set -e 263 | fi 264 | 265 | ## Stop and remove any previous instance of the shardeum-validator if it exists 266 | if docker-safe ps -a --filter "name=shardeum-validator" --format "{{.Names}}" | grep -q "^shardeum-validator$"; then 267 | echo "Stopping and removing previous instance of shardeum-validator" 268 | docker-safe stop shardeum-validator 2>/dev/null 269 | docker-safe rm shardeum-validator 2>/dev/null 270 | fi 271 | 272 | ## Ensure that the node user can write to the $NODEHOME directory inside of the container, to do so the directory must be owned by UID 1000 273 | set +e 274 | mkdir -p ${NODEHOME} 275 | 276 | # Get the owner UID of the directory 277 | OWNER_UID=$(stat -c '%u' "$NODEHOME") 278 | # UID of the node user in the docker image 279 | TARGET_UID=1000 280 | 281 | # Check if the owner UID is not the target UID 282 | if [ "$OWNER_UID" -ne "$TARGET_UID" ]; then 283 | echo "Changing ownership of $NODEHOME to UID $TARGET_UID..." 284 | # Attempt to change ownership 285 | if chown "$TARGET_UID" "$NODEHOME"; then 286 | echo "Ownership of $NODEHOME changed successfully." 287 | else 288 | echo "Failed to change ownership. Retrying with sudo..." 289 | if sudo chown "$TARGET_UID" "$NODEHOME"; then 290 | echo "Ownership of $NODEHOME changed successfully with sudo." 291 | else 292 | echo "Failed to change ownership of $NODEHOME even with sudo." 293 | exit 1 294 | fi 295 | fi 296 | else 297 | echo "Ownership of $NODEHOME is already UID $TARGET_UID. No changes needed." 298 | fi 299 | set -e 300 | 301 | echo "Downloading the shardeum-validator image and starting the validator container" 302 | 303 | ## Pull the latest image and run the validator 304 | docker-safe pull ghcr.io/shardeum/shardeum-validator:${TAG} 305 | 306 | IMAGE_DIGEST=$(docker-safe inspect --format='{{index .RepoDigests 0}}' "ghcr.io/shardeum/shardeum-validator:${TAG}" | cut -d'@' -f2) 307 | 308 | if [ -z "$IMAGE_DIGEST" ]; then 309 | echo "Failed to retrieve image digest. Exiting." 310 | exit 1 311 | fi 312 | 313 | echo "Image digest: $IMAGE_DIGEST" 314 | docker-safe run \ 315 | --name shardeum-validator \ 316 | -p ${DASHPORT}:${DASHPORT} \ 317 | -p ${SHMEXT}:${SHMEXT} \ 318 | -p ${SHMINT}:${SHMINT} \ 319 | -e RUNDASHBOARD=${RUNDASHBOARD} \ 320 | -e DASHPORT=${DASHPORT} \ 321 | -e EXT_IP=${EXTERNALIP} \ 322 | -e INT_IP=${INTERNALIP} \ 323 | -e SERVERIP=${SERVERIP} \ 324 | -e LOCALLANIP=${LOCALLANIP} \ 325 | -e SHMEXT=${SHMEXT} \ 326 | -e SHMINT=${SHMINT} \ 327 | -e IMAGE_DIGEST="$IMAGE_DIGEST" \ 328 | -e IMAGE_NAME="shardeum/shardeum-validator" \ 329 | -v ${NODEHOME}:/home/node/config \ 330 | --restart=always \ 331 | --detach \ 332 | ghcr.io/shardeum/shardeum-validator:${TAG} 1>/dev/null 333 | 334 | echo "Shardeum Validator starting." 335 | echo "Waiting for the container to be available (max 60 seconds).." 336 | 337 | timeout=60 338 | elapsed=0 339 | 340 | while [ ! -f "${NODEHOME}/set-password.sh" ]; do 341 | sleep 1 342 | elapsed=$((elapsed + 1)) 343 | if [ "$elapsed" -ge "$timeout" ]; then 344 | echo "Timeout: set-password.sh not found after 60 seconds." 345 | exit 1 346 | fi 347 | done 348 | 349 | echo "Enter a new password for the validator dashboard" 350 | "${NODEHOME}/set-password.sh" 351 | 352 | echo "Shardeum Validator is now running. You can access the dashboard at https://${EXT_IP}:${DASHPORT}/" 353 | echo "If you're running the validator on your local system you can access the dashboard at https://localhost:${DASHPORT}/ instead" 354 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ -z "$1" ]; then 3 | echo "No tag provided. Exiting." 4 | exit 1 5 | fi 6 | TAG=$1 7 | 8 | # Determine the architecture 9 | ARCH=$(uname -m) 10 | if [ "$ARCH" == "aarch64" ]; then 11 | ARCH_TAG="arm64" 12 | elif [ "$ARCH" == "arm64" ]; then 13 | ARCH_TAG="arm64" 14 | elif [ "$ARCH" == "x86_64" ]; then 15 | ARCH_TAG="amd64" 16 | else 17 | echo "Unsupported architecture: $ARCH. Exiting." 18 | exit 1 19 | fi 20 | 21 | IMAGE_NAME="shardeum/shardeum-validator-${ARCH_TAG}" 22 | IMAGE_REF="ghcr.io/${IMAGE_NAME}:${TAG}" 23 | 24 | # Ensure the image exists locally 25 | if ! docker image inspect "$IMAGE_REF" > /dev/null 2>&1; then 26 | echo "Image $IMAGE_REF not found locally. Please pull or build it first. Exiting." 27 | exit 1 28 | fi 29 | 30 | # Get the image digest from local metadata 31 | IMAGE_DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' "$IMAGE_REF" | cut -d'@' -f2) 32 | 33 | if [ -z "$IMAGE_DIGEST" ]; then 34 | echo "Failed to retrieve image digest. Exiting." 35 | exit 1 36 | fi 37 | 38 | echo "Using image: $IMAGE_REF" 39 | echo "Image digest: $IMAGE_DIGEST" 40 | 41 | # Stop and remove any previous instance 42 | if docker ps --filter "name=shardeum-validator" --format "{{.Names}}" | grep -q "^shardeum-validator$"; then 43 | echo "Stopping and removing previous instance of shardeum-validator" 44 | docker stop shardeum-validator 2>/dev/null 45 | docker rm shardeum-validator 2>/dev/null 46 | fi 47 | 48 | docker run \ 49 | --name shardeum-validator \ 50 | -p 8080:8080/tcp \ 51 | -p 9001:9001/tcp \ 52 | -p 10001:10001/tcp \ 53 | -v $(pwd)/shardeum:/home/node/config \ 54 | -e IMAGE_DIGEST="$IMAGE_DIGEST" \ 55 | -e IMAGE_NAME="$IMAGE_NAME" \ 56 | --restart=always \ 57 | --detach \ 58 | "$IMAGE_REF" 59 | -------------------------------------------------------------------------------- /scan-vuln.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "$1" ]; then 4 | echo "No tag provided. Exiting." 5 | exit 1 6 | fi 7 | TAG=$1 8 | 9 | ARCH=$(uname -m) 10 | if [ "$ARCH" == "aarch64" ]; then 11 | ARCH_TAG="arm64" 12 | elif [ "$ARCH" == "arm64" ]; then 13 | ARCH_TAG="arm64" 14 | elif [ "$ARCH" == "x86_64" ]; then 15 | ARCH_TAG="amd64" 16 | else 17 | echo "Unsupported architecture: $ARCH. Exiting." 18 | exit 1 19 | fi 20 | 21 | trivy image ghcr.io/shardeum/shardeum-validator-${ARCH_TAG}:${TAG} --pkg-types os --ignore-unfixed --severity HIGH,CRITICAL --scanners vuln --timeout 60m0s --format table --output trivy-high-and-critical.txt 22 | 23 | -------------------------------------------------------------------------------- /scripts/build-network.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | # Check if network name, tag, arch_tag, and registry are provided 6 | if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ] || [ -z "$4" ]; then 7 | echo "Usage: $0 " 8 | echo "Example: $0 testnet v1.0.0 amd64 ghcr.io" 9 | exit 1 10 | fi 11 | 12 | NETWORK_NAME=$1 13 | TAG=$2 14 | ARCH_TAG=$3 15 | REGISTRY=$4 # Use the fourth argument as the registry 16 | CONFIG_FILE="scripts/configs/${NETWORK_NAME}.sh" 17 | 18 | # Check if config file exists 19 | if [ ! -f "$CONFIG_FILE" ]; then 20 | echo "Error: Configuration file not found: $CONFIG_FILE" 21 | exit 1 22 | fi 23 | 24 | echo "Sourcing configuration from $CONFIG_FILE for network ${NETWORK_NAME}..." 25 | # Source the configuration file to load variables into the current shell 26 | # Use set -a to automatically export sourced variables if needed by subsequent processes 27 | set -a 28 | source "$CONFIG_FILE" 29 | set +a 30 | 31 | # Define image name using registry argument 32 | IMAGE_NAME="${REGISTRY}/shardeum/shardeum-validator-${ARCH_TAG}:${NETWORK_NAME}-${TAG}" 33 | 34 | echo "Building image: ${IMAGE_NAME} for network ${NETWORK_NAME}" 35 | 36 | echo "CHAIN_ID=${CHAIN_ID}" 37 | echo "NEXT_PUBLIC_CHAIN_ID=${NEXT_PUBLIC_CHAIN_ID}" 38 | echo "LOAD_JSON_CONFIGS=${LOAD_JSON_CONFIGS}" 39 | echo "LOAD_JSON_GENESIS_SECURE_ACCOUNTS=${LOAD_JSON_GENESIS_SECURE_ACCOUNTS}" 40 | echo "LOAD_JSON_MULTISIG_PERMISSION=${LOAD_JSON_MULTISIG_PERMISSION}" 41 | echo "LOAD_JSON_GENESIS=${LOAD_JSON_GENESIS}" 42 | 43 | # Execute the build command directly substituting shell variables 44 | docker build . \ 45 | --no-cache \ 46 | --build-arg NETWORK="${NETWORK_NAME}" \ 47 | --build-arg VALIDATOR_BRANCH="${VALIDATOR_BRANCH}" \ 48 | --build-arg CLI_BRANCH="${CLI_BRANCH}" \ 49 | --build-arg GUI_BRANCH="${GUI_BRANCH}" \ 50 | --build-arg CHAIN_ID="${CHAIN_ID}" \ 51 | --build-arg NEXT_PUBLIC_CHAIN_ID="${NEXT_PUBLIC_CHAIN_ID}" \ 52 | --build-arg APP_MONITOR="${APP_MONITOR}" \ 53 | --build-arg RPC_SERVER_URL="${RPC_SERVER_URL}" \ 54 | --build-arg EXISTING_ARCHIVERS="${EXISTING_ARCHIVERS}" \ 55 | --build-arg NEXT_PUBLIC_RPC_URL="${NEXT_PUBLIC_RPC_URL}" \ 56 | --build-arg NEXT_PUBLIC_EXPLORER_URL="${NEXT_PUBLIC_EXPLORER_URL}" \ 57 | --build-arg LOAD_JSON_CONFIGS="${LOAD_JSON_CONFIGS}" \ 58 | --build-arg LOAD_JSON_GENESIS_SECURE_ACCOUNTS="${LOAD_JSON_GENESIS_SECURE_ACCOUNTS}" \ 59 | --build-arg LOAD_JSON_MULTISIG_PERMISSION="${LOAD_JSON_MULTISIG_PERMISSION}" \ 60 | --build-arg LOAD_JSON_GENESIS="${LOAD_JSON_GENESIS}" \ 61 | -t "${IMAGE_NAME}" 62 | 63 | echo "Docker build completed for ${IMAGE_NAME}" -------------------------------------------------------------------------------- /scripts/configs/mainnet.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Branch Configuration 4 | export VALIDATOR_BRANCH="mainnet-launch" 5 | export CLI_BRANCH="mainnet-launch" 6 | export GUI_BRANCH="mainnet-launch" 7 | 8 | # Network details 9 | export CHAIN_ID="8118" 10 | export NEXT_PUBLIC_CHAIN_ID=$CHAIN_ID 11 | 12 | ## External Service Configuration 13 | export APP_MONITOR="104.154.117.74" 14 | export RPC_SERVER_URL="https://api.shardeum.org" 15 | export EXISTING_ARCHIVERS='[{"ip":"35.238.248.68","port":4000,"publicKey":"e25aa3465e43ecdee2cceddc381d137a4fa4c174144144683e0ea2a42a3801ff"},{"ip":"34.23.94.188","port":4000,"publicKey":"4a6c6ddc9cedb2f4b0ae90a9fd36e705abf572ba971585b429329408bfdfb20e"},{"ip":"34.145.9.44","port":4000,"publicKey":"5278029906ac9b0ae79b96364ef3c7aaa09abd4a36397f0bd5ca7faedd4c575c"}]' 16 | export NEXT_PUBLIC_RPC_URL="https://api.shardeum.org" 17 | export NEXT_PUBLIC_EXPLORER_URL="https://explorer.shardeum.org" 18 | 19 | export LOAD_JSON_CONFIGS=/usr/src/app/environments/mainnet.config.json 20 | export LOAD_JSON_GENESIS_SECURE_ACCOUNTS=/config/mainnet.genesis-secure-accounts.json 21 | export LOAD_JSON_MULTISIG_PERMISSION=/config/mainnet.multisig-permissions.json 22 | export LOAD_JSON_GENESIS=/config/mainnet.genesis.json 23 | -------------------------------------------------------------------------------- /scripts/configs/stagenet.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Branch Configuration 4 | export VALIDATOR_BRANCH="mainnet-launch" 5 | export CLI_BRANCH="mainnet-launch" 6 | export GUI_BRANCH="mainnet-launch" 7 | 8 | # Network details 9 | export CHAIN_ID="8081" 10 | export NEXT_PUBLIC_CHAIN_ID=$CHAIN_ID 11 | 12 | # External Service Configuration 13 | export APP_MONITOR="34.16.2.42" 14 | export RPC_SERVER_URL="https://api-stagenet.shardeum.org" 15 | export EXISTING_ARCHIVERS='[{"ip":"34.57.177.170","port":4000,"publicKey":"d831bb7c09db45d47338af23ab50cac5d29ef8f3a2cd274dd741370aa472d6c1"},{"ip":"34.73.104.156","port":4000,"publicKey":"37d162292c068030bbde55ee8ac777ad08f443b9bba0b0064e4919345d43727a"},{"ip":"35.230.76.119","port":4000,"publicKey":"d8475a2d2110becb2d031085a2915956239dafcafd2d57f5468a187bb7235dd7"}]' 16 | export NEXT_PUBLIC_RPC_URL="https://api-stagenet.shardeum.org" 17 | export NEXT_PUBLIC_EXPLORER_URL="https://explorer-stagenet.shardeum.org" 18 | 19 | export LOAD_JSON_CONFIGS=/usr/src/app/environments/stagenet.config.json 20 | export LOAD_JSON_GENESIS_SECURE_ACCOUNTS=/config/stagenet.genesis-secure-accounts.json 21 | export LOAD_JSON_MULTISIG_PERMISSION=/config/stagenet.multisig-permissions.json 22 | export LOAD_JSON_GENESIS=/config/stagenet.genesis.json 23 | -------------------------------------------------------------------------------- /scripts/configs/testnet.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Branch Configuration 4 | export VALIDATOR_BRANCH="mainnet-launch" 5 | export CLI_BRANCH="mainnet-launch" 6 | export GUI_BRANCH="mainnet-launch" 7 | 8 | # Network details 9 | export CHAIN_ID="8083" 10 | export NEXT_PUBLIC_CHAIN_ID=$CHAIN_ID 11 | 12 | # External Service Configuration 13 | export APP_MONITOR="34.56.47.170" 14 | export RPC_SERVER_URL="https://api-testnet.shardeum.org" 15 | export EXISTING_ARCHIVERS='[{"ip":"104.197.117.164","port":4000,"publicKey":"d831bb7c09db45d47338af23ab50cac5d29ef8f3a2cd274dd741370aa472d6c1"},{"ip":"34.139.3.222","port":4000,"publicKey":"1c42a7f9cca36e13e590ae00c1124c5a1f696c879da210ffcdccb312d08c8214"},{"ip":"35.233.192.167","port":4000,"publicKey":"d1721c924394ae1ff3e9ea22af15962e045511fde05ed0b56f0a8c36eb161d75"}]' 16 | export NEXT_PUBLIC_RPC_URL="https://api-testnet.shardeum.org" 17 | export NEXT_PUBLIC_EXPLORER_URL="https://explorer-testnet.shardeum.org" 18 | 19 | export LOAD_JSON_CONFIGS=/usr/src/app/environments/testnet.config.json 20 | export LOAD_JSON_GENESIS_SECURE_ACCOUNTS=/config/testnet.genesis-secure-accounts.json 21 | export LOAD_JSON_MULTISIG_PERMISSION=/config/testnet.multisig-permissions.json 22 | export LOAD_JSON_GENESIS=/config/testnet.genesis.json 23 | -------------------------------------------------------------------------------- /scripts/operator-cli.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | docker-safe() { 4 | if ! command -v docker &>/dev/null; then 5 | echo "docker is not installed on this machine" 6 | exit 1 7 | fi 8 | 9 | if ! docker $@; then 10 | echo "Trying again with sudo..." 11 | sudo docker $@ 12 | fi 13 | } 14 | 15 | docker-safe exec -it shardeum-validator operator-cli $@ -------------------------------------------------------------------------------- /scripts/set-password.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | echo 4 | 5 | docker-safe() { 6 | if ! command -v docker &>/dev/null; then 7 | echo "docker is not installed on this machine" 8 | exit 1 9 | fi 10 | 11 | if ! docker $@; then 12 | echo "Trying again with sudo..." 13 | sudo docker $@ 14 | fi 15 | } 16 | 17 | read_password() { 18 | # Clear input buffer to avoid processing leftover inputs 19 | stty -icanon min 0 time 0 # Set non-canonical mode temporarily 20 | while read -r -t 0; do read -r; done # Flush buffer 21 | stty sane # Restore terminal to normal mode 22 | 23 | local CHARCOUNT=0 24 | local PASSWORD="" 25 | while IFS= read -p "$PROMPT" -r -s -n 1 CHAR; do 26 | # Enter - accept password 27 | if [[ $CHAR == $'\0' ]]; then 28 | break 29 | fi 30 | # Backspace 31 | if [[ $CHAR == $'\177' ]]; then 32 | if [ $CHARCOUNT -gt 0 ]; then 33 | CHARCOUNT=$((CHARCOUNT - 1)) 34 | PROMPT=$'\b \b' 35 | PASSWORD="${PASSWORD%?}" 36 | else 37 | PROMPT='' 38 | fi 39 | else 40 | CHARCOUNT=$((CHARCOUNT + 1)) 41 | PROMPT='*' 42 | PASSWORD+="$CHAR" 43 | fi 44 | done 45 | echo $PASSWORD 46 | } 47 | 48 | check_password() { 49 | local PASSWORD=$1 50 | local ERRORS="" 51 | 52 | if [[ ${#PASSWORD} -lt 8 ]]; then 53 | ERRORS+="Password must be at least 8 characters long.\n" 54 | fi 55 | 56 | if ! [[ "$PASSWORD" =~ [a-z] ]]; then 57 | ERRORS+="Password must contain at least one lowercase letter.\n" 58 | fi 59 | 60 | if ! [[ "$PASSWORD" =~ [A-Z] ]]; then 61 | ERRORS+="Password must contain at least one uppercase letter.\n" 62 | fi 63 | 64 | if ! [[ "$PASSWORD" =~ [0-9] ]]; then 65 | ERRORS+="Password must contain at least one number.\n" 66 | fi 67 | 68 | # Corrected special character check: 69 | if ! [[ "$PASSWORD" =~ [!@#$%^\&*()_+] ]]; then 70 | ERRORS+="Password must contain at least one special character (!@#$%^&*()_+$).\n" 71 | fi 72 | 73 | if [[ -n "$ERRORS" ]]; then 74 | echo -e "\nInvalid password. Please correct the following:\n$ERRORS" 75 | return 1 76 | else 77 | return 0 78 | fi 79 | } 80 | 81 | echo "Password requirements: " 82 | echo -e "min 8 characters, at least 1 lower case letter, at least 1 upper case letter, at least 1 number, at least 1 special character !@#$%^&*()_+$ \n" 83 | 84 | while true; do 85 | echo -n "Enter the password for accessing the Dashboard: " 86 | DASHPASS=$(read_password) 87 | 88 | if [ -z "$DASHPASS" ]; then 89 | echo "Password cannot be empty" 90 | continue 91 | fi 92 | echo 93 | if check_password "$DASHPASS"; then 94 | break 95 | fi 96 | done 97 | 98 | docker-safe exec -it shardeum-validator operator-cli gui set password "$DASHPASS" 99 | 100 | echo 101 | echo -------------------------------------------------------------------------------- /scripts/shell.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | docker-safe() { 4 | if ! command -v docker &>/dev/null; then 5 | echo "docker is not installed on this machine" 6 | exit 1 7 | fi 8 | 9 | if ! docker $@; then 10 | echo "Trying again with sudo..." 11 | sudo docker $@ 12 | fi 13 | } 14 | 15 | docker-safe exec -it shardeum-validator /bin/bash -------------------------------------------------------------------------------- /scripts/upgrade.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | CONTAINER_NAME="shardeum-validator" 4 | IMAGE="ghcr.io/shardeum/shardeum-validator:latest" 5 | 6 | docker-safe() { 7 | if ! command -v docker &>/dev/null; then 8 | echo "docker is not installed on this machine" 9 | exit 1 10 | fi 11 | 12 | if ! docker $@; then 13 | echo "Trying again with sudo..." 14 | sudo docker $@ 15 | fi 16 | } 17 | 18 | # Step 1: Check if the container is running 19 | CONTAINER_ID=$(docker-safe ps -q --filter "name=$CONTAINER_NAME") 20 | if [ -z "$CONTAINER_ID" ]; then 21 | echo "No running container found with name: $CONTAINER_NAME" 22 | exit 1 23 | fi 24 | 25 | # Step 2: Extract current configuration 26 | echo "Extracting current configuration from $CONTAINER_NAME..." 27 | PORTS=$(docker inspect "$CONTAINER_ID" --format '{{range $p, $conf := .HostConfig.PortBindings}}-p {{$p}} {{end}}' | xargs -n1 | paste -sd' ' -) 28 | ENV_VARS=$(docker inspect "$CONTAINER_ID" --format '{{range .Config.Env}}-e {{.}} {{end}}') 29 | VOLUMES=$(docker inspect "$CONTAINER_ID" --format '{{range .Mounts}}-v {{.Source}}:{{.Destination}} {{end}}') 30 | 31 | # Step 3: Stop and remove the current container 32 | echo "Stopping and removing the current container..." 33 | docker-safe stop "$CONTAINER_ID" 1>/dev/null 34 | docker-safe rm "$CONTAINER_ID" 1>/dev/null 35 | 36 | # Step 4: Pull the latest image 37 | echo "Pulling the latest image: $IMAGE..." 38 | docker-safe pull "$IMAGE" 39 | 40 | # Step 5: Run the new container with the same configuration 41 | echo "Starting the new container with the same configuration..." 42 | docker-safe run \ 43 | --name "$CONTAINER_NAME" \ 44 | $PORTS \ 45 | $ENV_VARS \ 46 | $VOLUMES \ 47 | --restart=always \ 48 | --detach \ 49 | "$IMAGE" 1>/dev/null 50 | 51 | if [ $? -eq 0 ]; then 52 | echo "Upgrade successful! The new container is now running." 53 | else 54 | echo "Upgrade failed. Please check the logs and try again." 55 | exit 1 56 | fi -------------------------------------------------------------------------------- /tag.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | TAG=$1 4 | 5 | if [ -z "$TAG" ]; then 6 | echo "No tag provided. Exiting." 7 | exit 1 8 | fi 9 | 10 | echo "Pulling images" 11 | 12 | docker pull ghcr.io/shardeum/shardeum-validator-arm64:$TAG 13 | docker pull ghcr.io/shardeum/shardeum-validator-amd64:$TAG 14 | 15 | echo "Tagging latest" 16 | 17 | docker tag ghcr.io/shardeum/shardeum-validator-arm64:$TAG ghcr.io/shardeum/shardeum-validator-arm64:latest 18 | docker tag ghcr.io/shardeum/shardeum-validator-amd64:$TAG ghcr.io/shardeum/shardeum-validator-amd64:latest 19 | 20 | echo "Pushing latest" 21 | 22 | docker push ghcr.io/shardeum/shardeum-validator-arm64:latest 23 | docker push ghcr.io/shardeum/shardeum-validator-amd64:latest 24 | 25 | echo "Creating $TAG manifest" 26 | 27 | docker manifest create --amend ghcr.io/shardeum/shardeum-validator:$TAG ghcr.io/shardeum/shardeum-validator-arm64:$TAG ghcr.io/shardeum/shardeum-validator-amd64:$TAG 28 | docker manifest push ghcr.io/shardeum/shardeum-validator:$TAG 29 | 30 | echo "Creating :latest manifest" 31 | 32 | #docker manifest create --amend ghcr.io/shardeum/shardeum-validator:latest ghcr.io/shardeum/shardeum-validator-arm64:$TAG ghcr.io/shardeum/shardeum-validator-amd64:$TAG 33 | #docker manifest push ghcr.io/shardeum/shardeum-validator:latest 34 | 35 | docker pull ghcr.io/shardeum/shardeum-validator:$TAG 36 | docker tag ghcr.io/shardeum/shardeum-validator:$TAG ghcr.io/shardeum/shardeum-validator:latest 37 | docker push ghcr.io/shardeum/shardeum-validator:latest 38 | 39 | echo "Done" 40 | --------------------------------------------------------------------------------