Validator Guide
This guide covers everything needed to run a Specter validator, from initial setup to ongoing maintenance, slashing parameters, and key operational commands. Validators are responsible for proposing and signing blocks, and they earn staking rewards in return for securing the network.
Prerequisites
Before becoming a validator, you must have a fully synced Specter full node. Complete the Node Setup guide first and confirm your node is caught up:
umbralined status 2>&1 | jq '.SyncInfo.catching_up'
# Must return: false
Hardware Requirements
Validators have stricter requirements than full nodes due to the real-time demands of consensus:
| Resource | Minimum | Recommended |
|---|---|---|
| CPU | 4 cores | 8+ cores (high single-thread performance) |
| RAM | 16 GB | 32 GB |
| Storage | 500 GB NVMe SSD | 1 TB NVMe SSD |
| Network | 100 Mbps, low latency | 1 Gbps, under 50ms to peers |
| Uptime | 99%+ | 99.9%+ |
Software Requirements
- Go 1.21+
umbralinedbinary (built from source or official release)jqfor JSON processing
Stake Requirements
To create a validator, you need a minimum self-delegation of GHOST tokens. The exact minimum depends on the current active set size, but you need enough stake to be in the top N validators by total stake (including delegations).
Create a Validator
Step 1: Create or Import a Key
# Create a new key
umbralined keys add my-validator-key
# OR import an existing mnemonic
umbralined keys add my-validator-key --recover
Save the mnemonic phrase securely. This is the only way to recover your key. Loss of the mnemonic means permanent loss of access to your validator and all staked funds.
# Verify your key was created
umbralined keys show my-validator-key -a
# Returns: umbra1...
# Show the validator's public key (needed for create-validator tx)
umbralined tendermint show-validator
# Returns: {"@type":"/cosmos.crypto.ed25519.PubKey","key":"..."}
Step 2: Fund Your Account
Your validator account needs GHOST to cover the self-delegation and transaction fees.
# Check your balance
umbralined query bank balances $(umbralined keys show my-validator-key -a)
On testnet, use the faucet at the Specter Discord or request tokens from the faucet address.
Step 3: Create the Validator
umbralined tx staking create-validator \
--amount=1000000000000000000000aghost \
--pubkey=$(umbralined tendermint show-validator) \
--moniker="my-validator" \
--chain-id=umbraline_5446-1 \
--commission-rate="0.10" \
--commission-max-rate="0.20" \
--commission-max-change-rate="0.01" \
--min-self-delegation="1" \
--gas="auto" \
--gas-adjustment=1.5 \
--gas-prices="0.001aghost" \
--from=my-validator-key
Parameter breakdown:
| Parameter | Value | Description |
|---|---|---|
--amount | 1000000000000000000000aghost | Initial self-delegation (1000 GHOST) |
--commission-rate | 0.10 | 10% commission on delegator rewards |
--commission-max-rate | 0.20 | Maximum commission rate (can never exceed this) |
--commission-max-change-rate | 0.01 | Maximum daily commission change (1%/day) |
--min-self-delegation | 1 | Minimum self-delegation in GHOST |
--commission-max-rate and --commission-max-change-rate are set at validator creation and cannot be changed later. Choose values carefully.
Step 4: Verify Your Validator
# Check validator status
umbralined query staking validator $(umbralined keys show my-validator-key --bech val -a)
# Check if your validator is in the active set
umbralined query staking validators --status bonded | grep "my-validator"
# Check your validator's signing status
umbralined query slashing signing-info $(umbralined tendermint show-validator)
Managing Your Validator
Edit Validator
Update your validator's description, commission rate, or other mutable fields:
umbralined tx staking edit-validator \
--moniker="new-moniker" \
--details="Specter validator operated by Example Corp" \
--website="https://example.com" \
--identity="KEYBASE_ID" \
--commission-rate="0.12" \
--from=my-validator-key \
--chain-id=umbraline_5446-1 \
--gas="auto" \
--gas-prices="0.001aghost"
The --identity field should be a Keybase.io PGP key fingerprint (16 characters), which links your validator to a verifiable identity.
Delegate Additional Stake
umbralined tx staking delegate \
$(umbralined keys show my-validator-key --bech val -a) \
500000000000000000000aghost \
--from=my-validator-key \
--chain-id=umbraline_5446-1 \
--gas="auto" \
--gas-prices="0.001aghost"
Withdraw Rewards
# Withdraw staking rewards
umbralined tx distribution withdraw-rewards \
$(umbralined keys show my-validator-key --bech val -a) \
--from=my-validator-key \
--chain-id=umbraline_5446-1 \
--gas="auto" \
--gas-prices="0.001aghost"
# Withdraw rewards AND commission
umbralined tx distribution withdraw-rewards \
$(umbralined keys show my-validator-key --bech val -a) \
--commission \
--from=my-validator-key \
--chain-id=umbraline_5446-1 \
--gas="auto" \
--gas-prices="0.001aghost"
Unjail a Validator
If your validator is jailed (due to downtime or other infractions), you can unjail after the jail period expires:
# Check jail status
umbralined query slashing signing-info $(umbralined tendermint show-validator)
# Unjail (after the minimum jail duration has passed)
umbralined tx slashing unjail \
--from=my-validator-key \
--chain-id=umbraline_5446-1 \
--gas="auto" \
--gas-prices="0.001aghost"
Slashing
Slashing is the protocol's mechanism for penalizing validators that act against network interests. There are two slashing conditions:
Downtime (Liveness Fault)
A validator is slashed for downtime if they fail to sign a sufficient number of blocks within a rolling window.
| Parameter | Value |
|---|---|
| Slash Fraction | 1% of staked tokens |
| Jail Duration | 10 minutes |
| Signed Blocks Window | 100 blocks |
| Minimum Signed Per Window | 50% (50 of 100 blocks) |
How it works:
- The chain tracks the last 100 blocks.
- If a validator misses more than 50 of those 100 blocks, they are automatically jailed.
- 1% of the validator's total stake (including delegator stake) is slashed.
- After 10 minutes, the validator can submit an
unjailtransaction to rejoin the active set.
Common causes of downtime:
- Node crash or out-of-memory
- Network partition or connectivity issues
- Disk full
- Misconfigured firewall blocking P2P port
Double Signing (Equivocation)
Double signing occurs when a validator signs two different blocks at the same height. This is a severe offense because it can lead to chain forks.
| Parameter | Value |
|---|---|
| Slash Fraction | 5% of staked tokens |
| Jail Duration | Permanent (tombstoned) |
How it works:
- CometBFT's evidence module detects that a validator produced two conflicting signatures for the same block height.
- The validator is immediately jailed and tombstoned — permanently banned from the active validator set.
- 5% of the validator's total stake is slashed.
- The validator can never unjail. A new validator must be created with a new key.
Common causes of double signing:
- Running two instances of the same validator simultaneously (e.g., during migration without stopping the old node first)
- Restoring a validator from backup without ensuring the old instance is fully stopped
- Using the same
priv_validator_key.jsonon multiple machines
Double signing results in permanent removal from the validator set (tombstoning). There is no recovery. Always ensure only one instance of your validator is running at any time.
Evidence Module
The evidence module is responsible for detecting and processing equivocation (double-sign) evidence. When a CometBFT node receives conflicting votes from the same validator for the same height/round, it packages this as evidence and includes it in the next block.
Key parameters:
| Parameter | Value | Description |
|---|---|---|
max_age_num_blocks | 100,000 | Evidence older than this is discarded |
max_age_duration | 48 hours | Time-based evidence expiry |
max_bytes | 1,048,576 | Maximum evidence size per block (1 MB) |
Evidence is processed at BeginBlock — before any transactions in the block are executed. This ensures slashing happens promptly.
Monitoring
Essential Metrics to Monitor
| Metric | What to Watch | Alert Threshold |
|---|---|---|
| Block signing | Consecutive missed blocks | >10 consecutive misses |
| Peer count | Number of connected peers | Fewer than 5 peers |
| Disk usage | Available storage | Under 20% remaining |
| Memory usage | RAM consumption | >80% utilization |
| Block height | Chain sync status | >10 blocks behind |
| Process status | umbralined running | Process not found |
Prometheus Metrics
Enable Prometheus metrics in config.toml:
[instrumentation]
prometheus = true
prometheus_listen_addr = ":26660"
Key Prometheus metrics to track:
# Consensus height
cometbft_consensus_height
# Number of connected peers
cometbft_p2p_peers
# Missed blocks
cometbft_consensus_missing_validators
# Block processing time
cometbft_consensus_block_interval_seconds
# Transaction count
cometbft_consensus_num_txs
Health Check Script
#!/bin/bash
# validator-health-check.sh
NODE_STATUS=$(umbralined status 2>&1)
CATCHING_UP=$(echo "$NODE_STATUS" | jq -r '.SyncInfo.catching_up')
LATEST_HEIGHT=$(echo "$NODE_STATUS" | jq -r '.SyncInfo.latest_block_height')
PEER_COUNT=$(curl -s http://localhost:26657/net_info | jq -r '.result.n_peers')
echo "Height: $LATEST_HEIGHT"
echo "Catching Up: $CATCHING_UP"
echo "Peers: $PEER_COUNT"
if [ "$CATCHING_UP" = "true" ]; then
echo "WARNING: Node is still syncing!"
fi
if [ "$PEER_COUNT" -lt 5 ]; then
echo "WARNING: Low peer count ($PEER_COUNT)"
fi
# Check if validator is jailed
VALIDATOR_ADDR=$(umbralined keys show my-validator-key --bech val -a)
JAILED=$(umbralined query staking validator "$VALIDATOR_ADDR" -o json 2>/dev/null | jq -r '.jailed')
if [ "$JAILED" = "true" ]; then
echo "CRITICAL: Validator is JAILED!"
fi
Backup and Recovery
Critical Files to Back Up
| File | Location | Purpose |
|---|---|---|
priv_validator_key.json | ~/.umbralined/config/ | Validator signing key (most critical) |
node_key.json | ~/.umbralined/config/ | P2P identity key |
| Mnemonic phrase | Offline storage | Account recovery |
Backup Procedure
# Back up validator key (store securely, preferably offline/encrypted)
cp ~/.umbralined/config/priv_validator_key.json /secure/backup/location/
# Back up node key
cp ~/.umbralined/config/node_key.json /secure/backup/location/
Recovery Procedure
# 1. Set up a new node (follow Node Setup guide)
umbralined init recovery-node --chain-id umbraline_5446-1
# 2. STOP the old validator completely (critical to prevent double signing!)
# Verify the old instance is fully stopped before proceeding
# 3. Restore the validator key
cp /secure/backup/location/priv_validator_key.json ~/.umbralined/config/
# 4. Download genesis and configure peers
# (follow Node Setup guide)
# 5. Sync the node (state sync recommended for speed)
# 6. Verify sync, then the validator will resume signing automatically
Never run two instances with the same priv_validator_key.json simultaneously. This will cause double signing and result in permanent tombstoning. Always fully stop the old instance before starting a new one.
Key Reference Commands
Validator Status
# View your validator info
umbralined query staking validator $(umbralined keys show my-validator-key --bech val -a)
# View all active validators
umbralined query staking validators --status bonded
# View signing info (missed blocks, jail status)
umbralined query slashing signing-info $(umbralined tendermint show-validator)
# View your outstanding rewards
umbralined query distribution rewards $(umbralined keys show my-validator-key -a)
# View your validator's commission
umbralined query distribution commission $(umbralined keys show my-validator-key --bech val -a)
Staking Operations
# Delegate to your own validator
umbralined tx staking delegate <validator-addr> <amount>aghost \
--from=my-validator-key --chain-id=umbraline_5446-1 --gas=auto --gas-prices=0.001aghost
# Redelegate from one validator to another (no unbonding period)
umbralined tx staking redelegate <src-validator> <dst-validator> <amount>aghost \
--from=my-validator-key --chain-id=umbraline_5446-1 --gas=auto --gas-prices=0.001aghost
# Unbond (start unbonding, subject to unbonding period)
umbralined tx staking unbond <validator-addr> <amount>aghost \
--from=my-validator-key --chain-id=umbraline_5446-1 --gas=auto --gas-prices=0.001aghost
Node Operations
# Check node sync status
umbralined status | jq '.SyncInfo'
# View connected peers
curl -s http://localhost:26657/net_info | jq '.result.peers[] | {id: .node_info.id, moniker: .node_info.moniker, remote_ip: .remote_ip}'
# View the latest block
umbralined query block
# Export state (for debugging or migration)
umbralined export --height <height> > state_export.json