Skip to content

Valset (Validator Set)

The validator set is the current list of operators and their weights that a network uses for signing and verification during a given epoch. In Relay, this is represented by a validator set header that ValSetDriver helps derive and then commit to the Settlement contracts.

At any moment in an epoch, the validator set answers three questions:

  • which operators are active
  • which keys they use to sign
  • how much voting power each one has (as computed by the VotingPowerProvider)

Applications and Settlement never recompute this themselves – they read the committed header and verify signatures against it.

Epoch Formation

ValSetDriver is the on-chain “driver” the Relay binary uses to derive validator sets epoch by epoch. At the start of each network epoch (or whenever the network decides to rotate), the off-chain Relay nodes:

  1. Discover eligible operators
    • Read operator/vault relationships and voting power from VotingPowerProvider.
    • Respect onboarding modules (whitelist/blacklist/jail, shared vs operator vaults, multi-token rules) so only registered and permitted operators are considered.
    • Filter to operators that have opted into the network and meet minimum power / inclusion constraints configured in VotingPowerProvider.
  2. Select active key material
    • Fetch cryptographic keys for these operators from KeyRegistry (BLS BN254 or ECDSA secp256k1).
    • Enforce key requirements: tags, key types, and quorum / threshold rules as configured via ValSetDriver.
  3. Assign weights
    • Call VotingPowerProvider to get each operator’s voting power for this network (stake → power, token weights, vault weights, etc.).
    • Apply any network-side caps (e.g. max power per operator, max validator count) that ValSetDriver exposes for Relay config.
  4. Fix the decision threshold
    • Choose a decision rule like > 50% or ≥ 2/3 of total voting power.
    • Encode this into the header metadata so Settlement and applications know what constitutes a valid quorum for verification.
  5. Produce a compact header
    • Compress: operator IDs, keys (or key hashes), weights, epoch number, network id, and the chosen threshold into a ValSetHeader.
    • Compute a headerHash = keccak256(abi.encode(header)) (conceptually – exact struct is handled inside the contracts).

This header is what gets committed on-chain and later used by Settlement and apps to verify aggregated signatures.

Storage and Rotation

ValSetDriver and Settlement together manage storage and rotation of validator sets:

  • Epoch-based rotation
    • ValSetDriver tracks epoch timing and exposes the current epoch start / duration to Relay nodes.
    • At each epoch boundary, Relay derives a new validator set and sends its header to the Settlement contracts.
  • On-chain storage
    • Settlement stores the current header (and usually some history) in compressed form, keyed by epoch or sequence.
    • The driver and Settlement together act as the on-chain source of truth: “for epoch N, these are the validators, weights, and threshold”.
  • Design constraint
    • Network epochs should be long enough that the whole path “observe stake → compute voting power → derive set → aggregate signatures → post header” reliably fits inside the epoch window, otherwise headers risk arriving late.

Cross-chain Commitment

Relay is designed to support multiple chains from a single validator set.

  • ValSetDriver holds configuration for:
    • which Settlement contracts (replicas) exist on which chain IDs
    • verification type (Simple vs ZK) and per-replica parameters (e.g. quorum thresholds, gas-oriented constraints)
  • For each epoch, the Relay binary:
    • derives one validator set header
    • commits that same header to all configured Settlement replicas

Applications on any of those chains read the same header, so verification of a given message is consistent everywhere.

Enforcement and Verification

Once a header is committed, it becomes the reference set for signature checks until the next epoch’s header replaces it.

  • Verification contracts
    • Settlement uses either SimpleVerifier (compressed full set verification, good up to ~125 validators) or ZKVerifier (zkSNARK-based proof) to check that an aggregated signature meets the threshold for the committed set.
  • Enforcement properties
    • If a signature is produced using a key that is not in the header, verification fails – the key has no registered voting power for that epoch.
    • If the aggregated signature does not correspond to a subset of validators whose total voting power ≥ threshold, verification fails.
    • If a malicious or misconfigured app tries to verify against an old header, it will only succeed if that header is still the one committed for the relevant epoch / sequence.

From the network’s perspective, that means:

  • you get deterministic, epoch-by-epoch validator sets derived from Symbiotic stake and operator status
  • anyone on any connected chain can cheaply verify that “this message was signed by enough power in the active set for epoch N” using only the committed header and the verifier contracts.

So, if VotingPowerProvider defines how much power each operator has, ValSetDriver + Settlement define which set is active at a given time and enforce that only that set – with its weights and threshold – can authorize decisions.