Validator Guide
Run a MoltChain validator node to participate in consensus, produce blocks, and earn staking rewards. This guide covers hardware requirements, installation, configuration, staking, monitoring, and production deployment.
Requirements
Hardware
Operating System
- Production: Linux — Ubuntu 22.04 LTS or newer (Debian, RHEL 9+ also supported)
- Development: macOS (Apple Silicon or Intel)
Network Ports
| Network | P2P (QUIC) | RPC (HTTP) | WebSocket | Signer |
|---|---|---|---|---|
| Testnet | 7001 | 8899 | 8900 | 9201 |
| Mainnet | 8001 | 9899 | 9900 | 9201 |
Installation
Option A: Quick Start (Recommended)
Clone the repository, build, and start a validator in one go:
git clone https://github.com/moltchain/moltchain.git
cd moltchain
./moltchain-start.sh testnet
The start script will automatically build the binary, create genesis (if this is the first validator), deploy all 27 smart contracts, seed AMM pools, and fund the insurance reserve. Everything is idempotent — run it again and it picks up where it left off.
Port Assignments
| Network | RPC | WebSocket | P2P | Signer |
|---|---|---|---|---|
| Testnet | 8899 | 8900 | 7001 | 9201 |
| Mainnet | 9899 | 9900 | 8001 | 9201 |
You can run both testnet and mainnet on the same machine — they use different ports and separate data directories.
Joining an Existing Network
To join a network with existing validators, pass a bootstrap peer:
./moltchain-start.sh testnet --bootstrap seed1.moltchain.io:7001
Stop / Restart
# Stop
./moltchain-stop.sh testnet
# Full reset (wipe all state and start fresh)
./reset-blockchain.sh testnet
./moltchain-start.sh testnet
Option B: Build from Source (Manual)
If you prefer manual control, build the binary and run it directly. Requires Rust 1.75+ stable toolchain.
git clone https://github.com/moltchain/moltchain.git
cd moltchain
cargo build --release
# Start — the built-in supervisor auto-restarts on stalls/crashes
./target/release/moltchain-validator \
--network testnet \
--rpc-port 8899 \
--ws-port 8900 \
--p2p-port 7001 \
--db-path ./data/state-testnet-7001
# Disable the supervisor (e.g. when using systemd Restart=on-failure)
./target/release/moltchain-validator --no-watchdog \
--network testnet --rpc-port 8899 --p2p-port 7001
Option C: Docker
docker-compose up validator
See the Docker Deployment section below for full details.
Initialize Validator Identity
Generate a validator keypair. This Ed25519 key is your node's on-chain identity. The start script does this automatically, but you can also do it manually:
molt init --output ~/.moltchain/validator-keypair.json
New validator keypair generated
Identity: Mo1tVa1idAtoR...xYz789
Saved to: ~/.moltchain/validator-keypair.json
Configuration
MoltChain validators are currently configured via CLI flags when starting the binary. The section labels below (for example [network] and [rpc]) are conceptual groupings for readability, not literal TOML sections consumed by the validator today. A real config.toml input format is planned for a future release.
--network, --p2p-port, --rpc-port, --ws-port, --db-path, --keypair, --bootstrap, --bootstrap-peers, --admin-token, --no-watchdog, --watchdog-timeout, --max-restarts, --dev-mode, --import-key. They are documentation aliases, not direct TOML keys parsed by the current binary.
[validator]
Core validator identity and data paths.
| Key | Type | Default | Description |
|---|---|---|---|
keypair_path |
String | ~/.moltchain/validator-keypair.json |
Path to the validator Ed25519 keypair JSON file. Generate with molt init. |
data_dir |
String | ~/.moltchain/data |
Directory for blockchain state, ledger, and snapshots. |
enable_validation |
Boolean | true |
Set to false to run as a full-node observer (no block production). |
[network]
Peer-to-peer networking and gossip settings.
| Key | Type | Default | Description |
|---|---|---|---|
p2p_port |
Integer | 7001 |
QUIC transport listening port for P2P gossip and block propagation. Testnet default: 7001, Mainnet: 8001. |
rpc_port |
Integer | 8899 |
JSON-RPC HTTP server port. Testnet default: 8899, Mainnet: 9899. |
seed_nodes |
Array | [] |
Bootstrap peers. Testnet: ["seed1.moltchain.io:7001", "seed2.moltchain.io:7001"] |
enable_p2p |
Boolean | true |
Enable P2P networking. Disable for local-only testing. |
gossip_interval |
Integer | 10 |
Gossip protocol interval in seconds. |
cleanup_timeout |
Integer | 300 |
Seconds before cleaning up stale peer connections. |
[consensus]
BFT consensus and staking parameters.
| Key | Type | Default | Description |
|---|---|---|---|
min_validator_stake |
Integer | 75000000000000 |
Minimum stake in shells (1 MOLT = 1,000,000,000 shells). 75,000 MOLT (75K) minimum to participate in consensus. Bootstrap validators receive a 100,000 MOLT grant (25K buffer above minimum); validator 201+ must self-fund at least 75,000 MOLT. |
slot_duration_ms |
Integer | 400 |
Target block slot time in milliseconds. MoltChain targets ~2,500 TPS at 400ms slots. |
enable_slashing |
Boolean | true |
Enable slashing for double-signing and other protocol violations. |
[graduation]
Validator graduation and anti-fraud settings (CLI flags).
| Flag | Type | Default | Description |
|---|---|---|---|
--dev-mode |
Boolean | false |
Skip machine fingerprint uniqueness check. Allows multiple validators per machine (for local testing). Uses SHA-256(pubkey) as fingerprint. Blocked on mainnet. |
--import-key <path> |
String | — | Import an existing keypair from another machine. Copies <path> to the validator's data directory. The validator resumes with its existing stake, debt, and progress. Fingerprint auto-updates on next announcement. |
--import-key /path/to/keypair.json. All progress (debt, earned rewards, blocks produced) is tied to the keypair, not the machine. The machine fingerprint auto-updates with a 2-day cooldown between migrations.
[rpc]
JSON-RPC server configuration.
| Key | Type | Default | Description |
|---|---|---|---|
enable_rpc |
Boolean | true |
Enable the JSON-RPC server. |
bind_address |
String | "0.0.0.0" |
Bind address. Use 127.0.0.1 for localhost-only access. |
enable_cors |
Boolean | true |
Enable Cross-Origin Resource Sharing for browser clients. |
max_connections |
Integer | 1000 |
Maximum concurrent RPC connections. |
[logging]
Logging verbosity and output targets.
| Key | Type | Default | Description |
|---|---|---|---|
level |
String | "info" |
Log level. One of: trace, debug, info, warn, error. |
log_to_file |
Boolean | false |
Write logs to a file in addition to stdout. |
log_file_path |
String | ~/.moltchain/validator.log |
Path to the log file (when log_to_file = true). |
log_format |
String | "text" |
Output format. "json" for structured logging (recommended for production). |
[monitoring]
Prometheus metrics and health checks.
| Key | Type | Default | Description |
|---|---|---|---|
enable_metrics |
Boolean | true |
Enable the Prometheus-compatible metrics HTTP endpoint. |
metrics_port |
Integer | 9100 |
Port for the Prometheus metrics server. |
enable_health_check |
Boolean | true |
Enable the /health HTTP endpoint for load balancers. |
[genesis]
Genesis block and chain identity.
| Key | Type | Default | Description |
|---|---|---|---|
genesis_path |
String | "./genesis.json" |
Path to the genesis configuration file. Required on first startup. |
chain_id |
String | "moltchain-testnet-1" |
Chain identifier. Must match the genesis file exactly. |
[performance]
Tuning options for throughput and resource usage.
| Key | Type | Default | Description |
|---|---|---|---|
worker_threads |
Integer | 0 |
Tokio worker threads. 0 = auto-detect CPU core count. |
optimize_block_production |
Boolean | true |
Enable block production optimizations (parallel tx execution, pipelining). |
tx_batch_size |
Integer | 1000 |
Maximum transactions per block batch. |
[security]
Security hardening and access control.
| Key | Type | Default | Description |
|---|---|---|---|
check_firewall |
Boolean | true |
Check that required ports are accessible on startup. |
require_encryption |
Boolean | false |
Require TLS for all RPC connections. |
allowed_rpc_methods |
Array | [] |
Whitelist of RPC methods. Empty = all methods enabled. |
rpc_rate_limit |
Integer | 100 |
Maximum RPC requests per second per client. |
admin_token |
String | "" |
Bearer token for admin RPC endpoints. Generate with openssl rand -hex 32. Empty = admin endpoints disabled. |
[watchdog]
Built-in self-healing supervisor. The validator automatically monitors itself for stalls (deadlocks, resource exhaustion) and restarts when needed. No external scripts or cron jobs required — just run the binary.
| Key | CLI Flag | Default | Description |
|---|---|---|---|
watchdog_timeout |
--watchdog-timeout |
120 |
Seconds of inactivity (no blocks produced or received) before the watchdog triggers a restart. |
max_restarts |
--max-restarts |
50 |
Maximum number of automatic restarts before the supervisor gives up and exits. Set to 0 for unlimited. |
no_watchdog |
--no-watchdog |
false |
Disable the built-in supervisor entirely. Use this when running under systemd or another process manager that handles restarts. |
--no-watchdog since systemd's Restart=on-failure already provides external supervision.
--network testnet, --p2p-port, and --rpc-port flags -- everything else uses sane defaults.
Staking
Validators must stake MOLT tokens to participate in consensus. Stake weight determines your share of block production slots and rewards.
Stake via CLI
$ molt validator register --rpc-url https://testnet-rpc.moltchain.io
Registering validator Mo1tVa1idAtoR...xYz789
Transaction: 5bN2...kQrT
Bootstrap: 100,000.000000000 MOLT (granted, #47 of 200)
Debt: 100,000.000000000 MOLT (repay via 50% of rewards, or 75% at ≥95% uptime)
Uptime: 98.5% (≥ 95% → 75/25 debt/liquid split)
Status: Finalized (slot 1,204,817)
Validator registered! Your node will enter the active set next epoch.
Minimum Stake
- Bootstrap Grant (first 200 validators): 100,000 MOLT (
100,000,000,000,000shells) — new validators receive this at $0 cost from the treasury - Self-funded (validator 201+): Must provide your own 75,000 MOLT minimum — immediately fully vested, no debt
- Vesting (standard): 50% of earned rewards go to debt repayment, 50% liquid — this is the default split for all bootstrap validators
- Performance bonus (≥95% uptime): 75% of earned rewards go to debt repayment, 25% liquid — accelerates graduation by ~1.5× (via
PERFORMANCE_BONUS_BPS = 15000) - Time cap: All remaining debt is forgiven after 547 days (~18 months) regardless of repayment progress
Graduation System
Bootstrap validators go through a graduation process from Bootstrapping to FullyVested:
| Path | Reward Split | Condition | Effect |
|---|---|---|---|
| Standard | 50% debt / 50% liquid | Bootstrap debt reaches 0 | Status → FullyVested, 100% liquid rewards |
| Performance Bonus | 75% debt / 25% liquid | ≥95% uptime (9,500+ basis points) | Same graduation, reached ~1.5× sooner |
| Time Cap | N/A | 547 days since validator started (~118M slots) | Remaining debt forgiven, immediate graduation |
Uptime Calculation
Uptime is calculated in basis points (0–10,000 = 0%–100%) based on actual block production vs. expected share:
expected_blocks = (current_slot - start_slot) / num_active_validators
uptime_bps = min(10000, blocks_produced × 10000 / expected_blocks)
- Fair share: With N active validators, each one is expected to produce 1/N of total blocks. A validator that produces its full share has 100% uptime (10,000 bps).
- Threshold: ≥ 9,500 bps (95%) triggers the performance bonus (75/25 split).
- Edge cases: New validators with no slot history default to 0 bps. If fewer slots have elapsed than validators exist, validators with at least 1 block get benefit of the doubt (10,000 bps).
Anti-Sybil Protection
Each validator collects a machine fingerprint (SHA-256 hash of platform UUID + MAC address) at startup. This fingerprint is:
- Included in & signed with validator announcements
- Registered in the stake pool — one fingerprint per bootstrap validator
- Prevents running 50 validators on one machine to steal 50 bootstrap grants
Rule: One machine = one bootstrap grant. Self-funded validators (201+) are not restricted by fingerprint.
ReefStake Mechanism
MoltChain uses ReefStake, a delegated proof-of-stake variant inspired by coral reef ecosystems:
- Validator Coral: Each validator is a "coral head." Delegators attach stake to a validator, growing the reef.
- Epoch Rotation: The active validator set is recalculated every epoch (~4 hours). The top validators by total stake are selected.
- Reward Distribution: Block rewards (heartbeat + transaction fees) are split proportionally between the validator (commission) and delegators.
- Slashing: Double-signing or extended downtime results in a percentage of staked MOLT being burned. With
enable_slashing = true, evidence is gossiped via P2P and processed by theSlashingTracker.
Check Stake Status
$ molt stake status --rpc-url https://testnet-rpc.moltchain.io
Identity: Mo1tVa1idAtoR...xYz789
Stake: 100,000.000000000 MOLT (bootstrap)
Delegated: 450.000000000 MOLT
Total: 100,450.000000000 MOLT
Active: Yes (rank #7 of 21)
Commission: 10%
Last Vote: slot 1,205,142
Monitoring
Prometheus Metrics
When [monitoring] enable_metrics = true, the validator exposes a Prometheus-compatible endpoint at http://<host>:9100/metrics.
Key Metrics
| Metric | Type | Description |
|---|---|---|
moltchain_block_height | Gauge | Current finalized block height |
moltchain_tps | Gauge | Transactions per second (rolling 10s window) |
moltchain_peer_count | Gauge | Number of connected P2P peers |
moltchain_mempool_size | Gauge | Pending transactions in the mempool |
moltchain_slot_duration_ms | Histogram | Actual slot processing time |
moltchain_vote_count | Counter | Total votes cast by this validator |
moltchain_blocks_produced | Counter | Blocks produced by this validator |
# Fetch metrics
curl -s http://localhost:9100/metrics | grep moltchain_
# Example output
moltchain_block_height 1205247
moltchain_tps 842
moltchain_peer_count 18
moltchain_mempool_size 127
Health Check
The RPC server provides a health check via the getHealth JSON-RPC method:
curl -s http://localhost:8899 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"getHealth"}'
# Response: {"jsonrpc":"2.0","result":"ok","id":1}
Log Levels
Control verbosity with the RUST_LOG environment variable or the [logging] level config key:
# Per-module granularity via RUST_LOG
RUST_LOG=info,moltchain_p2p=debug,moltchain_rpc=warn moltchain-validator
# Or set in config.toml
# [logging]
# level = "debug"
# log_format = "json"
Docker Deployment
The recommended production deployment uses Docker Compose. The provided docker-compose.yml runs the validator, faucet, and optional explorer.
version: "3.8"
services:
validator:
build:
context: .
dockerfile: Dockerfile
container_name: moltchain-validator
restart: unless-stopped
ports:
- "7001:7001" # P2P (testnet)
- "8899:8899" # RPC (testnet)
- "8900:8900" # WebSocket (testnet)
- "9100:9100" # Metrics
volumes:
- moltchain-data:/var/lib/moltchain
environment:
- RUST_LOG=info
- MOLTCHAIN_NETWORK=testnet
- MOLTCHAIN_RPC_PORT=8899
- MOLTCHAIN_WS_PORT=8900
- MOLTCHAIN_P2P_PORT=7001
- MOLTCHAIN_SIGNER_BIND=0.0.0.0:9201
- MOLTCHAIN_ADMIN_TOKEN=${MOLTCHAIN_ADMIN_TOKEN:-}
networks:
- moltchain
healthcheck:
test: ["CMD-SHELL", "curl -sf http://localhost:8899/ -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"getHealth\"}' -H 'Content-Type: application/json' || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 15s
volumes:
moltchain-data:
driver: local
networks:
moltchain:
driver: bridge
Volume Mounts
| Mount | Purpose |
|---|---|
moltchain-data:/var/lib/moltchain | Persistent blockchain state — survives container restarts and upgrades. |
./config.toml:/etc/moltchain/config.toml:ro | Optional configuration file (future). Currently all settings are passed as CLI flags / environment variables in docker-compose. |
Running
# Start in foreground (see logs)
docker-compose up validator
# Start in background
docker-compose up -d validator
# View logs
docker-compose logs -f validator
# Stop
docker-compose down
Health Check
Docker will automatically restart the validator if the getHealth RPC call fails 3 consecutive times. The start_period: 15s gives the node time to initialize before checks begin.
Systemd Deployment
For bare-metal Linux servers, use the provided setup script to install a systemd service per network.
Setup Script
Run the setup script as root. It accepts one or both network names:
# Build first
cargo build --release
# Setup for testnet only
sudo bash deploy/setup.sh testnet
# Setup for both networks on the same machine
sudo bash deploy/setup.sh testnet mainnet
The script performs:
- Creates a dedicated
moltchainsystem user/group (no login shell) - Creates directories:
/etc/moltchain,/var/lib/moltchain,/var/log/moltchain - Copies binaries to
/usr/local/bin/ - Generates
/etc/moltchain/env-testnetand/or/etc/moltchain/env-mainnetwith correct port assignments - Installs per-network systemd services:
moltchain-validator-testnetandmoltchain-validator-mainnet
Systemd Unit File
The service reads its port configuration from the environment file. Key flags match moltchain-start.sh:
[Unit]
Description=MoltChain Validator Node
Documentation=https://docs.moltchain.io
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=moltchain
Group=moltchain
# --no-watchdog: systemd handles restarts via Restart=on-failure
ExecStart=/usr/local/bin/moltchain-validator --no-watchdog \
--network ${MOLTCHAIN_NETWORK} \
--rpc-port ${MOLTCHAIN_RPC_PORT} \
--ws-port ${MOLTCHAIN_WS_PORT} \
--p2p-port ${MOLTCHAIN_P2P_PORT} \
--db-path /var/lib/moltchain/state-${MOLTCHAIN_NETWORK}
Restart=on-failure
RestartSec=10
LimitNOFILE=65536
# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/moltchain /var/log/moltchain
PrivateTmp=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
# Environment
Environment=RUST_LOG=info
EnvironmentFile=/etc/moltchain/env
# Logging
StandardOutput=journal
StandardError=journal
SyslogIdentifier=moltchain-validator
[Install]
WantedBy=multi-user.target
NoNewPrivileges, ProtectSystem=strict, ProtectHome, PrivateTmp, and kernel protection directives. The process runs as the unprivileged moltchain user with write access only to /var/lib/moltchain and /var/log/moltchain.
Service Management
# Start the testnet validator
sudo systemctl start moltchain-validator-testnet
# Enable on boot
sudo systemctl enable moltchain-validator-testnet
# Check status
sudo systemctl status moltchain-validator-testnet
# Follow logs
journalctl -u moltchain-validator-testnet -f
# Restart after config change
sudo systemctl restart moltchain-validator-testnet
# Mainnet uses the same commands with -mainnet suffix
sudo systemctl start moltchain-validator-mainnet
Troubleshooting
Port Conflicts
If the validator fails to start with "address already in use":
# Find what's using the port (testnet example)
sudo lsof -i :7001 # P2P
sudo lsof -i :8899 # RPC
# The port scheme is fixed per network — see the Installation section above
Insufficient Stake
Your node won't produce blocks without meeting the minimum stake. Check your balance and stake:
molt balance --rpc-url https://testnet-rpc.moltchain.io
molt stake status --rpc-url https://testnet-rpc.moltchain.io
Sync Failures
If your node can't sync with the network:
- Verify
seed_nodesare correct and reachable - Check that the P2P port is open in your firewall (
sudo ufw allow 7001/tcpfor testnet) - Ensure
chain_idmatches the network you're connecting to - Try increasing log level:
RUST_LOG=debug,moltchain_p2p=trace
# Test connectivity to seed nodes
nc -zv seed1.moltchain.io 7001
# Check current block height via RPC (testnet port 8899)
curl -s http://localhost:8899 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"getBlockHeight"}' | jq .result
Disk Full
The ledger grows over time. Monitor disk usage and plan for growth:
# Check data directory size
du -sh /var/lib/moltchain/
# Check available disk
df -h /var/lib/moltchain/
# Set up monitoring alert (example with Prometheus Alertmanager)
# Alert when disk usage > 80%
Debug Commands
# Full node status dump (testnet RPC port)
curl -s http://localhost:8899 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"getHealth"}' | jq
# Peer list
curl -s http://localhost:8899 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"getClusterNodes"}' | jq
# Validator set
curl -s http://localhost:8899 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"getValidators"}' | jq
# Check systemd logs for crash details
journalctl -u moltchain-validator-testnet --since "1 hour ago" --no-pager
# Run validator with maximum verbosity (testnet)
RUST_LOG=trace moltchain-validator --network testnet --rpc-port 8899 --ws-port 8900 --p2p-port 7001 --db-path /var/lib/moltchain/state-testnet 2>&1 | head -200
#validators channel or open an issue on GitHub with your logs and config (redact your keypair and admin token).