Run a Validator
Setup Guide

Setting Up Your GenLayer Validator

Running a GenLayer Validator node ensures the security and reliability of the GenLayer network. Below are the requirements for running a GenLayer validator.

For a deeper understanding of how staking works in GenLayer, see the Staking documentation.

Create the Validator Wallet

Before setting up your validator node, you need to create your validator wallet and stake GEN tokens.

Understanding Validator Addresses

GenLayer validators use three distinct addresses:

AddressDescriptionWhere Used
OwnerThe only address that can withdraw staked funds. Keep this secure (cold wallet).CLI wizard - signs staking transaction
OperatorHot wallet on your server that signs blocks. Can be same as owner, but separate is recommended.Node config: operatorAddress
Validator WalletSmart contract created when you join. This is your validator's on-chain identity.Node config: validatorWalletAddress

The wizard outputs all three addresses at the end. Save them - you'll need the Validator Wallet and Operator addresses for your node configuration.

Prerequisites

  • Node.js (v18 or higher)
  • GenLayer CLI - Install the latest version:
    npm install -g genlayer
  • GEN tokens - You need at least 42,000 GEN for the minimum self-stake requirement

Using the Validator Wizard

The easiest way to create your validator wallet is using the interactive wizard:

genlayer staking wizard

The wizard guides you through:

  1. Account setup - Create or select your owner account
  2. Network selection - Choose testnet-asimov
  3. Balance verification - Confirms you have at least 42,000 GEN
  4. Operator setup - Create and export an operator keystore for your validator server
  5. Stake amount - Enter how much GEN to stake (minimum 42,000)
  6. Validator creation - Submits the staking transaction
  7. Identity setup - Set your validator's public profile (moniker, website, etc.)

Save Your Validator Wallet Address! After the wizard completes, note down your Validator Wallet address. You'll need this for your node configuration.

Operator Keystore Export

The wizard creates and exports an operator keystore file for you to transfer to your validator server. If your server is compromised, your staked funds (controlled by owner) remain safe.

Verify Your Validator

After completing the wizard, verify your status:

genlayer staking validator-info --validator 0xYourValidatorWallet...

Managing Your Validator

# Add more stake
genlayer staking validator-deposit --amount 1000gen
 
# Check active validators
genlayer staking active-validators
 
# Exit (initiates 7-epoch unbonding)
genlayer staking validator-exit --shares 100
 
# Claim after unbonding period
genlayer staking validator-claim
 
# Update identity
genlayer staking set-identity --validator 0x... --moniker "New Name"

Set Up the Validator Node

Once your validator wallet is created and staked, set up your node software.

Dependencies

LLM Access

Each validator needs access to a Large Language Model (LLM) for executing and evaluating Intelligent Contracts.

It is up to each validator to select the model they want to use.

Possible options:

  • Run an open-source model locally on the same machine with a GPU
  • Run an open-source model on a different machine
  • Connect to a hosted inference provider (OpenAI, Anthropic, Heurist, Atoma network etc.)

ZKSync Full Node for the GenLayer Chain

Each validator needs access to a ZKSync Full Node (opens in a new tab) connected to the GenLayer chain. Validators use this node to read the chain state and submit transactions.

One full node can be shared between multiple validators. The optimal validator-to-node ratio is currently under evaluation.

System Requirements

Below are the initial recommended system requirements. These guidelines may change as the network grows and evolves.

RAM

  • Recommended: 16 GB
  • Why:
    • GenLayer's genvm can spawn multiple Sub-VMs for contract calls and non-deterministic blocks.
    • Each Sub-VM can consume up to ~4 GB of RAM for storage.

CPU

  • Recommended: Modern multi-core processor with at least 8 cores/16 threads

Architecture

  • Recommended: AMD64
  • ARM64 is not supported at this time

Storage

  • Recommended Disk Space: 128 GB+
  • Preferred Type: SSD or NVMe (M.2)

Network

  • 100 Mbps connection
  • Recommended:: 1 Gbps+

GPU (Optional)

  • GPU is Not Required
  • If you want to run LLMs locally, you will need to select appropriate hardware (typically a CUDA-compatible GPU with sufficient VRAM for the model you intend to use)
⚠️

These requirements are a starting point. As GenLayer evolves and usage patterns change (e.g., more complex AI-driven Intelligent Contracts), the recommended hardware may change.

Software

  • Operating System - 64-bit Linux (Ubuntu, Debian, CentOS, etc.)
  • docker - for running the WebDriver container
  • python3, python3-pip and python3-venv for GenVM setup

Setup

Download the node software

  1. Select the version of the node you want to run by checking the available builds

    You can use this command to list available versions:

    curl -s "https://storage.googleapis.com/storage/v1/b/gh-af/o?prefix=genlayer-node/bin/amd64" | grep -o '"name": *"[^"]*"' | sed -n 's/.*\/\(v[^/]*\)\/.*/\1/p' | sort -ru

    You should see a list like this

       v0.4.0
       v0.3.11
       v0.3.10
       v0.3.9
       v0.3.8
       v0.3.7
       v0.3.6
       v0.3.5
       v0.3.4
       v0.3.3
       v0.3.2
       v0.3.1
       v0.3.0
       v0.2.0-testnet007
       v0.2.0-testnet005
       v0.2.0-testnet004
       v0.2.0-testnet003
       v0.2.0-testnet002
       v0.2.0-testnet001

    Typically, you will want to run the latest version

  2. Download the packaged application

    export version=v0.4.0 # set your desired version here
    wget https://storage.googleapis.com/gh-af/genlayer-node/bin/amd64/${version}/genlayer-node-linux-amd64-${version}.tar.gz
  3. Extract the node software

    mkdir -p ${version}
    tar -xzvf `genlayer-node-linux-amd64-${version}.tar.gz` -C `./${version}`
  4. Change the directory

    cd `./${version}`
  5. Run Genvm setup

    python3 ./third_party/genvm/bin/setup.py

Configuration

Before you can start up the node, you need to configure it.

config.yaml

This is the main configuration file of your node. Without it, your node won't start

The file needs to be located at configs/node/config.yaml

You can use the following example configuration. Note: For most users, you will only need to modify the zksyncurl and zksyncwebsocketurl values below.

# rollup configuration
rollup:
  genlayerchainrpcurl: "TODO: Set your GenLayer Chain ZKSync HTTP RPC URL here" # ZKSync RPC URL
  genlayerchainwebsocketurl: "TODO: Set your GenLayer Chain ZKSync WebSocket RPC URL here" # ZKSync WebSocket URL
# consensus contracts configuration
consensus:
  # Asimov - Phase 4
  contractmainaddress: "0x67fd4aC71530FB220E0B7F90668BAF977B88fF07" # ConsensusMain Smart Contract Address
  contractdataaddress: "0xB6E1316E57d47d82FDcEa5002028a554754EF243" # ConsensusData Smart Contract Address
  genesis: 4632386 # (Optional) Genesis block number for this consensus deployment. If not provided, it will be auto-detected by searching for the first log from the ConsensusMain contract.
 
# data directory
datadir: "./data/node"
 
# logging configuration
logging:
  level: "INFO"
  # json: `true` for json output to console, false for human readable log formatting
  json: false
  # Configuration for https://github.com/natefinch/lumberjack
  file:
    # enabled: set to `true` to save logs to a folder
    enabled: true
    level: "DEBUG"
    # folder: path to the folder where to store logs. Relative paths go under `datadir`.
    folder: logs
    # maxsize: maximum size in megabytes of the log file before it gets rotated.
    maxsize: 10
    # maxage: maximum number of days to retain old log files based on the timestamp encoded in their filename.
    maxage: 7
    # maxbackups: maximum number of old log files to retain. Set to 0 for no limit
    maxbackups: 100
    # localtime: determines if the time used for formatting the timestamps in backup files is the computer's local time. Set to `false` to use UTC time.
    localtime: false
    # compress: determines if the rotated log files should be compressed using gzip
    compress: true
 
# node configuration
node:
  # Uncomment if the ID of the node is different from the validator wallet address.
  # It is used to identify the node in the network.
  # id: "node"
  # Mode can be "validator" or "full".
  # Default value is "validator".
  mode: "validator"
  # Address of the ValidatorWallet contract (required for validator mode)
  validatorWalletAddress: ""
  # Address of the operator that owns the ValidatorWallet
  operatorAddress: ""
  admin:
    port: 9155
  rpc:
    port: 9151 # RPC server port
    endpoints:
      # Group-level configuration (enables/disables all methods in a group)
      groups:
        genlayer: true         # gen_* methods (call, getContractSchema, etc.)
        genlayer_debug: true   # gen_dbg_* methods (ping, load_test, trie)
        ethereum: true         # eth_* proxy methods
        zksync: true           # zks_* proxy methods
      # Method-level configuration (overrides group settings for specific methods)
      methods:
        gen_call: true
        gen_getContractSchema: true
        gen_getTransactionStatus: true
        gen_getTransactionReceipt: true
        gen_dbg_ping: true
        gen_dbg_load_test: true
        eth_blockNumber: true
        eth_getBlockByNumber: true
        eth_getBlockByHash: true
        eth_sendRawTransaction: true
        zks_getTransaction: true
  ops:
    port: 9153 # Metrics port
    endpoints:
      metrics: true # Enable metrics endpoint
      health: true # Enable health endpoint
      balance: true # Enable balance endpoint
 
# genvm configuration
genvm:
  root_dir: ./third_party/genvm
  start_manager: true # if true node will start genvm manager itself
  manager_url: http://127.0.0.1:3999
  permits: # Leave empty for autodiscovery, put a number for updating genvm permits on startup
 
# Advanced configuration
merkleforest:
  maxdepth: 16
  dbpath: "./data/node/merkle/forest/data.db"
  indexdbpath: "./data/node/merkle/index.db"
merkletree:
  maxdepth: 16
  dbpath: "./data/node/merkle/tree/"
 
# metrics configuration
metrics:
  interval: "15s"  # Default interval for all collectors (can be overridden per collector)
#   collectors:
#     node:
#       enabled: true
#       # interval: "30s"  # Optional: Override default interval for this collector
#     genvm:
#       enabled: true
#       # interval: "20s"  # Optional: Override default interval for this collector
#       # enable_simulated_traffic: false  # Optional: Enable simulated network traffic metrics for GenVM processes (default: false)
#       # simulated_rx_bytes_per_process: 1024  # Optional: Simulated received bytes per process per interval (default: 1024)
#       # simulated_tx_bytes_per_process: 512   # Optional: Simulated transmitted bytes per process per interval (default: 512)
#     webdriver:
#       enabled: true
#       # interval: "60s"  # Optional: Override default interval for this collector
 

Overriding Configuration with Environment Variables

Any configuration value in config.yaml can be overridden using environment variables with the prefix GENLAYERNODE_.

Pattern:

  • Replace dots (.) with underscores (_)
  • Convert to uppercase
  • Add the GENLAYERNODE_ prefix

Examples:

Config KeyEnvironment Variable
rollup.genlayerchainrpcurlGENLAYERNODE_ROLLUP_GENLAYERCHAINRPCURL
rollup.genlayerchainwebsocketurlGENLAYERNODE_ROLLUP_GENLAYERCHAINWEBSOCKETURL
consensus.contractmainaddressGENLAYERNODE_CONSENSUS_CONTRACTMAINADDRESS
consensus.contractdataaddressGENLAYERNODE_CONSENSUS_CONTRACTDATAADDRESS
consensus.genesisGENLAYERNODE_CONSENSUS_GENESIS
node.modeGENLAYERNODE_NODE_MODE
node.validatorWalletAddressGENLAYERNODE_NODE_VALIDATORWALLETADDRESS
node.operatorAddressGENLAYERNODE_NODE_OPERATORADDRESS
node.rpc.portGENLAYERNODE_NODE_RPC_PORT
logging.levelGENLAYERNODE_LOGGING_LEVEL

Usage example:

# Override the RPC port
export GENLAYERNODE_CONSENSUS_CONTRACTMAINADDRESS="0x..."
 
# Set validator wallet address
export GENLAYERNODE_NODE_VALIDATORWALLETADDRESS="0x..."
 
# Set logging level
export GENLAYERNODE_LOGGING_LEVEL="DEBUG"

Environment variables take precedence over values in config.yaml, making them ideal for Docker deployments or sensitive values you don't want in configuration files.

GenVM Configuration

You need to set up an LLM for your node to use to provide answers to natural language prompts. You can use any LLM you wish, however the quality of its answers will affect the performance of your node.

💡

GenLayer has partnered with multiple LLM providers to offer free credits for validators:

Heurist (opens in a new tab) - A Layer 2 network for AI model hosting and inference, built on the ZK Stack. It offers serverless access to open-source AI models through a decentralized network. GenLayer Validators can obtain free Heurist API credits (opens in a new tab) by using the referral code: "genlayer".

Comput3 (opens in a new tab) - A decentralized compute network providing access to various AI models. GenLayer Validators can use the Comput3.ai inferencing API with access to llama3, hermes3 and qwen3 models. Validators can obtain free Comput3 API credits (opens in a new tab) to get started with their validator setup.

io.net - A decentralized compute network providing GPU access for AI inference. GenLayer Validators can create an account at id.io.net (opens in a new tab) and obtain free credits by filling out this form (opens in a new tab).

The GenVM configuration files are located at third_party/genvm/config/

genvm-module-llm.yaml

This is the configuration file of the LLM module. In this file you can set up and configure various LLM providers, as well as the system prompts of your validator.

You can turn on and off various LLMs by setting the enabled field to false.

At this stage, select one LLM and set all other to disabled.

Note environment variable names for LLM API keys (e.g., HEURISTKEY, COMPUT3KEY, IOINTELLIGENCE_API_KEY). You will need to ensure the appropriate key is correctly set before running the node.

genvm-module-web.yaml

This is the configuration of webdriver module that enables the GenVM to access the internet. You should not need to modify this.

genvm.yaml

This is the configuration of the GenVM itself, such as how many threads it can use and what are the addresses of various modules. You should not need to edit this file either.

Precompilation (Recommended)

Run precompilation of pre-delivered wasm modules (this step is optional but highly recommended for improved performance):

./third_party/genvm/bin/genvm precompile

Precompilation should be re-run after switching to a different node release.

Greyboxing LLMs

Greyboxing is a way to further customise your LLM setup to improve its performance as well as security.

💡

Greyboxing is an advanced feature. Familiarity with Lua scripting and LLM prompt engineering is recommended for customization.

genvm-modules llm provides user with ability to customize greyboxing via lua scripting. Right now users can customize prompt templates, specify temperature and system prompt.

Related scripts are located at:

  1. ./scripts/genvm-greyboxing.lua – user defined script
  2. ./share/lib/genvm/greyboxing/lib-greyboxing.lua – more low-level library
🏗️

More features and built-in filters will be added soon

Import the Operator Key

The operator key is used by your node to sign blocks and perform validator duties.

Option 1: Import from CLI Wizard (Recommended)

If you used genlayer staking wizard, it exported an operator keystore file. Transfer this file to your validator server and import it:

./bin/genlayernode account import \
  --password "your node password" \
  --passphrase "password you set when exporting from wizard" \
  --path "/path/to/operator-keystore.json" \
  -c $(pwd)/configs/node/config.yaml \
  --setup

You should see:

Account imported:
  Address: 0xA0b12Fd2f3F7e86fEC458D114A5E7a6f571160a8
  Account setup as a validator

Option 2: Generate New Operator Key

You can also generate a new operator key directly on the server:

./bin/genlayernode account new -c $(pwd)/configs/node/config.yaml --setup --password "your secret password"

Then use this address when running the wizard on your local machine.

Restoring Your Operator Key

To restore from a backup (e.g., after migrating to a new server):

./bin/genlayernode account import \
  --password "your node password" \
  --passphrase "your backup encryption passphrase" \
  --path "/path/to/your/secure/backup.key" \
  -c $(pwd)/configs/node/config.yaml \
  --setup
🚨

Always verify that your imported key works by checking the operator address matches what's configured for your validator.

Backing Up Your Operator Key

After setting up your operator key, back it up securely:

./bin/genlayernode account export \
  --password "your node password" \
  --address "your operator address" \
  --passphrase "your backup encryption passphrase" \
  --path "/path/to/your/secure/backup.key" \
  -c $(pwd)/configs/node/config.yaml
🚨

Important: Back up your operator key! Losing access means you'll need to set up a new operator and update your validator configuration. Store the backup securely.

To print the private key from your backup file, use the --print flag. Keep this private key secure and never share it.

Running the node

Once you have configured everything, you are ready to start the node.

🚨

Important: Before starting the node, ensure you have:

  1. Operator key imported into the node (see "Import the Operator Key" above)
  2. Validator wallet address - obtained after joining as validator via genlayer staking wizard or validator-join

Without both configured, your node will run as a full node instead of a validator.

Running the Node using the binary

  1. Set the LLM Provider API Key

    Set the appropriate environment variable for your chosen LLM provider:

    # For Heurist
    export HEURISTKEY='your_heurist_api_key'
     
    # For Comput3
    export COMPUT3KEY='your_comput3_api_key'
     
    # For io.net
    export IOINTELLIGENCE_API_KEY='your_ionet_api_key'
     
    # For other providers, use the appropriate environment variable name
  2. Run the WebDriver container

    docker compose up -d # Starts the WebDriver needed by the GenVM web module
  3. (Optional) Run two services (modules) in background (this is a crucial step for running Intelligent contracts). This can be done automatically or manually.

    • To start them automatically in node configuration set genvm.manage_modules to true
    • To start them manually run
       ./third_party/genvm/bin/genvm-modules web & ./third_party/genvm/bin/genvm-modules llm &

Note: If you are using the default configuration, genvm.manage_modules is set to true by default, meaning the node will manage these modules automatically.

  1. Checking Your Configuration

    To ensure your node is correctly configured, you can run the following command:

    ./bin/genlayernode doctor

    The doctor command now includes comprehensive GenVM diagnostics integration to validate:

    • Consensus contract configuration and accessibility
    • GenVM module connectivity and health status
    • LLM provider configuration and API connectivity
    • Network configuration and ZKSync node accessibility
  2. Run the node

    ./bin/genlayernode run -c $(pwd)/configs/node/config.yaml --password "your secret password" # The same password you used when creating the account

If you are running the node via SSH, the process might terminate if your connection drops. To prevent this, consider using a terminal multiplexer like screen or tmux to keep the node running in the background even if your SSH session ends. You can find a guide on using screen here (opens in a new tab).

Running the Node using docker-compose

You can also run the GenLayer node using Docker and Docker Compose.

  1. Create a docker-compose.yaml file with the following content:
services:
  webdriver-container:
    container_name: genlayer-node-webdriver
    image: yeagerai/genlayer-genvm-webdriver:0.0.9
    shm_size: 2gb
    security_opt:
      - no-new-privileges:true
    environment:
      PORT: 4444
    ports:
      - "${WEBDRIVER_PORT:-4444}:4444"
    restart: unless-stopped
 
  genlayer-node:
    image: yeagerai/genlayer-node:${NODE_VERSION:-v0.4.0}
    entrypoint: [
      "sh", "-c", "/app/bin/genlayernode run --password ${NODE_PASSWORD:-12345678}",
    ]
    container_name: genlayer-node
    restart: unless-stopped
    env_file:
      - path: ./.env
        required: false
    ports:
      - "${NODE_RPC_PORT:-9151}:9151"
      - "${NODE_OPS_PORT:-9153}:9153"
    volumes:
      - ${NODE_CONFIG_PATH:-./configs/node/config.yaml}:/app/configs/node/config.yaml:ro
      - ${NODE_DATA_PATH:-./data}:/app/data
      - ./genvm-module-web-docker.yaml:/app/third_party/genvm/config/genvm-module-web.yaml
    security_opt:
      - no-new-privileges:true
    logging:
      driver: "json-file"
      options:
        max-size: "100m"
        max-file: "3"
        compress: "true"
    depends_on:
      - webdriver-container
    profiles:
      - node
 
  1. Create genvm-module-web-docker.yaml for Docker networking:

The extracted tarball includes third_party/genvm/config/genvm-module-web.yaml configured for localhost, which works when running the binary directly. For docker-compose, you need a version that points to the webdriver service name.

Create genvm-module-web-docker.yaml in the same directory as your docker-compose.yaml:

  • Copy the contents of third_party/genvm/config/genvm-module-web.yaml into genvm-module-web-docker.yaml.
  • Modify the webdriver_host configuration to use the service name webdriver-container instead of localhost:
webdriver_host: http://webdriver-container:4444

This allows the node container to reach the webdriver container using Docker's internal networking.

The key difference:

  • Binary execution: uses localhost:4444 (webdriver runs on same machine)
  • Docker-compose: uses webdriver-container:4444 (container service name)
  1. Set the required environment variables in a .env file:

This .env file serves two purposes: it configures Docker Compose variables (like NODE_VERSION, NODE_PASSWORD, ports) and can also include GENLAYERNODE_* variables to override node configuration values as described in Overriding Configuration with Environment Variables.

# GenLayer Node Release Configuration

# =============================================================================
# WebDriver Configuration (required for GenVM)
# =============================================================================
WEBDRIVER_PORT=4444

# =============================================================================
# Node Service Configuration (optional - use node profile)
# =============================================================================
# Docker image version
NODE_VERSION=v0.4.0

# Keystore password (used to unlock the pre-imported wallet)
NODE_PASSWORD=12345678

# Path to node configuration file
NODE_CONFIG_PATH=./configs/node/config.yaml

# Path to node data directory (for persistence)
NODE_DATA_PATH=./data

# Port mappings
NODE_RPC_PORT=9151
NODE_OPS_PORT=9153

# LLM API Key (required for GenVM LLM module)
HEURISTKEY=
ANTHROPICKEY=
XAIKEY=
GEMINIKEY=
ATOMAKEY=

or simply use the provided docker-compose.yaml, .env.example and the genvm-module-web-docker.yaml from the extracted tarball.

  1. Checking Your Configuration

To ensure your node is correctly configured, you can run the following command:

source .env && docker run --rm --env-file ./.env \
  -v ${NODE_CONFIG_PATH:-./configs/node/config.yaml}:/app/configs/node/config.yaml \
  yeagerai/genlayer-node:${NODE_VERSION:-v0.4.0} \
  ./bin/genlayernode doctor
  1. Start the services using Docker Compose:
source .env && docker compose --profile node up -d

Monitoring with Metrics

GenLayer validators expose comprehensive metrics that are ready for consumption by Prometheus and other monitoring tools. This allows you to monitor your validator's performance, health, and resource usage.

Accessing Metrics

The metrics endpoint is exposed on the operations port (default: 9153) configured in your config.yaml:

node:
  ops:
    port: 9153 # Metrics port
    endpoints:
      metrics: true # Enable metrics endpoint

Once your node is running, you can access the metrics at:

http://localhost:9153/metrics

Available Metrics

The validator exposes various metric collectors that can be individually configured:

  • Node Metrics: Core validator performance metrics including block processing, transaction handling, and consensus participation
  • GenVM Metrics: Virtual machine performance metrics, including execution times and resource usage
  • WebDriver Metrics: Metrics related to web access and external data fetching

Configuring Metrics Collection

You can customize metrics collection in your config.yaml:

metrics:
  interval: "15s"  # Default collection interval
  collectors:
    node:
      enabled: true
      interval: "30s"  # Override interval for specific collector
    genvm:
      enabled: true
      interval: "20s"
    webdriver:
      enabled: true
      interval: "60s"

Example Metrics Query

To check if metrics are working correctly:

# Get all available metrics
curl http://localhost:9153/metrics
 
# Check specific metric (example)
curl -s http://localhost:9153/metrics | grep genlayer_node_

The metrics endpoint also provides /health and /balance endpoints on the same port for additional monitoring capabilities.

Monitoring Best Practices

  1. Set up alerts for critical metrics like node synchronization status and missed blocks
  2. Monitor resource usage to ensure your validator has sufficient CPU, memory, and disk space
  3. Track GenVM performance to optimize LLM provider selection and configuration
  4. Use visualization tools like Grafana to create dashboards for easy monitoring
📊

For production validators, we recommend setting up a complete monitoring stack with Prometheus and Grafana. This enables real-time visibility into your validator's performance and helps identify issues before they impact your validator's operation.

Logs and metrics forwarding

You can forward your logs and metrics to external systems for centralized monitoring and alerting by using the service alloy provided in the docker-compose.yaml from the extracted tarball.