Skip to main content

Verifier

Verifier.sol is a supplementary contract responsible for validating Consensus Layer (CL) data proofs against the beacon block root obtained via EIP-4788 and reporting the verified facts to the module. All of its proof-processing methods are permissionless - anyone (typically the prover bot or the Node Operator) can submit a valid proof.

The following proof types are supported:

  • validator withdrawal (including historical);
  • validator balance (including historical);
  • validator slashing.

Hard-fork compatibility​

Verifier does not inspect the Consensus Layer fork version directly. Instead, it supports two sets of SSZ generalized indices, separated by PIVOT_SLOT. Proofs for state slots before the pivot use one set of indices, while proofs for the pivot slot and later use the other.

FIRST_SUPPORTED_SLOT is the deployment's lower acceptance boundary and should not be advanced merely because a new fork occurs. If a fork changes any relevant proof path, the immutable constructor values cannot be updated. A replacement Verifier must be deployed, tested with proofs from both sides of the fork boundary, and authorized on the module before activation. A changed leaf schema may also require contract code changes rather than new gindices alone.

The Mainnet deployment sets both FIRST_SUPPORTED_SLOT and PIVOT_SLOT to the Electra activation slot and configures both sets of indices for the Electra layout. As a result, the deployment supports Electra and remains compatible with later hard forks while the relevant SSZ indices remain unchanged. A hard fork does not necessarily change these paths; nevertheless, the generalized indices must be revalidated against the finalized specification for each fork.

The following values and assumptions must be tracked:

ValueFork-sensitive assumptions to verify
PIVOT_SLOTActivation slot at which the second set of proof paths becomes valid.
GI_*SSZ generalized indices for the corresponding fields used in proofs.
SLOTS_PER_EPOCHEpoch calculation used when checking validator withdrawability.
BEACON_ROOTSEIP-4788 system-contract address and lookup semantics.
SSZ leaf schemasLayouts of BeaconBlockHeader, Validator, and Withdrawal, whose roots are computed by the contract.

Upgradability​

The contract is immutable.

State Variables​

BEACON_ROOTS​

address public constant BEACON_ROOTS = 0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02

MAX_BP​

uint256 internal constant MAX_BP = 10_000

MIN_WITHDRAWAL_RATIO​

Minimum withdrawal amount as a ratio of the expected validator balance, expressed in basis points (10 000 = 100%).

uint256 public immutable MIN_WITHDRAWAL_RATIO

SLOTS_PER_EPOCH​

uint64 public immutable SLOTS_PER_EPOCH

SLOTS_PER_HISTORICAL_ROOT​

Count of historical roots per accumulator.

See https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#time-parameters

uint64 public constant SLOTS_PER_HISTORICAL_ROOT = 8192

GI_FIRST_WITHDRAWAL_PREV​

This index is relative to a state like: BeaconState.latest_execution_payload_header.withdrawals[0].

GIndex public immutable GI_FIRST_WITHDRAWAL_PREV

GI_FIRST_WITHDRAWAL_CURR​

This index is relative to a state like: BeaconState.latest_execution_payload_header.withdrawals[0].

GIndex public immutable GI_FIRST_WITHDRAWAL_CURR

GI_FIRST_VALIDATOR_PREV​

This index is relative to a state like: BeaconState.validators[0].

GIndex public immutable GI_FIRST_VALIDATOR_PREV

GI_FIRST_VALIDATOR_CURR​

This index is relative to a state like: BeaconState.validators[0].

GIndex public immutable GI_FIRST_VALIDATOR_CURR

GI_FIRST_HISTORICAL_SUMMARY_PREV​

This index is relative to a state like: BeaconState.historical_summaries[0].

GIndex public immutable GI_FIRST_HISTORICAL_SUMMARY_PREV

GI_FIRST_HISTORICAL_SUMMARY_CURR​

This index is relative to a state like: BeaconState.historical_summaries[0].

GIndex public immutable GI_FIRST_HISTORICAL_SUMMARY_CURR

GI_FIRST_BLOCK_ROOT_IN_SUMMARY​

This index is relative to HistoricalSummary like: HistoricalSummary.blockRoots[0]. Considered constant across forks.

GIndex public constant GI_FIRST_BLOCK_ROOT_IN_SUMMARY =
GIndex.wrap(0x000000000000000000000000000000000000000000000000000000000040000d)

GI_FIRST_BALANCES_NODE_PREV​

This index is relative to a state like: BeaconState.balances[0].

GIndex public immutable GI_FIRST_BALANCES_NODE_PREV

GI_FIRST_BALANCES_NODE_CURR​

This index is relative to a state like: BeaconState.balances[0].

GIndex public immutable GI_FIRST_BALANCES_NODE_CURR

FIRST_SUPPORTED_SLOT​

The very first slot the verifier is supposed to accept proofs for.

Slot public immutable FIRST_SUPPORTED_SLOT

PIVOT_SLOT​

The first slot of the currently compatible fork.

Slot public immutable PIVOT_SLOT

CAPELLA_SLOT​

Historical summaries started accumulating from the slot of Capella fork.

Slot public immutable CAPELLA_SLOT

WITHDRAWAL_ADDRESS​

An address withdrawals are supposed to happen to (Lido withdrawal credentials).

address public immutable WITHDRAWAL_ADDRESS

MODULE​

Staking module contract.

IBaseModule public immutable MODULE

Functions​

constructor​

The previous and current forks can be essentially the same.

constructor(
address withdrawalAddress,
address module,
uint64 slotsPerEpoch,
GIndices memory gindices,
Slot firstSupportedSlot,
Slot pivotSlot,
Slot capellaSlot,
uint256 minWithdrawalRatio,
address admin
) ;

processSlashedProof​

Verify proof of a slashed validator and report it to the module

function processSlashedProof(ProcessSlashedInput calldata data) external whenResumed;

Parameters

NameTypeDescription
dataProcessSlashedInput@see ProcessSlashedInput

processWithdrawalProof​

Verify withdrawal proof and report withdrawal to the module for valid proofs

function processWithdrawalProof(ProcessWithdrawalInput calldata data) external whenResumed;

Parameters

NameTypeDescription
dataProcessWithdrawalInput@see ProcessWithdrawalInput

processHistoricalWithdrawalProof​

Verify withdrawal proof against historical summaries data and report withdrawal to the module for valid proofs

function processHistoricalWithdrawalProof(ProcessHistoricalWithdrawalInput calldata data) external whenResumed;

Parameters

NameTypeDescription
dataProcessHistoricalWithdrawalInput@see ProcessHistoricalWithdrawalInput

processBalanceProof​

Verify a validator's balance proof from a recent beacon block and sync the key added balance.

function processBalanceProof(ProcessBalanceProofInput calldata data) external whenResumed;

Parameters

NameTypeDescription
dataProcessBalanceProofInputThe balance proof input containing recent block header, validator witness, and balance witness.

processHistoricalBalanceProof​

Verify a validator's balance proof from a historical beacon block and sync the key added balance. A historical proof is needed because the validator's balance may have increased at some point in the past and later decreased (e.g. due to inactivity leak or penalties). A recent proof alone would miss that peak, so a historical proof allows capturing the highest observed balance.

function processHistoricalBalanceProof(ProcessHistoricalBalanceProofInput calldata data) external whenResumed;

Parameters

NameTypeDescription
dataProcessHistoricalBalanceProofInputThe balance proof input containing recent + historical block headers, validator witness, and balance witness.

_reportSingleValidator​

function _reportSingleValidator(WithdrawnValidatorInfo memory info) internal;

_getParentBlockRoot​

function _getParentBlockRoot(uint64 blockTimestamp) internal view returns (bytes32);

_processWithdrawalProof​

header MUST be trusted at this point.

function _processWithdrawalProof(
WithdrawalWitness calldata withdrawal,
ValidatorWitness calldata validator,
BeaconBlockHeader calldata header,
uint256 nodeOperatorId,
uint256 keyIndex
) internal view returns (uint256 withdrawalAmount);

_processBalanceProof​

function _processBalanceProof(
ValidatorWitness calldata validator,
BalanceWitness calldata balance,
bytes32 stateRoot,
Slot stateSlot
) internal view returns (uint64 balanceGwei);

_verifyValidatorBalance​

function _verifyValidatorBalance(
uint256 validatorIndex,
bytes32 balanceNode,
bytes32 stateRoot,
Slot stateSlot,
bytes32[] calldata proof
) internal view returns (uint64 balanceGwei);

Returns

NameTypeDescription
balanceGweiuint64Validator's balance in gwei.

_getValidatorBalanceNodeInfo​

function _getValidatorBalanceNodeInfo(bytes32 balanceNode, uint256 validatorIndex, Slot stateSlot)
internal
view
returns (GIndex gI, uint64 balanceGwei);

Returns

NameTypeDescription
gIGIndexGeneralized index of the node for the validatorIndex and stateSlot.
balanceGweiuint64Balance in gwei extracted from the balanceNode.

_getValidatorGI​

function _getValidatorGI(uint256 offset, Slot stateSlot) internal view returns (GIndex);

_getWithdrawalGI​

function _getWithdrawalGI(uint256 offset, Slot stateSlot) internal view returns (GIndex);

_getValidatorBalanceGI​

function _getValidatorBalanceGI(uint256 offset, Slot stateSlot) internal view returns (GIndex);

_getHistoricalBlockRootGI​

function _getHistoricalBlockRootGI(Slot recentSlot, Slot targetSlot) internal view returns (GIndex gI);

_computeEpochAtSlot​

function _computeEpochAtSlot(Slot slot) internal view returns (uint256);

__checkRole​

function __checkRole(bytes32 role) internal view override;