Skip to content

Commit e123007

Browse files
committed
Support Nimbus Verified Proxy
1 parent bf11f6b commit e123007

9 files changed

Lines changed: 281 additions & 1 deletion

File tree

.github/workflows/build-clients.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@ jobs:
2222
test_cl: false
2323
test_el: false
2424
test_vc: false
25+
- env: |-
26+
COMPOSE_FILE=nimbus-vp.yml
27+
NIMVP_DOCKERFILE=Dockerfile.source
28+
test_cl: false
29+
test_el: false
30+
test_vc: false
2531
- env: |-
2632
COMPOSE_FILE=prysm.yml:geth.yml:mev-boost.yml
2733
MEV_DOCKERFILE=Dockerfile.source
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: Test Nimbus Verified Proxy
2+
3+
defaults:
4+
run:
5+
shell: bash
6+
7+
on:
8+
push:
9+
pull_request:
10+
types: [opened, synchronize, labeled, unlabeled]
11+
branches: [main]
12+
13+
jobs:
14+
test-grafana:
15+
if: |
16+
contains(github.event.pull_request.labels.*.name, 'test-nimbus-proxy') ||
17+
contains(github.event.pull_request.labels.*.name, 'test-all') ||
18+
github.event_name == 'push'
19+
runs-on: ubuntu-latest
20+
steps:
21+
- name: Checkout
22+
uses: actions/checkout@v6
23+
- name: Set up Docker buildx
24+
uses: docker/setup-buildx-action@v3
25+
- name: Create .env file
26+
run: cp default.env .env
27+
- name: Set Nimbus Verified Proxy
28+
run: |
29+
source ./.github/helper.sh
30+
NETWORK=mainnet
31+
var=NETWORK
32+
set_value_in_env
33+
COMPOSE_FILE=nimbus-vp.yml
34+
var=COMPOSE_FILE
35+
set_value_in_env
36+
RPC_URL=wss://ethereum-rpc.publicnode.com
37+
var=RPC_URL
38+
set_value_in_env
39+
CL_NODE=https://ethereum.operationsolarstorm.org/
40+
var=CL_NODE
41+
set_value_in_env
42+
- name: Start Nimbus Verified Proxy
43+
run: ./ethd up
44+
- name: Pause for 30 seconds
45+
run: sleep 30
46+
- name: Test Nimbus Verified Proxy
47+
run: ./.github/check-service.sh rpc-proxy

default.env

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ EL_HOST=rpc
8383
EL_LB=rpc-lb
8484
EL_WS_HOST=ws
8585
EL_WS_LB=ws-lb
86+
PROXY_RPC_HOST=rpc
87+
PROXY_WS_HOST=ws
8688
CL_HOST=cl
8789
CL_LB=cl-lb
8890
VC_HOST=vc
@@ -155,6 +157,10 @@ EL_RPC_PORT=8545
155157
# Note that for Erigon, this needs to match EL_RPC_PORT *if* you use traefik, and only then
156158
# Do not change it for Erigon and el-shared.yml
157159
EL_WS_PORT=8546
160+
# Ports to use for the verified proxy. They can be the same as the EL ports, depending on whether
161+
# you are mapping either to host.
162+
PROXY_RPC_PORT=48545
163+
PROXY_WS_PORT=48546
158164
# Erigon's torrent port. Don't make this 42070, as it will fail
159165
ERIGON_TORRENT_PORT=42069
160166
# Erigon's third P2P port
@@ -246,6 +252,8 @@ PG_ALIAS=${NETWORK}-postgres
246252
CL_ALIAS=${NETWORK}-consensus
247253
EL_ALIAS=${NETWORK}-execution
248254
MEV_ALIAS=${NETWORK}-mev
255+
RPC_PROXY_ALIAS=${NETWORK}-rpc-proxy
256+
WS_PROXY_ALIAS=${NETWORK}-ws-proxy
249257
# MEV-boost address. This would only be changed for Vouch setups
250258
MEV_NODE=http://${MEV_ALIAS}:18550
251259
# Web3signer address - match service name or alias, or it can be remote
@@ -258,6 +266,8 @@ OBOL_CL_NODE=http://${NETWORK}-consensus:${CL_REST_PORT}
258266
EL_RPC_NODE=http://${NETWORK}-execution:${EL_RPC_PORT}
259267
# Execution client address (WS) for SSV Anchor
260268
EL_WS_NODE=ws://${NETWORK}-execution:${EL_WS_PORT}
269+
# RPC provider when using a verified proxy, use wss:// here
270+
RPC_URL=wss://eth-${NETWORK}.g.alchemy.com/v2/<ApiKey>
261271

262272
# You can set specific version targets and choose binary or compiled from source builds below,
263273
# via "Dockerfile.binary" or "Dockerfile.source"
@@ -435,6 +445,11 @@ ETHREX_DOCKER_TAG=latest
435445
ETHREX_DOCKER_REPO=ghcr.io/lambdaclass/ethrex
436446
ETHREX_DOCKERFILE=Dockerfile.binary
437447

448+
# Nimbus verified proxy
449+
# SRC build target can be a tag, a branch, or a pr as "pr-ID"
450+
NIMVP_SRC_BUILD_TARGET=master
451+
NIMVP_SRC_REPO=https://github.com/status-im/nimbus-eth1
452+
NIMVP_DOCKERFILE=Dockerfile.source
438453

439454
# staking-deposit-cli
440455
# SRC build target can be a tag, a branch, or a pr as "pr-ID"
@@ -456,4 +471,4 @@ NODE_EXPORTER_IGNORE_MOUNT_REGEX='^/(dev|proc|sys|run|var/snap/.+|var/lib/docker
456471
DOCKER_ROOT=/var/lib/docker
457472

458473
# Used by ethd update - please do not adjust
459-
ENV_VERSION=50
474+
ENV_VERSION=51

ethd

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5366,6 +5366,14 @@ version() {
53665366
;;
53675367
esac
53685368

5369+
# RPC proxy version
5370+
case "${__value}" in
5371+
*nimbus-vp.yml*)
5372+
__docompose exec rpc-proxy nimbus_verified_proxy --version
5373+
echo
5374+
;;
5375+
esac
5376+
53695377
# Grafana version
53705378
case "${__value}" in
53715379
*grafana.yml*)

nimbus-vp.yml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
x-logging: &logging
2+
logging:
3+
driver: json-file
4+
options:
5+
max-size: 100m
6+
max-file: "3"
7+
tag: '{{.ImageName}}|{{.Name}}|{{.ImageFullID}}|{{.FullID}}'
8+
9+
services:
10+
rpc-proxy:
11+
restart: "unless-stopped"
12+
build:
13+
context: ./nimbus-vp
14+
dockerfile: ${NIMVP_DOCKERFILE}
15+
args:
16+
- BUILD_TARGET=${NIMVP_SRC_BUILD_TARGET:-master}
17+
- SRC_REPO=${NIMVP_SRC_REPO:-https://github.com/status-im/nimbus-eth1}
18+
stop_signal: SIGINT
19+
stop_grace_period: 30s
20+
image: nimbus-vp:local
21+
pull_policy: never
22+
user: user
23+
environment:
24+
- CL_NODE=${CL_NODE}
25+
volumes:
26+
- nimbus-vp-data:/var/lib/nimbus
27+
- /etc/localtime:/etc/localtime:ro
28+
networks:
29+
default:
30+
aliases:
31+
# This allows multiple Eth Docker stacks all connected to the same bridge network
32+
- ${RPC_PROXY_ALIAS:-default-rpc-proxy}
33+
<<: *logging
34+
entrypoint:
35+
- docker-entrypoint.sh
36+
- nimbus_verified_proxy
37+
- --data-dir=/var/lib/nimbus
38+
- --network=${NETWORK}
39+
- --execution-api-url=${RPC_URL}
40+
- --listen-url=http://0.0.0.0:${PROXY_RPC_PORT:-48545}
41+
- --listen-url=ws://0.0.0.0:${PROXY_WS_PORT:-48546}
42+
- --beacon-api-url=${CL_NODE}
43+
- --log-level=${LOG_LEVEL}
44+
45+
volumes:
46+
nimbus-vp-data:
47+
48+
networks:
49+
default:
50+
enable_ipv6: ${IPV6:-false}

nimbus-vp/Dockerfile.source

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# hadolint global ignore=DL3007,DL3008,DL3059,DL4006
2+
# Build Nimbus verified proxy in a stock debian container
3+
FROM debian:trixie-slim AS builder
4+
5+
RUN apt-get update && DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get install -y --no-install-recommends \
6+
build-essential \
7+
librocksdb-dev \
8+
ca-certificates \
9+
git
10+
11+
ARG BUILD_TARGET
12+
ARG SRC_REPO
13+
14+
WORKDIR /usr/src
15+
16+
ARG SRC_DIR=nimbus-eth1
17+
RUN bash -eo pipefail <<'EOF'
18+
git clone "$SRC_REPO" "$SRC_DIR"
19+
cd "$SRC_DIR"
20+
git config advice.detachedHead false
21+
git fetch --all --tags
22+
CLEANED=$(echo "$BUILD_TARGET" | sed 's/\$\$(/$(/g')
23+
TARGET=$(eval echo "$CLEANED")
24+
if [[ "$TARGET" =~ pr-.+ ]]; then
25+
git fetch origin pull/$(echo "$TARGET" | cut -d '-' -f 2)/head:build-pr
26+
git checkout build-pr
27+
else
28+
git checkout "$TARGET"
29+
fi
30+
make -j$(nproc) update
31+
make -j$(nproc) nimbus_verified_proxy
32+
EOF
33+
34+
35+
# Pull all binaries into a second stage deploy debian container
36+
FROM debian:trixie-slim
37+
38+
RUN apt-get update && DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get install -y --no-install-recommends \
39+
librocksdb-dev \
40+
ca-certificates \
41+
tzdata \
42+
gosu \
43+
adduser \
44+
bash \
45+
curl \
46+
jq \
47+
&& gosu nobody true \
48+
&& apt-get clean \
49+
&& rm -rf /var/lib/apt/lists/*
50+
51+
ARG USER=user
52+
ARG UID=11001
53+
54+
# See https://stackoverflow.com/a/55757473/12429735RUN
55+
RUN adduser \
56+
--disabled-password \
57+
--gecos "" \
58+
--home "/nonexistent" \
59+
--shell "/usr/sbin/nologin" \
60+
--no-create-home \
61+
--uid "${UID}" \
62+
"${USER}"
63+
64+
RUN mkdir -p /var/lib/nimbus && chown -R ${USER}:${USER} /var/lib/nimbus && chmod 700 /var/lib/nimbus
65+
66+
# Cannot assume buildkit, hence no chmod
67+
COPY --from=builder --chown=${USER}:${USER} /usr/src/nimbus-eth1/build/nimbus_verified_proxy /usr/local/bin/
68+
COPY --chown=${USER}:${USER} ./docker-entrypoint.sh /usr/local/bin/
69+
# Belt and suspenders
70+
RUN chmod -R 755 /usr/local/bin/*
71+
72+
USER ${USER}
73+
74+
ENTRYPOINT ["nimbus_verified_proxy"]

nimbus-vp/docker-entrypoint.sh

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
if [[ "$(id -u)" -eq 0 ]]; then
5+
chown -R user:user /var/lib/nimbus
6+
exec gosu user docker-entrypoint.sh "$@"
7+
fi
8+
9+
10+
while true; do
11+
if curl -s -m 5 "${CL_NODE}" &> /dev/null; then
12+
echo "Consensus Layer node is up, fetching trusted block root"
13+
break
14+
else
15+
echo "Waiting for Consensus Layer node to be reachable..."
16+
sleep 5
17+
fi
18+
done
19+
20+
set +e
21+
root=$(curl -s -f -m 30 "${CL_NODE}/eth/v1/beacon/headers/finalized" | jq -r '.data.root')
22+
__trusted_root="--trusted-block-root=${root}"
23+
exitstatus=$?
24+
set -e
25+
26+
if [[ "${exitstatus}" -ne 0 ]]; then
27+
echo "Failed to fetch trusted block root from ${CL_NODE}"
28+
echo "Please verify it's reachable"
29+
sleep 30
30+
exit 1
31+
fi
32+
33+
i=0
34+
# Verified proxy can get "stuck" if light client bootstrap isn't ready. Check for it here
35+
while true; do
36+
if curl -s -f -m 30 "${CL_NODE}/eth/v1/beacon/light_client/bootstrap/${root}" &> /dev/null; then
37+
echo "Consensus Layer node has light client bootstrap available, starting Nimbus Verified Proxy"
38+
break
39+
else
40+
((++i))
41+
if [[ "$i" -eq 4 ]]; then
42+
echo "Failed to get light client bootstrap data four times in a row. Waiting for epoch switchover to try with fresh block root"
43+
secs=370 # Plus the 15 we already waited, 385. Epoch is 384
44+
while [ $secs -gt 0 ]; do
45+
echo "Waiting for $secs seconds"
46+
sleep 10
47+
((secs -= 10))
48+
done
49+
exit 1
50+
else
51+
echo "Waiting for Consensus Layer node to have light client bootstrap data..."
52+
sleep 5
53+
fi
54+
fi
55+
done
56+
57+
# Word splitting is desired for the command line parameters
58+
# shellcheck disable=SC2086
59+
exec "$@" ${__trusted_root}

rpc-proxy-shared.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# To be used in conjunction with nimbus-vp.yml
2+
services:
3+
rpc-proxy:
4+
ports:
5+
- ${SHARE_IP:-}:${PROXY_RPC_PORT}:${PROXY_RPC_PORT:-48545}/tcp
6+
- ${SHARE_IP:-}:${PROXY_WS_PORT}:${PROXY_WS_PORT:-48546}/tcp

rpc-proxy-traefik.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# To be used in conjunction with nimbus-vp.yml
2+
services:
3+
rpc-proxy:
4+
labels:
5+
- traefik.enable=true
6+
- traefik.http.routers.${PROXY_RPC_HOST:-rpc}.service=${PROXY_HOST:-rpc}
7+
- traefik.http.routers.${PROXY_RPC_HOST:-rpc}.entrypoints=websecure
8+
- traefik.http.routers.${PROXY_RPC_HOST:-rpc}.rule=Host(`${PROXY_HOST:-rpc}.${DOMAIN}`)
9+
- traefik.http.routers.${PROXY_RPC_HOST:-rpc}.tls.certresolver=letsencrypt
10+
- traefik.http.services.${PROXY_RPC_HOST:-rpc}.loadbalancer.server.port=${PROXY_RPC_PORT:-48545}
11+
- traefik.http.routers.${PROXY_WS_HOST:-ws}.service=${PROXY_WS_HOST:-ws}
12+
- traefik.http.routers.${PROXY_WS_HOST:-ws}.entrypoints=websecure
13+
- traefik.http.routers.${PROXY_WS_HOST:-ws}.rule=Host(`${PROXY_WS_HOST:-ws}.${DOMAIN}`)
14+
- traefik.http.routers.${PROXY_WS_HOST:-ws}.tls.certresolver=letsencrypt
15+
- traefik.http.services.${PROXY_WS_HOST:-ws}.loadbalancer.server.port=${PROXY_WS_PORT:-48546}

0 commit comments

Comments
 (0)