Assessment reports>Hyperliquid>Threat Models>updateValidatorSet

Function: updateValidatorSet(ValidatorSetUpdateRequest newValidatorSet, ValidatorSet activeHotValidatorSet, address[] signers, Signature[] signatures)

This function can be called to initiate an update to the validator set.

Inputs

  • newValidatorSet

    • Control: Arbitrary.

    • Constraints: hotAddresses, coldAddresses, and powers array lengths must match; newValidatorSet.epoch > activeHotValidatorSet.epoch; and cumulative power must be greater than zero.

    • Impact: New validator set.

  • activeHotValidatorSet

    • Control: Arbitrary.

    • Constraints: makeValidatorSetHash(activeHotValidatorSet) == hotValidatorSetHash.

    • Impact: Active validator set --- used to validate the request.

  • signers

    • Control: Arbitrary.

    • Constraints: Length must match signatures.

    • Impact: Addresses of the signers of the request.

  • signatures

    • Control: Arbitrary.

    • Constraints: Length must match signers, and signatures must correspond with signers entries.

    • Impact: Signatures authorizing the validator set update.

Branches and code coverage (including function calls)

Intended branches

  • Validates the new set, checks the signature from the current set, and stores the pending validator set update.

Negative behavior

  • Reverts if the provided active validator hash set does not match.

  • Reverts if the lengths of the arrays in the new validator set do not match.

  • Reverts if the epoch of the new validator set is not greater than the epoch of the active validator set.

  • Reverts if a signature does not match the corresponding signer.

  • Reverts if a signature is invalid.

  • Reverts if the signers' total voting power is insufficient.

  • Reverts if the new total voting power is zero.

Function call analysis

  • rootFunction -> makeValidatorSetHash(activeHotValidatorSet)

    • What is controllable? activeHotValidatorSet.

    • If return value controllable, how is it used and how can it go wrong? Compared against the expected hot validator set hash.

    • What happens if it reverts, reenters, or does other unusual control flow? Reverts bubble up; reentrancy is not possible (no external calls).

  • rootFunction -> hash(agent)

    • What is controllable? agent (indirectly).

    • If return value controllable, how is it used and how can it go wrong? Hash representing the action being performed.

    • What happens if it reverts, reenters, or does other unusual control flow? Reverts bubble up; reentrancy is not possible (no external calls).

  • rootFunction -> updateValidatorSetInner(...)

    • What is controllable? newValidatorSet, activeHotValidatorSet, signers, signatures, and message (indirectly, it is a hash).

    • If return value controllable, how is it used and how can it go wrong? N/A.

    • What happens if it reverts, reenters, or does other unusual control flow? Reverts bubble up; reentrancy is not possible (no external calls).

  • updateValidatorSetInner -> checkNewValidatorPowers(newValidatorSet.powers)

    • What is controllable? newValidatorSet.powers.

    • If return value controllable, how is it used and how can it go wrong? Used as the sum of the voting powers.

    • What happens if it reverts, reenters, or does other unusual control flow? Reverts bubble up; reentrancy is not possible (no external calls).

  • updateValidatorSetInner -> checkValidatorSignatures(message, activeValidatorSet, signers, signatures, validatorSetHash)

    • What is controllable? message, activeValidatorSet, signers, and signatures.

    • If return value controllable, how is it used and how can it go wrong? N/A.

    • What happens if it reverts, reenters, or does other unusual control flow? Reverts bubble up; reentrancy is not possible (no external calls).

  • checkValidatorSignatures -> makeValidatorSetHash(activeValidatorSet)

    • What is controllable? activeValidatorSet.

    • If return value controllable, how is it used and how can it go wrong? Not meaningfully controllable, compared against the expected validator set hash.

    • What happens if it reverts, reenters, or does other unusual control flow? Reverts bubble up; reentrancy cannot happen (no external calls).

  • checkValidatorSignatures -> recoverSigner(message, signatures[signerIdx], domainSeparator)

    • What is controllable? message and signatures[signerIdx].

    • If return value controllable, how is it used and how can it go wrong? Not meaningfully controllable, compared against the expected signer; it is not possible to forge a signer's address.

    • What happens if it reverts, reenters, or does other unusual control flow? Reverts bubble up; reentrancy cannot happen (no external calls).

  • updateValidatorSetInner -> makeValidatorSetHash(newHotValidatorSet)

    • What is controllable? newHotValidatorSet.

    • If return value controllable, how is it used and how can it go wrong? Used as the hash of the new hot validator set.

    • What happens if it reverts, reenters, or does other unusual control flow? Reverts bubble up; reentrancy is not possible (no external calls).

  • updateValidatorSetInner -> makeValidatorSetHash(newColdValidatorSet)

    • What is controllable? newHotValidatorSet.

    • If return value controllable, how is it used and how can it go wrong? Used as the hash of the new cold validator set.

    • What happens if it reverts, reenters, or does other unusual control flow? Reverts bubble up; reentrancy is not possible (no external calls).

Zellic © 2025Back to top ↑