Skip to content

fix: tolerate unknown proposer duty views and gate network-triggered QBFT spawn #1190

Description

@shane-moore

Goal

Migrate general Role::Proposer validation to the pubkey-keyed tri-state proposer assignment, tolerate Unknown rather than treating an absent duty view as negative evidence, and prevent network input from creating a proposer QBFT instance unless the dispatch-time verdict is authoritatively Assigned.

This is an Anchor correctness and resource-safety prerequisite. It is not an independent SIP-101 wire requirement. #1177 builds the candidate-specific Early RANDAO IGNORE handoff on top of this general proposer migration.

Context

At upstream/epbs 7bad23f, Role::Proposer validation still resolves a beacon validator index from local committee data and has a special first-slot RANDAO path. The proposer-preferences and envelope roles already query the validator pubkey through proposer_assignment_at_slot and reject only an authoritative NotAssigned result.

An absent complete proposer schedule is not evidence that a validator has no duty. Treating it as NoDuty can drop honest inbound messages. Tolerating it through validation, however, must not let network traffic allocate a new proposer QBFT instance for an unverified duty.

Duty-view contract

After #1183 and #1184:

  • Assigned means a retained complete schedule contains the validator at exactly the queried slot.
  • NotAssigned means a retained complete schedule exists and contains no such exact assignment.
  • Unknown means no complete schedule is retained for that epoch.

Only NotAssigned is authoritative negative evidence. Failed or malformed refreshes, local validator changes, execution_optimistic, and reorg detection do not create extra Unknown causes when a prior complete schedule exists. The prior schedule remains Known until a complete replacement is retained.

For general Proposer traffic, Assigned and Unknown continue validation, while NotAssigned returns NoDuty. For an eligible Early RANDAO candidate, #1177 ensures both Unknown and NotAssigned map to the protocol IGNORE verdict. SIP-101 permits optional retention for either state when duty assignment is the sole non-passing check, but Anchor's current #1178 policy offers only an otherwise-valid Unknown candidate through the internal UnknownProposerEpoch reason. That retention handoff is not part of this issue's general mapping.

Suggested approach

  • Merge the Role::Proposer duty lookup into the existing pubkey-keyed proposer-related path:
    • extract the validator pubkey from the MessageID;
    • query proposer_assignment_at_slot(slot, pubkey);
    • continue on Assigned or Unknown;
    • return NoDuty on NotAssigned.
  • Delete the validator-index lookup, empty-index failure, first-slot RANDAO carve-out, and legacy proposer-duty boolean helpers once they have no callers.
  • Keep this general validation mapping slot-independent and message-kind-independent. feat(message_validator): early RANDAO receiver rules: eligibility predicate, earliness window, ordering exemption, duty tri-state #1177 owns the narrower Early RANDAO candidate result.
  • Make QBFT dispatch two explicit operations:
    • receive-or-spawn for an authoritative Assigned verdict;
    • receive-if-present for Unknown, delivering only to an already-running instance and never allocating one.
  • Recompute the proposer assignment immediately before dispatch. A verdict can change between validation and dispatch.
  • Drop without buffering when dispatch sees NotAssigned, or when Unknown has no existing processor. Existing local instances may receive Unknown traffic because they were created by local duty execution or an earlier authoritative assignment.
  • Keep spawn-on-receive behavior for unrelated validator and committee QBFT roles unchanged.

Acceptance criteria

  • Missing local validator index data no longer causes a proposer message to be Rejected.
  • Assigned and Unknown continue general Proposer validation; NotAssigned yields NoDuty.
  • First-slot RANDAO uses the same tri-state path as every other slot.
  • No proposer index resolution or legacy epoch-known boolean remains in this path.
  • A proposer QBFT message can create an instance only when the dispatch-time verdict is Assigned.
  • Under Unknown, a message can reach an existing instance but cannot create one.
  • A validation-time Assigned result that becomes non-assigned before dispatch cannot spawn.
  • A validation-time Unknown that becomes Assigned before dispatch may use receive-or-spawn.
  • Other QBFT roles retain existing allocation behavior.
  • The implementation does not introduce root-stale, optimistic, disputed, or cause-specific duty states.

Tests

Cover all three general proposer message kinds under Assigned, NotAssigned, and Unknown; missing validator index data; identical first-slot and ordinary-slot behavior; pubkey extraction; validation-to-dispatch verdict changes; receive-or-spawn only under dispatch-time Assigned; receive-if-present under Unknown; no allocation under Unknown or NotAssigned; delivery to a pre-existing instance; and unaffected controls for another validator QBFT role and a committee role.

Preserve the duties-tracker tri-state tests, updated to the complete-schedule authority contract from #1183 and #1184.

Notes

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

Metadata

Metadata

Assignees

Labels

epbsePBS / EIP-7732 / Gloas implementation

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions