Skip to content

feat(qbft_manager): shorten proposer QBFT round timeout to 1.5s (SIP-102) #1324

Closed

Description

@shane-moore

Goal

Shorten the proposer QBFT quick-round timeout from 2s to 1.5s (SIP-102), and add a --legacy-proposer-round-timeout flag that restores 2s, matching go-ssv #3044. Target the epbs RC so both clients run 1.5s on Sepolia from its Gloas fork (epoch 353024, 2026-10-06 13:53 UTC).

Context and motivation

Gloas moves the attestation deadline from 4s to 3s into the slot. A proposer QBFT instance starts about 1.1s to 1.5s into the slot (RANDAO pre-consensus, proposer delay, block fetch). With a 2s round, a round change starts round 2 after the deadline, so a round change that is usually recoverable today usually misses the slot. The SIP projects network-wide missed proposals at about 42 a month with 2s and about 26 a month with 1.5s.

On epbs at 9f9b183:

  • anchor/qbft_manager/src/timeout.rs:8 sets QUICK_TIMEOUT to 2s for both timer modes. single_round_timeout (timeout.rs:50) serves TimeoutMode::Relative.
  • TimeoutMode::Relative is documented as block-proposal timing (anchor/qbft_manager/src/lib.rs:62), and its only production constructor is the proposer path in decide_abstract_block (anchor/validator_store/src/lib.rs:971). Every other duty uses SlotTime, which this change leaves alone.
  • The relative timer starts when the instance starts and restarts on a local timeout or on a network round advance (anchor/qbft_manager/src/instance.rs). This already matches SIP-102's rule that each round is timed from when that round starts.
  • The proposer round cap is 2 (anchor/common/ssv_types/src/msgid.rs:82). At round-2 expiry, end_round completes the instance as timed out (anchor/common/qbft/src/lib.rs:1233). go-ssv #3041 does the same.

go-ssv merged #3044 into epbs-gloas on 2026-09-28. It is not fork-gated and adds LegacyProposerRoundTimeout (default false) as the rollback path. go-ssv calls it a committee-wide parameter: a rollback only takes effect once at most f operators of a committee still run 1.5s. In committees where Anchor runs more than f operators, go-ssv's flag cannot roll the committee back, so Anchor needs the same switch.

Suggested approach

  • Give TimeoutMode::Relative the per-round duration, and use it in single_round_timeout for quick rounds. Export 1.5s and 2s constants from qbft_manager.
  • Add a --legacy-proposer-round-timeout bool CLI flag whose help text carries go-ssv's committee-wide warning. Resolve it in client config, log at info when it is set, and pass the resulting duration through AnchorValidatorStore::new to the proposer TimeoutMode::Relative.
  • No fork gate, matching go-ssv.

Acceptance criteria

  • A proposer QBFT instance runs 1.5s rounds by default: round 1 from instance start, round 2 from round-2 entry, then gives up at the existing cap of 2.
  • With --legacy-proposer-round-timeout, proposer rounds are 2s, and startup logs that the legacy timeout is active.
  • SlotTime duties (committee, aggregator, sync committee, aggregator committee) keep their current timing.
  • No message validation change, no round-cap change.
  • Regenerated CLI reference (make cli-reference-update).

Tests

  • qbft_manager paused-time timer tests: Relative completes a two-round instance in 3s with the SIP-102 value and 4s with the legacy value. Existing Relative expectations are updated.
  • validator_store: the proposer path through sign_block hands QBFT the configured timeout, both default and legacy.
  • client: from_cli resolves 1.5s by default and 2s with the flag.

Notes

  • No message-validator change. A role-aware round estimate in consensus_message.rs would change nothing for the proposer. The allowed range is round 1 up to estimate + MAX_ALLOWED_ROUNDS_FUTURE (3), and the estimate is at least 1, so the upper limit is at least 4, which is above the cap of 2 (consensus_message.rs:313, :370).
  • No fork gate. go-ssv applies 1.5s unconditionally, so gating only Anchor would create committees running mixed timers before Gloas.
  • Residual risks accepted:
    • A round 1 that would have decided between 1.5s and 2.0s is now cut off. go-ssv's slowest observed mainnet round 1 was 1148ms. Anchor's round-1 durations under Gloas have not been measured yet, and Sepolia is where to measure them.
    • During a mixed-version rollout, a single 1.5s operator with one other operator offline can lose a round-1 quorum that 2s timers would reach. The SIP's "never worse than today" claim does not hold in that case.
  • Open SIP wording point: SIP-102 says an instance stays in round 2 until it decides or the duty ends. Both clients give up at round-2 expiry instead.

Issues are directionally correct, not prescriptive; verify symbols at PR time.

Activity

  1. shane-moore commented on Sep 29, 2026

    @shane-moore
    MemberAuthor

    Closed by #1325, merged to epbs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    epbsePBS / EIP-7732 / Gloas implementation

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions