Running a Validator Node
Validators (block producers) are accounts scheduled by the Fair-DPOS algorithm to produce blocks every 3 seconds. Running a validator node requires a registered validator account, a signing key, and a properly configured node.
Prerequisites
- A VIZ Ledger account registered as a validator via
validator_update_operation. - The WIF private key corresponding to the signing key registered on-chain.
- A synced full node (validator plugin requires chain + p2p + snapshot plugins).
Configuration
Use share/vizd/config/config_witness.ini as the base template.
Key settings:
# P2P — allow public inbound connections for block propagation
p2p-endpoint = 0.0.0.0:2001
p2p-seed-node = seed1.viz.world:2001
# RPC — bind to localhost for security (validators don't need public API)
webserver-http-endpoint = 127.0.0.1:8090
webserver-ws-endpoint = 127.0.0.1:8091
# Required plugins for a validator
plugin = chain p2p webserver json_rpc database_api network_broadcast_api validator validator_api
# Skip virtual-op indexing to save memory (validators don't need it)
skip-virtual-ops = true
# Shared memory — 2G is enough for low-memory validator builds
shared-file-size = 2G
# ─── Validator identity ───────────────────────────────────────
# Your validator account name
validator = myvalidator
# Your signing private key (WIF format)
private-key = 5JxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxWIF
# Participation threshold — stop producing if network drops below this
required-participation = 33
# Do NOT enable this on mainnet (only for testnet/bootstrap)
# enable-stale-production = falseNTP Synchronization
Accurate time is critical for block production. The validator plugin maintains its own NTP client:
# NTP servers (defaults are pool.ntp.org, time.google.com, time.cloudflare.com)
ntp-server = pool.ntp.org
ntp-server = time.cloudflare.com
# Check NTP every 15 minutes
ntp-request-interval = 900
# Discard NTP replies with round-trip > 150ms
ntp-round-trip-threshold = 150Ensure the server OS clock is also synchronized (via chrony or systemd-timesyncd).
Starting the Node
./vizd --config-file /data/vizd/config.ini --data-dir /data/vizdDocker
docker run -d \
--name vizd-validator \
--restart unless-stopped \
-p 2001:2001 \
-v /data/vizd:/var/lib/vizd \
-e VIZD_WITNESS=myvalidator \
-e VIZD_PRIVATE_KEY=5Jxxx... \
vizblockchain/vizd:latestRegistering / Updating Your Validator
Use cli_wallet or any compatible wallet to broadcast a validator_update_operation:
{
"type": "validator_update_operation",
"value": {
"owner": "myvalidator",
"url": "https://mysite.example/validator",
"block_signing_key": "VIZ5hqSa...",
"props": [3, {
"account_creation_fee": "1.000 VIZ",
"maximum_block_size": 65536
}]
}
}The block_signing_key must match the private-key configured in the node.
To disable your validator (remove from schedule), set block_signing_key to the null key:
"block_signing_key": "VIZ1111111111111111111111111111111114T1Anm"Production Loop: What the Node Does
The validator plugin runs a 250ms production timer on a dedicated thread (isolated from P2P I/O). On each tick it calls maybe_produce_block() which checks (in order):
- Sync gate (DLT mode): Not producing if catching up from peers.
- Snapshot gate: Not producing if snapshot creation is in progress.
- Participation check: Network must have ≥33% validator participation.
- Slot assignment: Is this node's validator scheduled for the current slot?
- Key check: Does the node have the correct private key?
- Minority fork detection: If the last 21 blocks are all from this node's validators — rollback and resync.
- Fork collision resolution: If another block exists at the same height, apply vote-weight comparison.
- Lag check: If the node is >500ms past the slot boundary — skip.
- Generate and broadcast the block.
See Validator Plugin for the complete execution flow.
Production Results (Log Messages)
| Result | Meaning |
|---|---|
produced | Block produced and broadcast successfully |
not_synced | Node still catching up or snapshot in progress |
not_time_yet | No slot available or NTP drift |
not_my_turn | Another validator is scheduled for this slot |
no_private_key | Configured validator scheduled but private key missing |
low_participation | Network participation below threshold |
lag | Woke up >500ms past slot — slot missed |
fork_collision | Competing block at next height — waiting |
minority_fork | Node is on isolated fork — rolling back |
Safety Mechanisms
Network Partition Guard
If fewer than 33% of validators are participating, production stops to prevent split-brain scenarios. Override with enable-stale-production = true only for bootstrap/testnet.
Minority Fork Detection
If the node's fork database shows 21+ consecutive blocks all from this node's own validators, it automatically rolls back to LIB and resyncs. This catches network isolation.
Production Watchdog
If no block has been produced for 180 seconds (60s for emergency master) while should_be_producing is true, the watchdog automatically clears stuck flags (minority_fork_recovering, P2P catchup, chain syncing) and attempts to resume.
Snapshot Safety
Block production is paused while a snapshot is being created to avoid write-lock conflicts.
Monitoring
Watch for these log patterns:
# Good: block produced
produced block #123456 ... validator=myvalidator
# Warning: missed slot
MISSED-SLOT-OUR-validator: ...
# Warning: minority fork
MINORITY FORK DETECTED: rolling back to LIB
# Warning: watchdog fires
WATCHDOG: no production for 180s, clearing flagsAlso see Monitoring and Validator Guard for automated alerting.
Multiple Validators on One Node
The validator and private-key options are repeatable:
validator = alice
validator = alice.backup
private-key = 5Jxxx... # Alice's key
private-key = 5Jyyy... # Alice.backup's keyThe node will produce blocks for any of the configured validators when scheduled.
Emergency Consensus Key
For nodes involved in emergency consensus recovery:
emergency-private-key = 5Jzzz... # Committee emergency keyWhen set, the node automatically adds CHAIN_EMERGENCY_VALIDATOR_ACCOUNT to its validator set and participates in emergency block production. See Emergency Consensus.
Troubleshooting
| Problem | Check |
|---|---|
| Not producing | Verify validator and private-key in config; check signing key registered on-chain matches config |
no_private_key in logs | On-chain signing key doesn't match any private-key in config |
low_participation | Network health issue — check peer count and other validators |
minority_fork | Network isolation — verify connectivity to seed nodes |
| NTP stall warnings | Check OS NTP sync: chronyc tracking or timedatectl |
| Slot hijacks | Signing key may have been blanked by emergency master; restore via validator_update_operation |