Skip to content

User Stories for RPIP-73: rETH Protection From Underperforming Nodes

RPIP-73 introduces a permissionless, optimistic on-chain challenge mechanism to exit significantly underperforming or abandoned Rocket Pool validators. The mechanism is designed to protect rETH yield from being dragged down by offline validators while utilising a high economic bond to deter griefing and false challenges.


Challenge Lifecycle Diagram

The diagram below illustrates the lifecycle of a performance challenge under RPIP-73:

flowchart TD
    Start([One or more validators underperform]) --> Challenge[Challenger submits challenge against a list of validators]
    Challenge --> LockBond[100 RPL Bond locked]
    LockBond --> Period{24-Hour Challenge Period}

    Period -- Defender proves participation in >=1 epoch for a listed validator --> Defeat[Entire list Defeated]
    Period -- Defender proves a listed validator's activation_epoch > start_epoch --> Defeat
    Defeat --> Slash[Challenger's 100 RPL sent to Defender]
    Slash --> EndDefeated([Challenge Cancelled])

    Period -- 24 hours pass uncontested --> Finalise[Challenger/anyone finalises exit]
    Finalise --> Queue[Validators queued for Exit RPIP-80]
    Queue --> Refund[100 RPL Bond refunded to Challenger]
    Refund --> EndExited([Validator Exits Initiated])

Actors

  • Challenger: A Node operator with RPL staked and governance locking approved, monitors validator performance. They initiate challenges against a list of one or more underperforming validators by locking a bond.
  • Defender: A Node operator with RPL staked and governance locking approved, attempts to either find a single valid epoch for a listed validator, or prove a listed validator wasn't yet active, to defeat the entire challenge and claim the challenger's bond.
  • pDAO / Security Council: The governance bodies responsible for enabling/disabling the mechanism and tuning the protocol parameters.
  • rETH Holders: The beneficiaries of the proposal, whose yield is protected by the removal of non-performing validators.

Protocol Parameters

Parameter Type Initial Value Description
performance_exits_enabled* bool true Emergency pause/unpause for the challenge mechanism.
performance_period Epochs 44032 (~200 days) The rolling window used to evaluate validator performance.
proof_buffer Epochs 225 (Guardrail: > 10) Extra time after performance_period during which a challenge's start_epoch is still valid, giving challengers time to detect underperformance and generate proofs.
performance_threshold pct 94 The minimum performance percentage required to avoid challenges.
performance_challenge_period Hours 24 The time window allowed for anyone to defeat a challenge.
performance_challenge_bond RPL 100 (Guardrail: > 20) The amount of RPL that a challenger must lock.

*Modifiable by the Security Council without delay.


Epic 1: Parameter Management

1.1: Emergency Enable/Disable

As a Security Council Member,
I want to toggle performance_exits_enabled on or off,
So that I can pause the challenge mechanism during consensus bugs, network splits, or security incidents.

  • Acceptance Criteria:
    • Only Security Council proposal can toggle the setting.
    • When disabled:
      • New challenges cannot be created.
      • Active challenges can still be defeated by defenders (to prevent challengers from being trapped if a pause occurs during their challenge window).
      • Active challenges cannot be finalised/exited.
    • Toggling emits an event.

1.2: Parameter Tuning

As the pDAO,
I want to adjust the performance thresholds, periods, and bonds via on-chain governance voting,
So that the protocol can adapt to changes in network performance expectations.

  • Acceptance Criteria:
    • Updates to performance_period, proof_buffer, performance_threshold, performance_challenge_period, and performance_challenge_bond can only be initiated by pDAO proposal.
    • The update proposal reverts with a clear error when attempting to set proof_buffer to a value less than or equal to 10 epochs.
    • The update proposal executes only when setting performance_challenge_bond to any value greater than or equal to 20 RPL, emitting a event.
    • The update proposal reverts with a clear error when attempting to set performance_challenge_bond to a value less than 20 RPL.
    • Parameter updates do not retroactively alter the rules or bonds of active challenges.

Epic 2: Challenging Validator Performance

2.1: Challenge a List of Validators

As a Challenger,
I want to submit a performance challenge on-chain for a list of underperforming validators by providing the start epoch, the list of missed epochs, and locking a single required RPL bond,
So that I can exit the underperforming validators in one transaction.

  • Acceptance Criteria:
    • The challenger must call proposeValidatorExit providing:
      • validatorIndices of the target validators (one or more).
      • startEpoch, which must be greater than currentEpoch - performance_period - proof_buffer.
      • A representation of the performance_period * (1 - performance_threshold) epochs (e.g. 2,642 epochs) where the listed validators supposedly missed target attestations.
    • The contract locks a single performance_challenge_bond RPL from the challenger node operator stake, covering the whole list.
    • The transaction reverts if:
      • performance_exits_enabled is false.
      • Any validator in the list is already in an active challenge.
      • Any validator in the list is already queued for exit.
      • The number of epochs provided is less than performance_period * (1 - performance_threshold).
      • startEpoch is not greater than currentEpoch - performance_period - proof_buffer.
      • Any provided epoch lies outside the [startEpoch, min(currentEpoch, startEpoch + performance_period)] range.
    • Emits an event.

2.2: Defeat an Invalid Challenge

As a Defender I want to submit proof of either a single successful timely target attestation for one of the challenged epochs, or that a listed validator was not yet active when the challenge claims it missed attestations,
So that I can cancel the exit process for the entire list and claim the challenger's locked RPL bond.

  • Acceptance Criteria:
    • The defender must call defeatChallenge providing one of the following proofs for at least one validator in the challenged list:
      • Attestation proof:
        • challengeId or validatorIndex of the active challenge.
        • The specific epoch number being proven.
        • Proof that this epoch was included in the challenger's dataset.
        • A proof verifying that previous_epoch_participation in the Beacon State for that epoch contains a timely target attestation.
      • Activation proof:
        • challengeId or validatorIndex of the active challenge.
        • A proof that the validator's activation_epoch is greater than the challenge's startEpoch.
    • The contract verifies the proof using the on-chain Beacon block root history (e.g. EIP-4788).
    • If either proof is verified for any validator in the list:
      • The entire challenge (covering all listed validators) is marked as defeated
      • The locked performance_challenge_bond RPL is sent to the defender, minus a burn amount.
      • Emits an event.
    • The transaction reverts if proof is unverified, or the performance_challenge_period has expired, or the challenge was already finalised/defeated.

2.3: Finalise Uncontested Challenge

As a Challenger,
I want to finalise a challenge once the performance_challenge_period has elapsed without being defeated,
So that all the validators in my list are exited and my locked RPL bond is returned.

  • Acceptance Criteria:
    • Anyone can call finalizeChallenge after performance_challenge_period (24 hours) from the challenge submission.
    • The transaction reverts if:
      • The challenge was defeated.
      • The 24-hour period has not yet elapsed.
    • If successful:
      • All validators in the challenged list are registered as "requested to exit" in the protocol (initiating RPIP-80 exit flow).
      • The locked RPL bond is returned to the challenger.
      • The challenge is marked as finalised and removed from active storage.
      • Emits an event.

Epic 3: Monitoring & Tooling

3.1: Smart Node Alerting

As a Rocket Pool Node Operator,
I want to see on my Grafana dashboard if any of my validators are challenged,
So that I am aware of the challenge

  • Acceptance Criteria:
    • The alert displays whether any of my validators are challenged

3.2: Community Monitoring

As the Rocket Pool community, I want to see what nodes/validators have been challenged, So that we can see the system exiting under-performing nodes

  • Acceptance Criteria:
    • Website feature that displays summary of challenges

Questions

  • ~~Support multiple challenges in single transaction?~~ Resolved: yes — RPIPs PR #384 introduces list-based challenges covering one or more validators under a single bond.
  • Should we enforce a max concurrent challenges?
  • Should owner have the opportunity to defeat first? (prevent pile on and provides NO with bond)
  • Burn on defeat? for the RPL transfer issue - not an issue with megapool but is for minipool
  • Do we use merkle tree submission? or call data?
  • There is currently no profit motive to challenge... I guess there is if there is a queue