Skip to content

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

  1. A VIZ Ledger account registered as a validator via validator_update_operation.
  2. The WIF private key corresponding to the signing key registered on-chain.
  3. 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:

ini
# P2P — allow public inbound connections for block propagation
p2p-endpoint = 0.0.0.0:2001
p2p-seed-node = seed3.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 = false

NTP Synchronization

Accurate time is critical for block production. The validator plugin maintains its own NTP client:

ini
# 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 = 150

Ensure the server OS clock is also synchronized (via chrony or systemd-timesyncd).


Starting the Node

bash
./vizd --config-file /data/vizd/config.ini --data-dir /data/vizd

Docker

bash
docker run -d \
  --name vizd-validator \
  --restart unless-stopped \
  -p 2001:2001 \
  -v /data/vizd:/var/lib/vizd \
  -e VIZD_WITNESS_NAME=myvalidator \
  -e VIZD_PRIVATE_KEY=5Jxxx... \
  vizblockchain/vizd:latest

Registering / Updating Your Validator

Use cli_wallet or any compatible wallet to broadcast a validator_update_operation:

json
{
  "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:

json
"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):

  1. Sync gate (DLT mode): Not producing if catching up from peers.
  2. Snapshot gate: Not producing if snapshot creation is in progress.
  3. Participation check: Network must have ≥33% validator participation.
  4. Slot assignment: Is this node's validator scheduled for the current slot?
  5. Key check: Does the node have the correct private key?
  6. Minority fork detection: If the last 21 blocks are all from this node's validators — rollback and resync.
  7. Fork collision resolution: If another block exists at the same height, apply vote-weight comparison.
  8. Lag check: If the node is >500ms past the slot boundary — skip.
  9. Generate and broadcast the block.

See Validator Plugin for the complete execution flow.


Production Results (Log Messages)

ResultMeaning
producedBlock produced and broadcast successfully
not_syncedNode still catching up or snapshot in progress
not_time_yetNo slot available or NTP drift
not_my_turnAnother validator is scheduled for this slot
no_private_keyConfigured validator scheduled but private key missing
low_participationNetwork participation below threshold
lagWoke up >500ms past slot — slot missed
fork_collisionCompeting block at next height — waiting
minority_forkNode 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.

Single-operator forks

On a testnet or mainnet fork where one operator controls all validators, "21 blocks all ours" is the normal healthy state, so this detector loops forever resetting to LIB. enable-stale-production = true does not help here: healthy participation (≥33%) auto-clears that override every block. Use disable-minority-fork-detection = true instead — it bypasses both the standard and DLT detection paths and is never auto-cleared. Never enable it on a real public network — it removes the isolation guard.

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 flags

Also see Monitoring and Validator Guard for automated alerting.


Multiple Validators on One Node

The validator and private-key options are repeatable:

ini
validator = alice
validator = alice.backup
private-key = 5Jxxx...   # Alice's key
private-key = 5Jyyy...   # Alice.backup's key

The node will produce blocks for any of the configured validators when scheduled.


Emergency Consensus Key

For nodes involved in emergency consensus recovery:

ini
emergency-private-key = 5Jzzz...   # Committee emergency key

When set, the node automatically adds CHAIN_EMERGENCY_VALIDATOR_ACCOUNT to its validator set and participates in emergency block production. See Emergency Consensus.


Troubleshooting

ProblemCheck
Not producingVerify validator and private-key in config; check signing key registered on-chain matches config
no_private_key in logsOn-chain signing key doesn't match any private-key in config
low_participationNetwork health issue — check peer count and other validators
minority_forkNetwork isolation — verify connectivity to seed nodes
NTP stall warningsCheck OS NTP sync: chronyc tracking or timedatectl
Slot hijacksSigning key may have been blanked by emergency master; restore via validator_update_operation