Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ data
*.old
.DS_Store

# User configuration files
user-config.yml

# Generated genesis files (created by generate-genesis.sh)
config.yaml
validators.yaml
Expand Down
54 changes: 52 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,44 @@ NETWORK_DIR=local-devnet ./spin-node.sh --node zeam_0 --generateGenesis --popupT
NETWORK_DIR=local-devnet ./spin-node.sh --node all --generateGenesis --metrics
```

### Using custom Docker images

You can override default Docker images using the `--config-file` flag. This is useful for testing custom builds or using specific versions without modifying the codebase.

**Basic usage (without custom images):**
```sh
# Uses default images from client-cmds/default-client-config.yml
NETWORK_DIR=local-devnet ./spin-node.sh --node all --generateGenesis
```

**With custom config file:**
```sh
# Override specific client images
NETWORK_DIR=local-devnet ./spin-node.sh --node all --generateGenesis --config-file user-config.yml
```

**Example config file (user-config.yml):**
```yaml
clients:
- name: zeam
image: blockblaz/zeam:feature-branch
- name: ream
image: ghcr.io/reamlabs/ream:v2.0
```

**Testing a specific client build:**
```sh
# Create custom config file for zeam <your-PATH>/my-zeam-config.yml
clients:
- name: zeam
image: blockblaz/zeam:custom-tag

# Run with custom zeam image
NETWORK_DIR=local-devnet ./spin-node.sh --node zeam_0 --config-file <your-PATH>/my-zeam-config.yml
```

Only specify clients you want to override - others will use their defaults from `client-cmds/default-client-config.yml`.

## Args

1. `NETWORK_DIR` is an env to specify the network directory. Should have a `genesis` directory with genesis config. A `data` folder will be created inside this `NETWORK_DIR` if not already there.
Expand Down Expand Up @@ -119,6 +157,11 @@ NETWORK_DIR=local-devnet ./spin-node.sh --node all --generateGenesis --metrics
- If not provided, defaults to `latest` for zeam, ream, and lantern, and `dd67521` for qlean
- The script will automatically pull the specified Docker images before running containers
- Example: `--tag devnet0` or `--tag devnet1`
11. `--config-file` specifies a custom configuration file to override default Docker images for specific clients.
- Path to a YAML file containing client image overrides (e.g., `user-config.yml` or `/path/to/my-config.yml`)
- Only clients specified in the config file are overridden; others use defaults from `client-cmds/default-client-config.yml`
- See [Using custom Docker images](#using-custom-docker-images) scenario for usage examples
- Example: `--config-file user-config.yml` or `--config-file /path/to/custom-config.yml`
12. `--metrics` enables metrics collection on all nodes. When specified, each client will activate its metrics endpoint according to its implementation. Metrics ports are configured per node in `validator-config.yaml`.

### Clients supported
Expand Down Expand Up @@ -148,12 +191,19 @@ The quickstart uses separate directories for local and Ansible deployments:

```
lean-quickstart/
├── local-devnet/ # Local development
├── client-cmds/ # Client command scripts
│ ├── default-client-config.yml # Default Docker images for all clients
│ ├── zeam-cmd.sh
│ ├── ream-cmd.sh
│ └── ...
├── user-config.yml.example # Example custom config (copy to user-config.yml)
├── user-config.yml # Your custom image overrides (gitignored)
├── local-devnet/ # Local development
│ ├── genesis/
│ │ └── validator-config.yaml # Local IPs (127.0.0.1)
│ └── data/ # Node data directories
└── ansible-devnet/ # Ansible/remote deployment
└── ansible-devnet/ # Ansible/remote deployment
├── genesis/
│ └── validator-config.yaml # Remote IPs (your server IPs)
└── data/ # Node data directories
Expand Down
22 changes: 22 additions & 0 deletions client-cmds/default-client-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Default Client Configuration
# This file contains the default Docker images for all supported clients
# These defaults are used when no custom config file is specified via --config-file

clients:
- name: zeam
image: blockblaz/zeam:latest

- name: ream
image: ghcr.io/reamlabs/ream:latest

- name: qlean
image: qdrvm/qlean-mini:latest

- name: lantern
image: piertwo/lantern:latest

- name: lighthouse
image: hopinheimer/lighthouse:latest

- name: grandine
image: sifrai/lean:latest
5 changes: 4 additions & 1 deletion client-cmds/grandine-cmd.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#!/bin/bash

# Docker image (set from default-client-config.yml or user config via --config-file)
# grandineImage is exported by spin-node.sh before sourcing this file

node_binary="$grandine_bin \
--genesis $configDir/config.yaml \
--validator-registry-path $configDir/validators.yaml \
Expand All @@ -10,7 +13,7 @@ node_binary="$grandine_bin \
--address 0.0.0.0 \
--hash-sig-key-dir $configDir/hash-sig-keys"

node_docker="sifrai/lean:unstable \
node_docker="$grandineImage \
--genesis /config/config.yaml \
--validator-registry-path /config/validators.yaml \
--bootnodes /config/nodes.yaml \
Expand Down
5 changes: 3 additions & 2 deletions client-cmds/lantern-cmd.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#!/bin/bash

#-----------------------lantern setup----------------------
LANTERN_IMAGE="piertwo/lantern:v0.0.1"
# Docker image (set from default-client-config.yml or user config via --config-file)
# lanternImage is exported by spin-node.sh before sourcing this file

devnet_flag=""
if [ -n "$devnet" ]; then
Expand All @@ -24,7 +25,7 @@ node_binary="$scriptDir/lantern/build/lantern_cli \
--log-level debug \
--hash-sig-key-dir $configDir/hash-sig-keys"

node_docker="$LANTERN_IMAGE --data-dir /data \
node_docker="$lanternImage --data-dir /data \
--genesis-config /config/config.yaml \
--validator-registry-path /config/validators.yaml \
--genesis-state /config/genesis.ssz \
Expand Down
5 changes: 4 additions & 1 deletion client-cmds/lighthouse-cmd.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
# Metrics enabled by default
metrics_flag="--metrics"

# Docker image (set from default-client-config.yml or user config via --config-file)
# lighthouseImage is exported by spin-node.sh before sourcing this file

node_binary="$lighthouse_bin lean_node \
--datadir \"$dataDir/$item\" \
--config \"$configDir/config.yaml\" \
Expand All @@ -16,7 +19,7 @@ node_binary="$lighthouse_bin lean_node \
--metrics-address 0.0.0.0 \
--metrics-port $metricsPort"

node_docker="hopinheimer/lighthouse:latest lighthouse lean_node \
node_docker="$lighthouseImage lighthouse lean_node \
--datadir /data \
--config /config/config.yaml \
--validators /config/validator-config.yaml \
Expand Down
8 changes: 6 additions & 2 deletions client-cmds/qlean-cmd.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
#-----------------------qlean setup----------------------
# expects "qlean" submodule or symlink inside "lean-quickstart" root directory
# https://github.com/qdrvm/qlean-mini

# Docker image (set from default-client-config.yml or user config via --config-file)
# qleanImage is exported by spin-node.sh before sourcing this file

node_binary="$scriptDir/qlean/build/src/executable/qlean \
--modules-dir $scriptDir/qlean/build/src/modules \
--genesis $configDir/config.yaml \
Expand All @@ -16,8 +20,8 @@ node_binary="$scriptDir/qlean/build/src/executable/qlean \
--listen-addr /ip4/0.0.0.0/udp/$quicPort/quic-v1 \
--prometheus-port $metricsPort \
-ldebug"
node_docker="qdrvm/qlean-mini:3a96a1f \

node_docker="$qleanImage \
--genesis /config/config.yaml \
--validator-registry-path /config/validators.yaml \
--validator-keys-manifest /config/hash-sig-keys/validator-keys-manifest.yaml \
Expand Down
5 changes: 4 additions & 1 deletion client-cmds/ream-cmd.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
# Metrics enabled by default
metrics_flag="--metrics"

# Docker image (set from default-client-config.yml or user config via --config-file)
# reamImage is exported by spin-node.sh before sourcing this file

# modify the path to the ream binary as per your system
node_binary="$scriptDir/../ream/target/release/ream --data-dir $dataDir/$item \
lean_node \
Expand All @@ -17,7 +20,7 @@ node_binary="$scriptDir/../ream/target/release/ream --data-dir $dataDir/$item \
--metrics-port $metricsPort \
--http-address 0.0.0.0"

node_docker="ghcr.io/reamlabs/ream:latest --data-dir /data \
node_docker="$reamImage --data-dir /data \
lean_node \
--network /config/config.yaml \
--validator-registry-path /config/validators.yaml \
Expand Down
5 changes: 4 additions & 1 deletion client-cmds/zeam-cmd.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
# Metrics enabled by default
metrics_flag="--metrics_enable"

# Docker image (set from default-client-config.yml or user config via --config-file)
# zeamImage is exported by spin-node.sh before sourcing this file

node_binary="$scriptDir/../zig-out/bin/zeam node \
--custom_genesis $configDir \
--validator_config $validatorConfig \
Expand All @@ -14,7 +17,7 @@ node_binary="$scriptDir/../zig-out/bin/zeam node \
$metrics_flag \
--metrics_port $metricsPort"

node_docker="--security-opt seccomp=unconfined blockblaz/zeam:devnet1 node \
node_docker="--security-opt seccomp=unconfined $zeamImage node \
--custom_genesis /config \
--validator_config $validatorConfig \
--data-dir /data \
Expand Down
134 changes: 134 additions & 0 deletions load-client-config.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#!/bin/bash
# Load client configuration from default and optional user config files

# Arrays to store client names and images (bash 3.2 compatible)
CLIENT_NAMES=()
CLIENT_IMAGES_LIST=()
KNOWN_CLIENTS=("zeam" "ream" "qlean" "lantern" "lighthouse" "grandine")

# Function to load default config
load_default_config() {
local default_config="$scriptDir/client-cmds/default-client-config.yml"

if [ ! -f "$default_config" ]; then
echo "⚠️ Warning: Default config not found at $default_config"
return 1
fi

# Load default images using yq
while IFS= read -r line; do
local client_name=$(echo "$line" | awk '{print $1}')
local client_image=$(echo "$line" | awk '{print $2}')
CLIENT_NAMES+=("$client_name")
CLIENT_IMAGES_LIST+=("$client_image")
done < <(yq eval '.clients[] | .name + " " + .image' "$default_config")

echo "✓ Loaded default client images from $default_config"
}

# Function to find index of client name
find_client_index() {
local search_name="$1"
local i=0
for name in "${CLIENT_NAMES[@]}"; do
if [ "$name" == "$search_name" ]; then
echo "$i"
return 0
fi
((i++))
done
echo "-1"
}

# Function to load user config and override defaults
load_user_config() {
local user_config="$1"

if [ -z "$user_config" ]; then
return 0
fi

if [ ! -f "$user_config" ]; then
echo "⚠️ Warning: User config file not found at $user_config - using defaults"
return 1
fi

echo "Loading user config from $user_config..."

# Load user-specified images
local override_count=0
while IFS= read -r line; do
local client_name=$(echo "$line" | awk '{print $1}')
local client_image=$(echo "$line" | awk '{print $2}')

# Validate client name
local valid_client=false
for known in "${KNOWN_CLIENTS[@]}"; do
if [ "$client_name" == "$known" ]; then
valid_client=true
break
fi
done

if [ "$valid_client" == "false" ]; then
echo "⚠️ Warning: Unknown client '$client_name' in config - skipping"
continue
fi

# Validate image format (basic check)
if [[ ! "$client_image" =~ ^[a-zA-Z0-9._/-]+:[a-zA-Z0-9._-]+$ ]]; then
echo "⚠️ Warning: Invalid image format '$client_image' for client '$client_name' - using default"
continue
fi

# Find and update the client image
local idx=$(find_client_index "$client_name")
if [ "$idx" != "-1" ]; then
CLIENT_IMAGES_LIST[$idx]="$client_image"
echo " ✓ Override $client_name: $client_image"
((override_count++))
fi
done < <(yq eval '.clients[] | .name + " " + .image' "$user_config" 2>/dev/null)

if [ $override_count -eq 0 ]; then
echo "⚠️ No valid overrides found in user config"
else
echo "✓ Applied $override_count custom image(s) from user config"
fi
}

# Function to get image for a specific client
get_client_image() {
local client_name="$1"
local idx=$(find_client_index "$client_name")
if [ "$idx" != "-1" ]; then
echo "${CLIENT_IMAGES_LIST[$idx]}"
fi
}

# Function to display loaded configuration
display_client_config() {
echo ""
echo "=================================================="
echo "Client Configuration:"
echo "=================================================="
printf "%-12s | %s\n" "Client" "Docker Image"
echo "--------------------------------------------------"
local i=0
for client in "${CLIENT_NAMES[@]}"; do
if [ -n "${CLIENT_IMAGES_LIST[$i]}" ]; then
printf "%-12s | %s\n" "$client" "${CLIENT_IMAGES_LIST[$i]}"
fi
((i++))
done
echo "=================================================="
echo ""
}

# Load default configuration
load_default_config

# Load user configuration if provided
if [ -n "$configFile" ]; then
load_user_config "$configFile"
fi
6 changes: 6 additions & 0 deletions parse-env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ while [[ $# -gt 0 ]]; do
shift # past argument
shift # past value
;;
--config-file)
configFile="$2"
shift # past argument
shift # past value
;;
--stop)
stopNodes=true
shift
Expand Down Expand Up @@ -109,4 +114,5 @@ echo "generateGenesis = $generateGenesis"
echo "cleanData = $cleanData"
echo "popupTerminal = $popupTerminal"
echo "dockerTag = ${dockerTag:-latest}"
echo "configFile = ${configFile:-none}"
echo "enableMetrics = $enableMetrics"
Loading