Validator Guide
Register on-chain, run a paraloom validator on devnet, and survive reputation + slashing.
Validator guide
A paraloom validator verifies Groth16 withdrawal proofs and votes in the BFT cohort. It does not generate proofs — that's client-side. The hardware bar is intentionally low: a recent laptop, a Raspberry Pi 5, or a small cloud VM all work.
What you're signing up for
| Role | Verify-only — proof verification, voting, optional compute |
| Stake | 1 SOL minimum (devnet), held in a per-validator on-chain PDA |
| Reward | Verification + compute fees, accrued on-chain (total_earnings) |
| Risk | Slashing on equivocation or persistent unavailability |
| Discovery | Other validators find you via the on-chain registry — you don't manually exchange peer addresses |
1. Hardware
| Required | Recommended | |
|---|---|---|
| CPU | 2 cores x86_64 / arm64 | 4+ cores |
| RAM | 8 GB | 16 GB |
| Disk | 60 GB SSD | 120 GB NVMe |
| Network | 50 Mbit/s symmetric | 100+ Mbit/s |
No GPU required. RocksDB does fsync on hot writes so prefer SSD over HDD.
2. Install
Either use a signed release binary (recommended) or build from source:
git clone https://github.com/paraloom-labs/paraloom-core.git
cd paraloom-core
cargo build --release3. Solana wallet & devnet SOL
# Create the wallet that owns the validator stake
solana-keygen new -o ./validator-wallet.json
# Point at devnet, top up
solana config set --url devnet --keypair ./validator-wallet.json
solana airdrop 2
solana balanceKeep this wallet secure — it controls the staked SOL.
4. Generate node identity
./target/release/paraloom validator keygen --out ./validator.key
./target/release/paraloom validator show-id --key ./validator.key
# 12D3KooW... ← libp2p peer ID5. On-chain registration
This is the moment you become a validator. The Anchor program creates a ValidatorAccount PDA seeded by your pubkey, transfers your stake into it, and inits reputation = 1000.
./target/release/paraloom validator register \
--network devnet \
--key ./validator.key \
--wallet ./validator-wallet.json \
--stake 1 # SOLUnder the hood this calls register_validator in programs/paraloom/src/lib.rs:
pub fn register_validator(ctx: Context<RegisterValidator>, stake: u64) -> Result<()> {
require!(stake >= MIN_VALIDATOR_STAKE, ParaloomError::StakeTooLow);
transfer(/* wallet → validator_pda */, stake)?;
validator_pda.stake_amount = stake;
validator_pda.reputation = 1000;
validator_pda.total_earnings = 0;
validator_pda.times_slashed = 0;
validator_registry.total_validators += 1;
validator_registry.active_validators += 1;
Ok(())
}Verify your registration is live on-chain:
./target/release/paraloom validator status --network devnet --key ./validator.key
# stake: 1 SOL
# reputation: 1000
# active: true6. Configure
validator.toml:
[node]
data_dir = "./data"
[network]
network = "devnet"
listen = "0.0.0.0:9001"
# bootstrap_peers are read from on-chain ValidatorRegistry —
# you usually don't need to specify any seeds manually.
[consensus]
threshold = 7
total_validators = 10
heartbeat_secs = 5
[bridge]
solana_rpc = "https://api.devnet.solana.com"
program_id = "DSysqF2oYAuDRLfPajMnRULce2MjC3AtTszCkcDv1jco"
[metrics]
listen = "0.0.0.0:9300" # /health /ready /metrics
[validator]
key_path = "./validator.key"
wallet_path = "./validator-wallet.json"Discovery is automatic — Kademlia DHT bootstraps from the on-chain registry, so once your validator is registered other peers will find you. Manual bootstrap_peers is only needed for fully isolated localnet runs. See Networking.
7. Start
./target/release/paraloom validator start --config ./validator.tomlVerify health from another shell:
curl -s http://localhost:9300/health # → {"status":"ok"}
curl -s http://localhost:9300/ready # → 200 once peer count > 0 and bridge is reachableRun as a systemd service
# /etc/systemd/system/paraloom-validator.service
[Unit]
Description=Paraloom validator
After=network-online.target
[Service]
Type=simple
User=paraloom
WorkingDirectory=/home/paraloom
ExecStart=/usr/local/bin/paraloom validator start --config /home/paraloom/validator.toml
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable --now paraloom-validator
sudo journalctl -u paraloom-validator -fReputation & slashing
Reputation is tracked off-chain by the BFT cohort and bounded between 0 and 10000. Validators below a configurable gate threshold cannot vote on withdrawals — see Consensus. Reputation moves with observed behaviour; the exact deltas are tunable per network.
Two on-chain slashable events:
| Event | Detection | Result |
|---|---|---|
| Equivocation | Two valid signatures on conflicting messages at the same height | Stake slashed, times_slashed += 1, reputation tanked |
| Persistent unavailability | Missed heartbeats / votes over a configurable window without unregistering | Cohort signs evidence; authority submits slashing tx |
Recover from a graceful outage by unregistering before extended downtime, not by going silent:
paraloom validator unregister --network devnet --key ./validator.key
# Stake returned to your wallet; PDA closed.Monitoring
Each validator exposes Prometheus-format metrics on the metrics.listen port:
| Metric | Description |
|---|---|
paraloom_proof_verify_seconds | Per-proof verification latency histogram |
paraloom_consensus_round_total{outcome=…} | Withdrawal rounds, by outcome |
paraloom_consensus_vote_total{vote=…} | Votes cast, by approve/reject |
paraloom_peer_count | Currently connected peers |
paraloom_nullifier_set_size | Local nullifier set cardinality |
paraloom_coordinator_role | Primary / passive |
paraloom_reputation | Tracked reputation for this validator |
A scrape config + endpoint reference: Monitoring.
Earnings
total_earnings accrues on the on-chain ValidatorAccount PDA as withdrawal fees and compute fees flow in. Read it any time:
paraloom validator earnings --network devnet --key ./validator.key
# stake: 1 SOL
# earned: 0.043 SOLClaim withdrawals are not yet exposed via CLI on devnet — earnings simply accumulate on-chain pre-mainnet.
Security checklist
-
./validator.keyand./validator-wallet.jsonarechmod 600 - Wallet keypair is backed up offline
- Firewall allows TCP/9001 inbound from anywhere;
9300only from your monitoring net - Time is NTP-synced (consensus uses slot timestamps; large drift breaks heartbeats)
- You have a plan for graceful unregistration before extended maintenance windows
Troubleshooting
Next
- Consensus — vote weighting, slashing evidence, leader rotation
- Coordinator HA — what failover looks like when the primary dies
- Monitoring — full metrics reference