Skip to content

feat(qbft_manager): wire PTC committee-scoped QBFT instances and fork gate #1035

Description

@shane-moore

Goal

Replace #1032's //todo(epbs) stub at the Some(Role::PTCCommittee) arm in qbft_manager/src/lib.rs::receive_data with real PTC plumbing: a new PTCCommitteeInstanceId, a fourth instance Map on QbftManager, routing in receive_data, a cleaner entry, and the QbftDecidable impl for PayloadAttestationVote. Fork-gate mirroring the AggregatorCommittee/Boole+ pattern.

Context

Per SIP-94 §3 (ssvlabs/SIPs#94), PTC runs one QBFT instance per cluster per slot over PayloadAttestationVote (introduced in #1034). The qbft_manager currently routes Role::PTCCommittee messages to the placeholder stub introduced in #1032, which rejects with RoleNotActive + a warn-log + a //todo(epbs) marker. This issue replaces the stub with the real instance map plumbing: PTC joins Committee, AggregatorCommittee, and Proposer as the fourth committee-scoped instance kind.

PayloadAttestationVote (the QBFT decision type for PTC) needs a QbftDecidable impl so the manager can map Role::PTCCommittee + CommitteeId to a deterministic message id, in the same style as the existing BeaconVote and AggregatorCommitteeConsensusData impls.

Suggested approach

anchor/qbft_manager/src/lib.rs:

  • Add PTCCommitteeInstanceId { committee: CommitteeId, instance_height: InstanceHeight }, mirroring the existing AggregatorCommitteeInstanceId.
  • Add a fourth Map<PTCCommitteeInstanceId, PayloadAttestationVote> field on QbftManager; initialize it in the constructor.
  • In receive_data, replace the Some(Role::PTCCommittee) stub arm (currently warn! + Err(QbftError::RoleNotActive) + //todo(epbs) line comment) with real routing next to Role::AggregatorCommittee. Fork-gate with if active_fork < Fork::CStar { return Err(QbftError::RoleNotActive); }. The //todo(epbs) line comment and the placeholder warn-log must be gone after this PR.
  • Add .retain(...) for the new map in cleaner, matching the TTL/eviction policy of the existing committee-scoped maps.
  • Add a QbftDecidable impl for PayloadAttestationVote. message_id() uses Role::PTCCommittee and DutyExecutor::Committee; structure should parallel the existing BeaconVote and AggregatorCommitteeConsensusData impls.

Acceptance criteria

  • QbftManager has four instance maps: Committee, AggregatorCommittee, Proposer, PTCCommittee.
  • receive_data routes Role::PTCCommittee messages to the new map.
  • Pre-CStar slot: receive_data returns Err(QbftError::RoleNotActive).
  • Post-CStar slot: PTC messages route into the new instance map.
  • cleaner retains the new map under the same TTL/eviction policy as the sibling committee maps.
  • QbftDecidable for PayloadAttestationVote produces a deterministic message_id matching the structural pattern of the existing BeaconVote / AggregatorCommitteeConsensusData impls.
  • The //todo(epbs) marker and placeholder warn-log from feat: add Role::PTCCommittee with message-validator fork-gate #1032 are gone. grep -r "//todo(epbs)" anchor/qbft_manager/ returns no hits.
  • New routing tests cover pre-CStar rejection and post-CStar acceptance, paralleling tests/aggregator_tests.rs::test_aggregator_committee_rejected_before_boole.
  • All pre-existing tests still pass.

Open questions

  • message_id byte composition. Existing QbftDecidable impls for BeaconVote / AggregatorCommitteeConsensusData (around qbft_manager/src/lib.rs:470-506) encode a specific layout. PTC must follow the same pattern; verify the exact byte composition at PR time against the in-tree impls rather than copy-pasting from any prior plan.

Risks

  • Cleaner eviction policy mismatch. PTC instances must be evicted under the same TTL as the other committee-scoped instances to bound memory; mirror AggregatorCommittee retention exactly. A divergence here leaks instance state across slots.
  • Stub-removal completeness. Two markers from feat: add Role::PTCCommittee with message-validator fork-gate #1032 must be removed: the //todo(epbs) line comment (visible/grep-able) and the placeholder warn!(...) (runtime). Easy to remove one and miss the other.

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