chore: add script to launch up local kurtosis testnet (#8070)

**Motivation**

Adds a bash script that allows one to launch up a local kurtosis testnet
based off of the changes made locally.

Might be useful to others -- if so, I can clean it up

<!-- Why is this PR exists? What are the goals of the pull request? -->

**Description**

```
# start a testnet with local changes
./scripts/kurtosis/run.sh start 

# stop the testnet and cleanup
./scripts/kurtosis/run.sh stop
```

---------

Co-authored-by: Nico Flaig <nflaig@protonmail.com>
This commit is contained in:
kevaundray
2025-09-02 13:51:13 +01:00
committed by GitHub
parent 684db9fff1
commit 7332b1afe1
4 changed files with 446 additions and 0 deletions

View File

@@ -0,0 +1,203 @@
# Kurtosis Scripts for Lodestar
This directory contains scripts and configurations for running Lodestar testnets using [Kurtosis](https://www.kurtosis.com/).
## Prerequisites
1. Install Kurtosis: https://docs.kurtosis.com/install
2. Install Docker: https://docs.docker.com/get-docker/
## Quick Start
From the Lodestar root directory:
```bash
# Start a testnet (automatically builds local Docker image)
./scripts/kurtosis/run.sh start
# View running services and find service names
kurtosis enclave inspect lodestar-testnet
# List just the service names
kurtosis enclave inspect lodestar-testnet | grep -E "cl-|el-|vc-" | grep RUNNING
# Check logs of a specific service (use actual service name from above)
# Note: Service names follow pattern: cl-<number>-<client>-<execution-client>
# For Lodestar nodes, this will be cl-3-lodestar-geth, cl-4-lodestar-geth, etc.
./scripts/kurtosis/run.sh logs cl-3-lodestar-geth
# Follow logs in real-time
./scripts/kurtosis/run.sh logs cl-3-lodestar-geth --follow
# Stop and clean up the testnet
./scripts/kurtosis/run.sh stop
# Force clean up (if stop fails)
./scripts/kurtosis/run.sh clean
```
Or change to the kurtosis directory first:
```bash
cd scripts/kurtosis/
# Start a testnet
./run.sh start
# Find service names
kurtosis enclave inspect lodestar-testnet | grep RUNNING
# Check logs (replace with actual service name)
./run.sh logs cl-3-lodestar-geth
# Stop
./run.sh stop
```
**Note:** The `start` command automatically builds a fresh Docker image from your local Lodestar code before starting the testnet.
## Advanced Usage
### Custom Configuration
```bash
# Create a custom config
cp lodestar.yaml my-custom-config.yaml
# Edit my-custom-config.yaml
# Run with custom config
./run.sh start my-custom-config.yaml
```
### Port Forwarding
Access services running inside Kurtosis:
```bash
# Forward Grafana dashboard
./run.sh port-forward grafana 3000
# Forward Lodestar REST API
./run.sh port-forward cl-1-lodestar 9596
```
### Custom Enclave Name
Run multiple testnets simultaneously:
```bash
./run.sh -e testnet-1 start
./run.sh -e testnet-2 start config-2.yaml
```
## Troubleshooting
### Finding Service Names
The testnet runs multiple services. To find the correct service name for logs:
```bash
# Show all services with their names
kurtosis enclave inspect lodestar-testnet | grep -A 1 "User Services" | grep -E "cl-|el-|vc-"
# Example output:
# cl-1-lighthouse-geth (Lighthouse consensus client)
# cl-2-lighthouse-geth (Lighthouse consensus client)
# cl-3-lodestar-geth (Lodestar consensus client)
# cl-4-lodestar-geth (Lodestar consensus client)
# el-1-geth-lighthouse (Geth execution client)
# el-2-geth-lighthouse (Geth execution client)
```
Service naming pattern:
- `cl-` = Consensus Layer
- `el-` = Execution Layer
- `vc-` = Validator Client
- Format: `<layer>-<number>-<client>-<paired-client>`
### Check Service Status
```bash
kurtosis service inspect lodestar-testnet <service-name>
```
### Debug Failed Services
```bash
# Check logs of a failed service
kurtosis service logs lodestar-testnet <service-name>
# Get a shell inside a service container
kurtosis service shell lodestar-testnet <service-name>
```
### Clean Up Stuck Enclaves
```bash
# Force remove an enclave
kurtosis enclave rm -f lodestar-testnet
# Remove all enclaves
kurtosis clean -a
```
## Configuration Options
The configuration files use the [ethereum-package](https://github.com/ethpandaops/ethereum-package) format. Key options include:
- `participants`: Define execution and consensus layer nodes
- `network_params`: Network configuration (preset, fork epochs, etc.)
- `additional_services`: Enable monitoring, transaction spammers, etc.
See the [ethereum-package documentation](https://github.com/ethpandaops/ethereum-package) for all available options.
## Examples
### Minimal Testnet
```yaml
participants:
- el_type: geth
count: 1
- cl_type: lodestar
count: 1
validator_count: 32
network_params:
preset: minimal
```
### Multi-Client Testnet
```yaml
participants:
- el_type: geth
count: 2
- el_type: besu
count: 1
- cl_type: lodestar
count: 2
- cl_type: lighthouse
count: 1
validator_count: 32
network_params:
preset: mainnet
```
### Testnet with Custom Lodestar Flags
```yaml
participants:
- el_type: geth
count: 2
- cl_type: lodestar
cl_image: chainsafe/lodestar:latest
count: 2
cl_extra_params:
- "--metrics"
- "--metrics.port=8008"
- "--network.subscribeAllSubnets"
validator_count: 32
```

View File

@@ -114,6 +114,7 @@ const sidebars: SidebarsConfig = {
"contribution/testing/index",
"contribution/testing/end-to-end-tests",
"contribution/testing/integration-tests",
"contribution/testing/kurtosis",
"contribution/testing/performance-tests",
"contribution/testing/simulation-tests",
"contribution/testing/spec-tests",

View File

@@ -0,0 +1,18 @@
participants:
# Execution layer
- el_type: geth
el_image: ethereum/client-go:latest
count: 2
# Consensus layer - Lodestar nodes using local build
- cl_type: lodestar
cl_image: lodestar:local # Uses locally built image
count: 4
validator_count: 8 # 32 validators total (8 per node)
network_params:
# Use minimal preset for faster testing
preset: minimal
additional_services:
- prometheus_grafana

224
scripts/kurtosis/run.sh Executable file
View File

@@ -0,0 +1,224 @@
#!/bin/bash
# Script to run Lodestar testnet using Kurtosis
set -e
# Colors for output
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Default values
ENCLAVE_NAME="lodestar-testnet"
CONFIG_FILE="lodestar.yaml"
KURTOSIS_PACKAGE="github.com/ethpandaops/ethereum-package"
# Function to print colored output
print_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
print_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
# Function to check if command exists
command_exists() {
command -v "$1" >/dev/null 2>&1
}
# Function to check dependencies
check_dependencies() {
print_info "Checking dependencies..."
if ! command_exists kurtosis; then
print_error "Kurtosis is not installed. Please install it from https://docs.kurtosis.com/install"
exit 1
fi
if ! command_exists docker; then
print_error "Docker is not installed. Please install Docker."
exit 1
fi
}
# Function to start the testnet
start_testnet() {
local config_path="$1"
print_info "Starting testnet with enclave name: $ENCLAVE_NAME"
# Check if enclave already exists
if kurtosis enclave inspect "$ENCLAVE_NAME" >/dev/null 2>&1; then
print_warn "Enclave $ENCLAVE_NAME already exists. Cleaning it up..."
kurtosis enclave rm -f "$ENCLAVE_NAME"
fi
# Run Kurtosis with the configuration
print_info "Starting Kurtosis with configuration: $config_path"
kurtosis run --enclave "$ENCLAVE_NAME" "$KURTOSIS_PACKAGE" --args-file "$config_path"
print_info "Testnet started successfully!"
print_info "View services: kurtosis enclave inspect $ENCLAVE_NAME"
}
# Function to stop the testnet
stop_testnet() {
print_info "Stopping testnet: $ENCLAVE_NAME"
kurtosis enclave stop "$ENCLAVE_NAME"
print_info "Cleaning up testnet resources..."
kurtosis enclave rm -f "$ENCLAVE_NAME"
print_info "Testnet stopped and cleaned up successfully"
}
# Function to clean up the testnet
clean_testnet() {
print_info "Cleaning up testnet: $ENCLAVE_NAME"
kurtosis enclave rm -f "$ENCLAVE_NAME"
}
# Function to show logs
show_logs() {
local service="$1"
if [ -z "$service" ]; then
print_info "Available services:"
kurtosis service ls "$ENCLAVE_NAME"
else
print_info "Showing logs for service: $service"
kurtosis service logs "$ENCLAVE_NAME" "$service" --follow
fi
}
# Function to port-forward a service
port_forward() {
local service="$1"
local port="$2"
if [ -z "$service" ] || [ -z "$port" ]; then
print_error "Usage: $0 port-forward <service-name> <port>"
exit 1
fi
print_info "Port-forwarding $service:$port"
kurtosis port-forward "$ENCLAVE_NAME" "$service" "$port"
}
# Function to build local Docker image
build_local() {
print_info "Building local Lodestar Docker image..."
# Get the root directory (two levels up from scripts/kurtosis)
# TODO: There might be a better way to get the root
LODESTAR_ROOT="$SCRIPT_DIR/../.."
# Build the Docker image
if docker build -f Dockerfile.dev -t lodestar:local "$LODESTAR_ROOT"; then
print_info "Successfully built lodestar:local"
print_info "You can now use this image in your config files with: cl_image: lodestar:local"
else
print_error "Failed to build Docker image"
exit 1
fi
}
# Function to show usage
usage() {
echo "Usage: $0 [command] [options]"
echo ""
echo "Commands:"
echo " start [config-file] Start the testnet (builds local image, default: lodestar.yaml)"
echo " stop Stop and clean up the testnet"
echo " clean Force clean up the testnet (if stop fails)"
echo " logs [service] Show logs for a service (or list services)"
echo " port-forward <service> <port> Forward a port from a service"
echo " build Build local Docker image only (without starting)"
echo " help Show this help message"
echo ""
echo "Options:"
echo " -e, --enclave <name> Set enclave name (default: lodestar-testnet)"
echo ""
echo "Examples:"
echo " $0 start"
echo " $0 start custom-config.yaml"
echo " $0 logs cl-1-lodestar"
echo " $0 port-forward grafana 3000"
}
# Parse command line arguments
COMMAND=""
while [[ $# -gt 0 ]]; do
case $1 in
-e|--enclave)
ENCLAVE_NAME="$2"
shift 2
;;
build|start|stop|clean|logs|port-forward|help)
COMMAND="$1"
shift
break
;;
*)
print_error "Unknown option: $1"
usage
exit 1
;;
esac
done
# Check dependencies
check_dependencies
# Get the directory of this script
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# Execute command
case $COMMAND in
build)
build_local
;;
start)
CONFIG_PATH="${1:-$CONFIG_FILE}"
# Make path absolute if relative
if [[ ! "$CONFIG_PATH" = /* ]]; then
CONFIG_PATH="$SCRIPT_DIR/$CONFIG_PATH"
fi
if [ ! -f "$CONFIG_PATH" ]; then
print_error "Configuration file not found: $CONFIG_PATH"
exit 1
fi
# Always build local image before starting
print_info "Building local Lodestar Docker image before starting testnet..."
build_local
start_testnet "$CONFIG_PATH"
;;
stop)
stop_testnet
;;
clean)
clean_testnet
;;
logs)
show_logs "$1"
;;
port-forward)
port_forward "$1" "$2"
;;
help)
usage
;;
*)
print_error "No command specified"
usage
exit 1
;;
esac