A single command line quickstart to spin up lean node(s)
- ✅ Single source of truth -
validator-config.yaml- defines everything
- Generates full genesis state (JSON + SSZ) plus config files
- add/remove nodes, modify validator count, assign IPs, ports, enr keys
- Uses PK's
eth-beacon-genesisdocker tool (not custom tooling) - Generates PQ keys based on specified configuration in
validator-config.yaml- Force regen with flag
--forceKeyGenwhen supplied withgenerateGenesis
- Force regen with flag
- ✅ Integrates zeam, ream, qlean (and more incoming...)
- ✅ Configure to run clients in docker or binary mode for easy development
- ✅ Linux & Mac compatible & tested
- ✅ Option to operate on single or multiple nodes or
all
- Shell terminal: Preferably linux especially if you want to pop out separate new terminals for node
- Docker: Required to run PK's eth-beacon-genesis tool and hash-sig-cli for post-quantum keys
- Install from: Docker Desktop
- yq: YAML processor for automated configuration parsing
- Install on macOS:
brew install yq - Install on Linux: See yq installation guide
- Install on macOS:
# 1. Clone the repository
git clone <repo-url>
cd lean-quickstartNETWORK_DIR=local-devnet ./spin-node.sh --node all --generateGenesis --popupTerminal# Run only zeam_0 and ream_0 nodes (comma-separated)
NETWORK_DIR=local-devnet ./spin-node.sh --node zeam_0,ream_0 --generateGenesis --popupTerminal
# Run only zeam_0 and qlean_0 nodes (space-separated)
NETWORK_DIR=local-devnet ./spin-node.sh --node "zeam_0 qlean_0" --generateGenesis --popupTerminal
# Run only a single node
NETWORK_DIR=local-devnet ./spin-node.sh --node zeam_0 --generateGenesis --popupTerminal-
NETWORK_DIRis an env to specify the network directory. Should have agenesisdirectory with genesis config. Adatafolder will be created inside thisNETWORK_DIRif not already there.genesisdirectory should have the following filesa.
validator-config.yamlwhich has node setup information for all the bootnodes b.validators.yamlwhich assigns validator indices c.nodes.yamlwhich has the enrs generated for each of the respective nodes. d.config.yamlthe actual network config -
--generateGenesisregenerate all genesis files with fresh genesis time and clean data directories -
--popupTerminalif you want to pop out new terminals to run the nodes, opens gnome terminals -
--nodespecify which node(s) you want to run:- Use
allto run all the nodes in a single go - Specify a single node name (e.g.,
zeam_0) to run just that node - Use comma-separated node names (e.g.,
zeam_0,qlean_0) to run multiple specific nodes - Use whitespace-separated node names (e.g.,
"zeam_0 ream_0") to run multiple specific nodes
The client is provided this input so as to parse the correct node configuration to startup the node.
- Use
-
--validatorConfigis the path to specify your nodesvalidator-config.yaml,validators.yaml(for which--nodeis still the node key to index) if your node is not a bootnode. If unspecified it assumes value ofgenesis_bootnodewhich is to say that your node config is to be picked fromgenesisfolder with--nodeas the node key index. This value is further provided to the client so that they can parse the correct config information.
The quickstart includes an automated genesis generator that eliminates the need for hardcoded validators.yaml and nodes.yaml files.
Current following clients are supported:
- Zeam
- Ream
- Qlean
However adding a lean client to this setup is very easy. Feel free to do the PR or reach out to the maintainers.
The genesis generator (generate-genesis.sh) uses PK's official eth-beacon-genesis docker tool to automatically generate:
- validators.yaml - Validator index assignments using round-robin distribution
- nodes.yaml - ENR (Ethereum Node Records) for peer discovery
- genesis.json - Genesis state in JSON format
- genesis.ssz - Genesis state in SSZ format
- .key files - Private key files for each node
Docker Image: ethpandaops/eth-beacon-genesis:pk910-leanchain
Source: ethpandaops/eth-beacon-genesis#36
config.yaml is also generated from scratch with the appropriate properties populated.
The genesis generator runs automatically when:
validators.yamlornodes.yamldon't exist, OR- You use the
--generateGenesisflag
# Regenerate genesis files with fresh genesis time
NETWORK_DIR=local-devnet ./spin-node.sh --node all --generateGenesisYou can also run the generator standalone:
./generate-genesis.sh local-devnet/genesisThis quickstart includes integrated support for post-quantum secure hash-based signatures for validator keys. The system automatically generates and manages hash-sig keys during genesis generation.
The genesis generator automatically:
- Uses Docker image
blockblaz/hash-sig-cli:latestto generate hash-sig keys - Generates hash-sig keys for N validators (Step 1 of genesis generation)
- Stores keys in
genesis/hash-sig-keys/directory - Loads keys automatically when nodes start via environment variables
When you run the genesis generator, it creates post-quantum secure keys for each validator:
./generate-genesis.sh local-devnet/genesisGenerated files:
local-devnet/genesis/hash-sig-keys/
├── validator-keys-manifest.yaml # Metadata for all keys
├── validator_0_pk.json # Public key for validator 0
├── validator_0_sk.json # Secret key for validator 0
├── validator_1_pk.json # Public key for validator 1
├── validator_1_sk.json # Secret key for validator 1
└── ... # Keys for additional validators
The system uses the SIGTopLevelTargetSumLifetime32Dim64Base8 hash-based signature scheme, which provides:
- Post-quantum security: Resistant to attacks from quantum computers
- Active epochs: 2^18 (262,144 signatures)
- Total lifetime: 2^32 (4,294,967,296 signatures)
- Stateful signatures: Uses hierarchical signature tree structure
The validator-config.yaml file defines the shuffle algorithm, active epoch configuration, and validator specifications:
shuffle: roundrobin
config:
activeEpoch: 18 # Required: Exponent for active epochs (2^18 = 262,144 signatures)
keyType: "hash-sig" # Required: Network-wide signature scheme (hash-sig for post-quantum security)
validators:
- name: "zeam_0"
privkey: "bdf953adc161873ba026330c56450453f582e3c4ee6cb713644794bcfdd85fe5"
enrFields:
ip: "127.0.0.1"
quic: 9000
metricsPort: 8080
count: 1Required Top-Level Fields:
shuffle: Validator shuffle algorithm (e.g.,roundrobin)config.activeEpoch: Exponent for active epochs used in hash-sig key generation (2^activeEpoch signatures per active period)config.keyType: Network-wide signature scheme - must be"hash-sig"for post-quantum security
Validator Fields:
- Hash-sig key files are automatically mapped based on validator position in the array (first validator uses
validator_0_*.json, second usesvalidator_1_*.json, etc.)
The parse-vc.sh script automatically loads hash-sig keys when starting nodes:
- Reads
config.keyTypefrom validator config (network-wide setting) - Automatically calculates key index based on validator position in the array
- Locates corresponding key files in
genesis/hash-sig-keys/ - Exports environment variables for client use:
HASH_SIG_PK_PATH: Path to public key fileHASH_SIG_SK_PATH: Path to secret key fileHASH_SIG_KEY_INDEX: Validator's key index (auto-calculated)
Client Integration:
Your client implementation should read these environment variables and use the hash-sig keys for validator operations.
Each hash-sig key has a finite lifetime of 2^32 signatures. The keys are structured as:
- Active epochs: 2^18 epochs before requiring key rotation
- Total lifetime: 2^32 total signatures possible
Hash-based signatures are stateful - each signature uses a unique one-time key from the tree. Once exhausted, keys must be rotated:
# Regenerate all hash-sig keys
./generate-genesis.sh local-devnet/genesisWarning: Keep track of signature counts to avoid key exhaustion.
Secret keys are highly sensitive:
⚠️ Never commitvalidator_*_sk.jsonfiles to version control⚠️ Never share secret keys- ✅ Backup secret keys in secure, encrypted storage
- ✅ Restrict permissions on key files (e.g.,
chmod 600)
The .gitignore should already exclude hash-sig keys:
local-devnet/genesis/hash-sig-keys/
The manifest file (validator-keys-manifest.yaml) contains metadata about all generated keys:
# Hash-Sig Validator Keys Manifest
# Generated: 2024-01-15T10:30:00Z
scheme: "SIGTopLevelTargetSumLifetime32Dim64Base8"
activeEpochs: 262144 # 2^18
totalLifetime: 4294967296 # 2^32
validatorCount: 3
validators:
- index: 0
publicKey: "validator_0_pk.json"
secretKey: "validator_0_sk.json"
- index: 1
publicKey: "validator_1_pk.json"
secretKey: "validator_1_sk.json"
# ... additional validatorsProblem: Hash-sig keys not loading during node startup
Warning: Hash-sig public key not found at genesis/hash-sig-keys/validator_0_pk.json
Solution: Run the genesis generator to create keys:
./generate-genesis.sh local-devnet/genesisProblem: Hash-sig key file not found
Warning: Hash-sig secret key not found at genesis/hash-sig-keys/validator_5_sk.json
Solution: This usually means you have more validators configured than hash-sig keys generated. Regenerate genesis files:
./generate-genesis.sh local-devnet/genesisThis quickstart includes automated configuration parsing:
- Official Genesis Generation: Uses PK's
eth-beacon-genesisdocker tool from PR #36 - Complete File Set: Generates
validators.yaml,nodes.yaml,genesis.json,genesis.ssz, and.keyfiles - QUIC Port Detection: Automatically extracts QUIC ports from
validator-config.yamlusingyq - Node Detection: Dynamically discovers available nodes from the validator configuration
- Private Key Management: Automatically extracts and creates
.keyfiles for each node - Error Handling: Provides clear error messages when nodes or ports are not found
The system reads all configuration from YAML files, making it easy to add new nodes or modify existing ones without changing any scripts.
Clients can maintain their own branches to integrated and use binay with their repos as the static targets (check git diff main zeam_repo). And those branches can be rebased as per client convinience whenever the main code is updated.