diff --git a/.dockerignore b/.dockerignore index 5628ed5..927362b 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,3 @@ geth-data/ reth-data/ +nethermind-data/ diff --git a/.env.mainnet b/.env.mainnet index c114869..522f019 100644 --- a/.env.mainnet +++ b/.env.mainnet @@ -1,9 +1,13 @@ RETH_CHAIN=base RETH_SEQUENCER_HTTP=https://mainnet-sequencer.base.org OP_GETH_SEQUENCER_HTTP=https://mainnet-sequencer.base.org +OP_SEQUENCER_HTTP=https://mainnet-sequencer.base.org # [optional] used to enable geth stats: # OP_GETH_ETH_STATS=nodename:secret@host:port +# OP_NETHERMIND_ETHSTATS_ENABLED=true +# OP_NETHERMIND_ETHSTATS_NODE_NAME=NethermindNode +# OP_NETHERMIND_ETHSTATS_ENDPOINT=ethstats_endpoint # [required] replace with your preferred L1 (Ethereum, not Base) node RPC URL: OP_NODE_L1_ETH_RPC=https://1rpc.io/eth @@ -42,4 +46,5 @@ OP_NODE_ROLLUP_LOAD_PROTOCOL_VERSIONS=true # To enable snap sync, uncomment and set the env vars below: # OP_NODE_SYNCMODE=execution-layer # OP_GETH_BOOTNODES=enode://87a32fd13bd596b2ffca97020e31aef4ddcc1bbd4b95bb633d16c1329f654f34049ed240a36b449fda5e5225d70fe40bc667f53c304b71f8e68fc9d448690b51@3.231.138.188:30301,enode://ca21ea8f176adb2e229ce2d700830c844af0ea941a1d8152a9513b966fe525e809c3a6c73a2c18a12b74ed6ec4380edf91662778fe0b79f6a591236e49e176f9@184.72.129.189:30301,enode://acf4507a211ba7c1e52cdf4eef62cdc3c32e7c9c47998954f7ba024026f9a6b2150cd3f0b734d9c78e507ab70d59ba61dfe5c45e1078c7ad0775fb251d7735a2@3.220.145.177:30301,enode://8a5a5006159bf079d06a04e5eceab2a1ce6e0f721875b2a9c96905336219dbe14203d38f70f3754686a6324f786c2f9852d8c0dd3adac2d080f4db35efc678c5@3.231.11.52:30301,enode://cdadbe835308ad3557f9a1de8db411da1a260a98f8421d62da90e71da66e55e98aaa8e90aa7ce01b408a54e4bd2253d701218081ded3dbe5efbbc7b41d7cef79@54.198.153.150:30301 +# OP_NETHERMIND_BOOTNODES=enode://87a32fd13bd596b2ffca97020e31aef4ddcc1bbd4b95bb633d16c1329f654f34049ed240a36b449fda5e5225d70fe40bc667f53c304b71f8e68fc9d448690b51@3.231.138.188:30301,enode://ca21ea8f176adb2e229ce2d700830c844af0ea941a1d8152a9513b966fe525e809c3a6c73a2c18a12b74ed6ec4380edf91662778fe0b79f6a591236e49e176f9@184.72.129.189:30301,enode://acf4507a211ba7c1e52cdf4eef62cdc3c32e7c9c47998954f7ba024026f9a6b2150cd3f0b734d9c78e507ab70d59ba61dfe5c45e1078c7ad0775fb251d7735a2@3.220.145.177:30301,enode://8a5a5006159bf079d06a04e5eceab2a1ce6e0f721875b2a9c96905336219dbe14203d38f70f3754686a6324f786c2f9852d8c0dd3adac2d080f4db35efc678c5@3.231.11.52:30301,enode://cdadbe835308ad3557f9a1de8db411da1a260a98f8421d62da90e71da66e55e98aaa8e90aa7ce01b408a54e4bd2253d701218081ded3dbe5efbbc7b41d7cef79@54.198.153.150:30301 # OP_GETH_SYNCMODE=snap diff --git a/.env.sepolia b/.env.sepolia index 00e5351..37d0f4b 100644 --- a/.env.sepolia +++ b/.env.sepolia @@ -1,9 +1,13 @@ RETH_CHAIN=base-sepolia RETH_SEQUENCER_HTTP=https://sepolia-sequencer.base.org OP_GETH_SEQUENCER_HTTP=https://sepolia-sequencer.base.org +OP_SEQUENCER_HTTP=https://sepolia-sequencer.base.org # [optional] used to enable geth stats: # OP_GETH_ETH_STATS=nodename:secret@host:port +# OP_NETHERMIND_ETHSTATS_ENABLED=true +# OP_NETHERMIND_ETHSTATS_NODE_NAME=NethermindNode +# OP_NETHERMIND_ETHSTATS_ENDPOINT=ethstats_endpoint # [required] replace with your preferred L1 (Ethereum, not Base) node RPC URL: OP_NODE_L1_ETH_RPC=https://rpc.sepolia.org @@ -42,4 +46,5 @@ OP_NODE_ROLLUP_LOAD_PROTOCOL_VERSIONS=true # To enable snap sync, set env vars below: # OP_NODE_SYNCMODE=execution-layer # OP_GETH_BOOTNODES=enode://548f715f3fc388a7c917ba644a2f16270f1ede48a5d88a4d14ea287cc916068363f3092e39936f1a3e7885198bef0e5af951f1d7b1041ce8ba4010917777e71f@18.210.176.114:30301,enode://6f10052847a966a725c9f4adf6716f9141155b99a0fb487fea3f51498f4c2a2cb8d534e680ee678f9447db85b93ff7c74562762c3714783a7233ac448603b25f@107.21.251.55:30301 +# OP_NETHERMIND_BOOTNODES=enode://548f715f3fc388a7c917ba644a2f16270f1ede48a5d88a4d14ea287cc916068363f3092e39936f1a3e7885198bef0e5af951f1d7b1041ce8ba4010917777e71f@18.210.176.114:30301,enode://6f10052847a966a725c9f4adf6716f9141155b99a0fb487fea3f51498f4c2a2cb8d534e680ee678f9447db85b93ff7c74562762c3714783a7233ac448603b25f@107.21.251.55:30301 # OP_GETH_SYNCMODE=snap diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index d7d4bf5..28ea740 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -1,6 +1,7 @@ name: Tag Docker image on: + workflow_dispatch: push: branches: - 'main' @@ -13,6 +14,7 @@ env: GETH_DEPRECATED_IMAGE_NAME: node GETH_IMAGE_NAME: node-geth RETH_IMAGE_NAME: node-reth + NETHERMIND_IMAGE_NAME: node-nethermind jobs: geth: @@ -87,3 +89,43 @@ jobs: build-args: | FEATURES=${{ matrix.features }} platforms: ${{ matrix.arch }} + nethermind: + runs-on: ubuntu-latest + strategy: + matrix: + platform: [linux/amd64] + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Log into the Container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + with: + platforms: linux/amd64,linux/arm64 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Extract metadata for the Docker image + id: meta + uses: docker/metadata-action@v4 + with: + images: | + ${{ env.NAMESPACE }}/${{ env.NETHERMIND_IMAGE_NAME }} + + - name: Build and push the Docker image + uses: docker/build-push-action@v6 + with: + context: . + file: nethermind/Dockerfile + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + platforms: linux/amd64 diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 3b2fc9f..bc3836e 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -2,6 +2,7 @@ name: Pull Request on: pull_request: + workflow_dispatch: jobs: geth: @@ -48,3 +49,27 @@ jobs: build-args: | FEATURES=${{ matrix.features }} platforms: ${{ matrix.arch }} + nethermind: + runs-on: ubuntu-latest + strategy: + matrix: + arch: [ linux/amd64, linux/arm64 ] + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha }} + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + with: + platforms: linux/amd64,linux/arm64 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Build the Docker image + uses: docker/build-push-action@v6 + with: + context: . + file: nethermind/Dockerfile + push: false + platforms: ${{ matrix.arch }} + diff --git a/.gitignore b/.gitignore index b2f231e..27ac158 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /.idea/ /geth-data/ /reth-data/ +/nethermind-data/ .DS_Store diff --git a/README.md b/README.md index eb0d01e..1f6aff0 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,15 @@ If you encounter problems with your node, please open a [GitHub issue](https://g docker compose up --build ``` +> [!NOTE] +> To run the node using a supported client, you can use the following command: +> `CLIENT=supported_client docker compose up --build` +> +> Supported clients: +> - geth +> - reth +> - nethermind + 4. You should now be able to `curl` your Base node: ``` diff --git a/nethermind/Dockerfile b/nethermind/Dockerfile new file mode 100644 index 0000000..7277504 --- /dev/null +++ b/nethermind/Dockerfile @@ -0,0 +1,50 @@ +FROM golang:1.21 AS op + +WORKDIR /app + +ENV REPO=https://github.com/ethereum-optimism/optimism.git +ENV VERSION=v1.9.1 +ENV COMMIT=4797ddb70e05d4952685bad53e608cb5606284e6 +RUN git clone $REPO --branch op-node/$VERSION --single-branch . && \ + git switch -c branch-$VERSION && \ + bash -c '[ "$(git rev-parse HEAD)" = "$COMMIT" ]' + +RUN cd op-node && \ + make VERSION=$VERSION op-node + +FROM mcr.microsoft.com/dotnet/sdk:8.0-noble AS build + +ARG BUILD_CONFIG=release +ARG TARGETARCH + +WORKDIR /app + +ENV REPO=https://github.com/NethermindEth/nethermind.git +ENV VERSION=1.29.1 +ENV COMMIT=dfea52404006c6ce1b133b98f324dbfcb62773e1 +RUN git clone $REPO --branch $VERSION --single-branch . && \ + git switch -c $VERSION +RUN bash -c '[ "$(git rev-parse HEAD)" = "$COMMIT" ]' +RUN TARGETARCH=${TARGETARCH#linux/} && \ + arch=$([ "$TARGETARCH" = "amd64" ] && echo "x64" || echo "$TARGETARCH") && \ + echo "Using architecture: $arch" && \ + dotnet publish src/Nethermind/Nethermind.Runner -c $BUILD_CONFIG -a $arch -o /publish --sc false + + +FROM mcr.microsoft.com/dotnet/aspnet:8.0-noble + +RUN apt-get update && \ + apt-get install -y jq curl supervisor && \ + rm -rf /var/lib/apt/lists + +RUN mkdir -p /var/log/supervisor + +WORKDIR /app + +COPY --from=build /publish ./ +COPY --from=op /app/op-node/bin/op-node ./ +COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf +COPY nethermind/nethermind-entrypoint ./execution-entrypoint +COPY op-node-entrypoint . + +CMD ["/usr/bin/supervisord"] diff --git a/nethermind/nethermind-entrypoint b/nethermind/nethermind-entrypoint new file mode 100644 index 0000000..1a33768 --- /dev/null +++ b/nethermind/nethermind-entrypoint @@ -0,0 +1,63 @@ +#!/bin/bash +set -eu + +# Default configurations +NETHERMIND_DATA_DIR=${NETHERMIND_DATA_DIR:-/data} +NETHERMIND_LOG_LEVEL=${NETHERMIND_LOG_LEVEL:-Info} +NETWORK=${NETWORK:-mainnet} + +RPC_PORT="${RPC_PORT:-8545}" +WS_PORT="${WS_PORT:-8546}" +AUTHRPC_PORT="${AUTHRPC_PORT:-8551}" +METRICS_PORT="${METRICS_PORT:-6060}" +DISCOVERY_PORT="${DISCOVERY_PORT:-30303}" + +JWT_SECRET_FILE=${JWT_SECRET_FILE:-/tmp/jwt/jwtsecret} +ADDITIONAL_ARGS="" + +# Check if required variables are set +if [[ -z "$NETWORK" ]]; then + echo "Expected NETWORK to be set" 1>&2 + exit 1 +fi + +# Create necessary directories +mkdir -p "$NETHERMIND_DATA_DIR" + +# Write the JWT secret +if [[ -z "${OP_NODE_L2_ENGINE_AUTH_RAW:-}" ]]; then + echo "Expected OP_NODE_L2_ENGINE_AUTH_RAW to be set" 1>&2 + exit 1 +fi +echo "$OP_NODE_L2_ENGINE_AUTH_RAW" > "$OP_NODE_L2_ENGINE_AUTH" + +# Additional arguments based on environment variables +if [ "${OP_NETHERMIND_BOOTNODES+x}" = x ]; then + ADDITIONAL_ARGS="$ADDITIONAL_ARGS --Network.Bootnodes=$OP_NETHERMIND_BOOTNODES" +fi + +if [[ -n "${OP_NETHERMIND_ETHSTATS_ENABLED:-}" ]]; then + ADDITIONAL_ARGS="$ADDITIONAL_ARGS --EthStats.Enabled=$OP_NETHERMIND_ETHSTATS_ENABLED" +fi + +if [[ -n "${OP_NETHERMIND_ETHSTATS_ENDPOINT:-}" ]]; then + ADDITIONAL_ARGS="$ADDITIONAL_ARGS --EthStats.NodeName=${OP_NETHERMIND_ETHSTATS_NODE_NAME:-NethermindNode} --EthStats.Endpoint=$OP_NETHERMIND_ETHSTATS_ENDPOINT" +fi + +# Execute Nethermind +exec ./nethermind \ + --config="$OP_NODE_NETWORK" \ + --datadir="$NETHERMIND_DATA_DIR" \ + --Optimism.SequencerUrl=$OP_SEQUENCER_HTTP \ + --log="$NETHERMIND_LOG_LEVEL" \ + --JsonRpc.Enabled=true \ + --JsonRpc.Host=0.0.0.0 \ + --JsonRpc.WebSocketsPort="$WS_PORT" \ + --JsonRpc.Port="$RPC_PORT" \ + --JsonRpc.JwtSecretFile="$OP_NODE_L2_ENGINE_AUTH" \ + --JsonRpc.EngineHost=0.0.0.0 \ + --JsonRpc.EnginePort="$AUTHRPC_PORT" \ + --HealthChecks.Enabled=true \ + --Metrics.Enabled=true \ + --Metrics.ExposePort="$METRICS_PORT" \ + $ADDITIONAL_ARGS