Skip to content

Validator Sets

Atif Anowar edited this page Dec 2, 2020 · 1 revision

A number of Engines available in Geth achieve consensus by referring to a list of “validators” (referred to as authorities if they are linked to physical entities). Validators are a group of accounts which are allowed to participate in the consensus, they validate the transactions and blocks to later sign messages about them. The validator set can be specified in a number of different ways.

Immutable list

A simple list of addresses specified at genesis.

"authorities": {
    "list": [
        "0x7d577a597b2742b498cb5cf0c26cdcd726d39e6e",
        "0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1"
    ]
}

Contracts

The list can be also a part of the blockchain state by being stored in an Ethereum contract. Example contracts can be found here with the contract used on Kovan Network. A simple validator contract has to have the following interface:

[{"constant":false,"inputs":[],"name":"finalizeChange","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"name":"_validators","type":"address[]"}],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_parent_hash","type":"bytes32"},{"indexed":false,"name":"_new_set","type":"address[]"}],"name":"InitiateChange","type":"event"}]

which corresponds to this Solidity contract definition:

contract ValidatorSet {
    /// Issue this log event to signal a desired change in validator set.
    /// This will not lead to a change in active validator set until
    /// finalizeChange is called.
    ///
    /// Only the last log event of any block can take effect.
    /// If a signal is issued while another is being finalized it may never
    /// take effect.
    ///
    /// _parent_hash here should be the parent block hash, or the
    /// signal will not be recognized.
    event InitiateChange(bytes32 indexed _parent_hash, address[] _new_set);

    /// Get current validator set (last enacted or initial if no changes ever made)
    function getValidators() constant returns (address[] _validators);

    /// Called when an initiated change reaches finality and is activated.
    /// Only valid when msg.sender == SUPER_USER (EIP96, 2**160 - 2)
    ///
    /// Also called when the contract is first enabled for consensus. In this case,
    /// the "change" finalized is the activation of the initial set.
    function finalizeChange();
}

The function getValidators should always return the active set or the initial set of validators if the contract hasn’t been activated yet. The “active” validator set is the set of the most recently finalized signal (finalizeChange event).

Switching the set should be done by issuing an InitiateChange event with the parent block hash and the new set, storing the pending set, and then waiting for the call to finalizeChange (by the SYSTEM_ADDRESS: 2^160 - 2) before setting the active set to the pending set. This mechanism is used to ensure that the previous validator set “signs off” on the changes before activation, leading to full security in situations like warp and light sync, where state transitions aren’t checked.

Other than these restrictions, the switching rules are fully determined by the contract implementing that method. The spec should contain the contract address:

"authorities": {
    "safeContract": "0x1107C970670a4A92e22e5Ee94601f607263d8838"
}

Multi set

This validator set can specify any combination of other validator sets. Switching is done based on the number of the current block. It can be useful for conducting chain forks. First set has to start at block 0.

"authorities": {
    "multi": {
        "0": {
            "list": [
                "0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1",
                "0x7d577a597b2742b498cb5cf0c26cdcd726d39e6e"
            ]
        },
        "100": {
            "safeContract": "0x1107C970670a4A92e22e5Ee94601f607263d8838"
        }
    }
}

Note that transitions to a contract will not take effect immediately. Rather, they will take effect when the transition block is finalized by the previous set of validators. Again, this is to provide full security for warp and light sync.

Transitions to a fixed list will take effect immediately because regardless of whether an attacker gives a light client a transition block with an invalid state, the subsequent validator set will always be the same.

Limitations

Currently events emitted by the validator set contract when the engine calls finalizeChange are not observable. This is a limitation of how “system” transactions are implemented at the moment.

Not Implemented

Reporting contract

Sometimes one might want to automatically take action when one of the validators behaves badly. The definition of bad behaviour depends on a consensus engine and there are two types of bad behaviour:

  • benign misbehaviour
  • malicious misbehaviour Benign misbehaviour in Aura may be simply not receiving a block from a designated primary, while malicious misbehaviour would be releasing two different blocks for the same step.

This type of contract can listen to misbehaviour reports from the consensus engine and decide what are the consequences for the validators.