description | hidden |
---|---|
Setting Up a Distributed Validator Cluster with Obol Network and StakeWise Vaults |
true |
Follow these steps to set up a Distributed Validator Cluster using Obol Network and integrate it with StakeWise Vaults.
- Install Docker Engine
- Ensure Docker is running. Check:
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
...
{% hint style="warning" %}
IMPORTANT! When using the create-keys
command, add the --per-keystore-password
flag to generate a keystore with a separate password file for each keystore. This is necessary for the normal operation of the Charon CLI, especially when splitting keys.
{% endhint %}
First, create .env
file with charon
settings:
{% hint style="info" %} Addresses must be in lowercase {% endhint %}
cat <<EOF > .env
export VAULT_CONTRACT_ADDR=[ENTER YOUR VAULT CONTRACT ADDRESS HERE]
export FEE_RECIPIENT_ADDR=[ENTER YOUR VAULT FEE RECIPIENT ADDRESS HERE]
export NETWORK=[ENTER YOUR NETWORK NAME]
EOF
Next create cluster obol cluster:
source .env
docker run --rm -v "$(pwd):/opt/charon" -v "$HOME/.stakewise:/.stakewise" obolnetwork/charon:v0.19.2 \
create cluster \
--name="cluster-name" \
--cluster-dir=".charon/cluster/" \
--withdrawal-addresses=$VAULT_CONTRACT_ADDR \
--fee-recipient-addresses=$FEE_RECIPIENT_ADDR \
--nodes 3 \
--network $NETWORK \
--split-existing-keys \
--split-keys-dir /.stakewise/$VAULT_CONTRACT_ADDR/keystores
~~~~~ OUTPUT:
***************** WARNING: Splitting keys **********************
Please make sure any existing validator has been shut down for
at least 2 finalised epochs before starting the charon cluster,
otherwise slashing could occur.
****************************************************************
Created charon cluster:
--split-existing-keys=true
/opt/charon/.charon/cluster/
├─ node[0-2]/ Directory for each node
│ ├─ charon-enr-private-key Charon networking private key for node authentication
│ ├─ cluster-lock.json Cluster lock defines the cluster lock file which is signed by all nodes
│ ├─ deposit-data.json Deposit data file is used to activate a Distributed Validator on DV Launchpad
│ ├─ validator_keys Validator keystores and password
│ │ ├─ keystore-*.json Validator private share key for duty signing
│ │ ├─ keystore-*.txt Keystore password files for keystore-*.json
You should now have multiple folders within ./.charon/cluster/
, one for each node created. Backup the ./.charon
folder, then move on to deploying the cluster physically.
After initial setup run 3 charon client and 3 validators client (you can run it on single server or distribute across multiple), copy below docker-compose.yml
, file to the server the same dir with .charon
and run docker compose up -d
{% hint style="info" %}
Replace [ENTER YOUR VAULT FEE RECIPIENT ADDRESS HERE]
with your vault fee recipient address
{% endhint %}
docker-compose.yml
x-logging: &logging
logging:
driver: json-file
options:
max-size: 10m
max-file: "3"
tag: "{{.ImageName}}|{{.Name}}|{{.ImageFullID}}|{{.FullID}}"
networks:
cluster:
x-node-base:
# Pegged charon version (update this for each release).
&node-base
image: obolnetwork/charon:${CHARON_VERSION:-v0.19.2}
restart: unless-stopped
networks: [ cluster ]
depends_on: [ relay ]
volumes:
- ./.charon:/opt/charon/.charon/
x-node-env:
&node-env
CHARON_BEACON_NODE_ENDPOINTS: ${CHARON_BEACON_NODE_ENDPOINTS:-http://lighthouse:6000}
CHARON_LOG_LEVEL: ${CHARON_LOG_LEVEL:-info}
CHARON_LOG_FORMAT: ${CHARON_LOG_FORMAT:-console}
CHARON_P2P_EXTERNAL_HOSTNAME: ${CHARON_P2P_EXTERNAL_HOSTNAME:-} # Empty default required to avoid warnings.
CHARON_P2P_RELAYS: ${CHARON_P2P_RELAYS:-http://relay:3640/enr}
CHARON_P2P_TCP_ADDRESS: ${CHARON_P2P_TCP_ADDRESS:-0.0.0.0:3610}
CHARON_VALIDATOR_API_ADDRESS: ${CHARON_VALIDATOR_API_ADDRESS:-0.0.0.0:3600}
services:
mev-boost:
image: flashbots/mev-boost:1.7.0
restart: always
command: >
-mainnet
-relays
https://0xac6e77dfe25ecd6110b8e780608cce0dab71fdd5ebea22a16c0205200f2f8e2e3ad3b71d3499c54ad14d6c21b41a37ae@boost-relay.flashbots.net,https://0xa1559ace749633b997cb3fdacffb890aeebdb0f5a3b6aaa7eeeaf1a38af0a8fe88b9e4b1f61f236d2e64d95733327a62@relay.ultrasound.money,https://0x8b5d2e73e2a3a55c6c87b8b6eb92e0149a125c852751db1422fa951e42a09b82c142c3ea98d0d9930b056a3bc9896b8f@bloxroute.max-profit.blxrbdn.com,https://0xa7ab7a996c8584251c8f925da3170bdfd6ebc75d50f5ddc4050a6fdc77f2a3b5fce2cc750d0865e05d7228af97d69561@agnostic-relay.net,https://0xb0b07cd0abef743db4260b0ed50619cf6ad4d82064cb4fbec9d3ec530f7c5e6793d9f286c4e082c0244ffb9f2658fe88@bloxroute.regulated.blxrbdn.com,https://0xa15b52576bcbf1072f4a011c0f99f9fb6c66f3e1ff321f11f461d15e31b1cb359caa092c71bbded0bae5b5ea401aab7e@aestus.live
-addr
127.0.0.1:18551
-loglevel
info
-json
networks: [ cluster ]
geth:
image: ethereum/client-go:v1.13.14
restart: always
command: >
--mainnet
--syncmode=snap
--datadir=/data
--db.engine=pebble
--authrpc.jwtsecret=/data/jwtsecret --authrpc.addr=0.0.0.0 --authrpc.port=8551 --authrpc.vhosts=*
--http --http.addr=0.0.0.0 --http.port=8445 --http.corsdomain=* --http.vhosts=*
--port=30303
--ipcdisable
volumes: ["./data/geth:/data"]
ports:
- 30303:30303/tcp
- 30303:30303/udp
networks: [ cluster ]
lighthouse:
image: sigp/lighthouse:v5.1.2
restart: always
command: >
lighthouse
bn
--staking
--datadir=/data
--network=mainnet
--execution-endpoint=http://geth:8551
--execution-jwt=/data/jwtsecret
--checkpoint-sync-url=https://mainnet-checkpoint-sync.attestant.io/
--slots-per-restore-point=8192
--http
--http-port=6000
--http-address=0.0.0.0
--http-allow-origin=*
--builder http://localhost:18551
--port=30304
--enr-udp-port=30305
--disable-upnp
ulimits:
nofile:
soft: "1000000"
hard: "1000000"
volumes: ["./data/lighthouse:/data"]
ports:
- 30304:30304/tcp
- 30304:30304/udp
- 30305:30305/udp
networks: [ cluster ]
relay:
<<: *node-base
command: relay
depends_on: []
environment:
<<: *node-env
CHARON_HTTP_ADDRESS: 0.0.0.0:3640
CHARON_DATA_DIR: /opt/charon/relay
CHARON_P2P_RELAYS: ""
CHARON_P2P_EXTERNAL_HOSTNAME: relay
volumes:
- ./data/relay:/opt/charon/relay:rw
node0:
<<: *node-base
environment:
<<: *node-env
CHARON_PRIVATE_KEY_FILE: /opt/charon/.charon/cluster/node0/charon-enr-private-key
CHARON_LOCK_FILE: /opt/charon/.charon/cluster/node0/cluster-lock.json
CHARON_P2P_EXTERNAL_HOSTNAME: node0
node1:
<<: *node-base
environment:
<<: *node-env
CHARON_PRIVATE_KEY_FILE: /opt/charon/.charon/cluster/node1/charon-enr-private-key
CHARON_LOCK_FILE: /opt/charon/.charon/cluster/node1/cluster-lock.json
CHARON_P2P_EXTERNAL_HOSTNAME: node1
node2:
<<: *node-base
environment:
<<: *node-env
CHARON_PRIVATE_KEY_FILE: /opt/charon/.charon/cluster/node2/charon-enr-private-key
CHARON_LOCK_FILE: /opt/charon/.charon/cluster/node2/cluster-lock.json
CHARON_P2P_EXTERNAL_HOSTNAME: node2
vc0-teku:
image: consensys/teku:${TEKU_VERSION:-24.3.0}
networks: [ cluster ]
depends_on: [ node0 ]
restart: unless-stopped
command: |
validator-client
--network=auto
--beacon-node-api-endpoint="http://node0:3600"
--Xblock-v3-enabled=false
--validators-proposer-default-fee-recipient=[ENTER YOUR VAULT FEE RECIPIENT ADDRESS HERE]
--validator-keys="/opt/charon/validator_keys:/opt/charon/validator_keys"
--validators-keystore-locking-enabled=false
volumes:
- .charon/cluster/node0/validator_keys:/opt/charon/validator_keys
- ./data/vc0:/opt/charon/teku
vc1-teku:
image: consensys/teku:${TEKU_VERSION:-24.3.0}
networks: [ cluster ]
depends_on: [ node1 ]
restart: unless-stopped
command: |
validator-client
--network=auto
--beacon-node-api-endpoint="http://node1:3600"
--Xblock-v3-enabled=false
--validators-proposer-default-fee-recipient=[ENTER YOUR VAULT FEE RECIPIENT ADDRESS HERE]
--validator-keys="/opt/charon/validator_keys:/opt/charon/validator_keys"
--validators-keystore-locking-enabled=false
volumes:
- .charon/cluster/node1/validator_keys:/opt/charon/validator_keys
- ./data/vc1:/opt/charon/teku
vc2-teku:
image: consensys/teku:${TEKU_VERSION:-24.3.0}
networks: [ cluster ]
depends_on: [ node2 ]
restart: unless-stopped
command: |
validator-client
--network=auto
--beacon-node-api-endpoint="http://node2:3600"
--Xblock-v3-enabled=false
--validators-proposer-default-fee-recipient=[ENTER YOUR VAULT FEE RECIPIENT ADDRESS HERE]
--validator-keys="/opt/charon/validator_keys:/opt/charon/validator_keys"
--validators-keystore-locking-enabled=false
volumes:
- .charon/cluster/node2/validator_keys:/opt/charon/validator_keys
- ./data/vc2:/opt/charon/teku
{% hint style="info" %} For more info check Obol Documentation {% endhint %}