Skip to content

feat(message_receiver): quarantine Unknown-view Early RANDAO shares and promote on complete duty install #1178

Description

@shane-moore

Blocked by: #1177, #1183, and #1184

Goal

Implement Anchor's Unknown-only subset of SIP-101's optional duty-assignment retention: keep an otherwise-valid Early RANDAO candidate locally when its proposer-duty view is Unknown, then fully revalidate it after a complete proposer schedule is installed. SIP-101 also permits retaining Known-unassigned candidates when duty assignment is their sole non-passing check, but Anchor initially does not admit that higher-supply class.

SIP-101 makes retention a receiver MAY, and permits implementation-specific earlier discard. Anchor intentionally includes Unknown retention in the Early RANDAO milestone because it can recover shares that arrived before the beacon-node duty response. Keeping Known-unassigned outside Anchor's initial cache is a conformant local policy choice. Once Anchor retains a candidate, the SIP's admission, isolation, and promotion safety requirements are mandatory.

Dependency model

#1176 remains closed. Its current and next epoch duty-fetch work was absorbed by #1182. The remaining chain is:

  1. refactor(duties_tracker): retain proposer-duty v2 response metadata #1183 retains and shape-validates complete proposer-duty responses.
  2. fix(duties_tracker): authoritative complete-schedule transitions for proposer assignment verdicts #1184 atomically installs complete schedules and provides proposer_duties_watch().
  3. This issue consumes that watch to retry retained candidates.

The watch is therefore not lost when #1176 stays closed.

Protocol classification

The initial gossip verdict for an otherwise-valid candidate under either Unknown or Known-unassigned is always IGNORE, whether retention is enabled or disabled. SIP-101 permits local retention for either state when duty assignment is the sole non-passing check, and a receiver that retains neither remains conformant.

Anchor initially admits only Unknown candidates. Known-unassigned candidates keep the same wire-visible IGNORE and are not retained. This narrows continuous operator-signature verification, cache-contention, and revalidation exposure while preserving recovery for missing duty views.

If Anchor retains the candidate, it must satisfy these SIP requirements:

  • Before retention, the candidate passed operator-signature verification and every applicable message-validation rule other than duty assignment.
  • Initial retention does not forward the message, penalize the peer, feed signature collection or a reconstruction cache, or mutate ordinary validation state.
  • Promotion performs full validation again against the then-current duty view and applies every stateful rule at that time.
  • Promotion does not retroactively forward the original message or change its original gossip verdict.
  • A candidate reaches signature collection only after successful promotion or normal acceptance.
  • Normal lateness decides whether promotion can still succeed, whether attempted before or after the proposal slot.
  • Full revalidation success permits local consumption. If duty assignment remains the only non-passing check, the SIP permits the candidate to remain retained under local policy. Any other applicable validation failure requires discard.

Capacity, keying, duplicate handling inside the retention store, eviction, expiry, persistence, and earlier discard are implementation-specific. Anchor must bound operator-signature verification, local memory, and revalidation work, but cross-client conformance does not depend on an exact cache size or eviction algorithm.

Current code

At upstream/epbs 7bad23f, message_receiver::manager owns validation, the gossipsub outcome, interest filtering, and downstream dispatch. That makes the manager the correct retention boundary. message_validator should identify the internal candidate-specific Unknown outcome, but it must not own retained network messages or promotion dispatch.

Suggested approach

  • Add a bounded in-memory retention store owned by message_receiver::manager. Choose and document a finite Anchor-local capacity and deterministic local behavior at PR time. Do not describe those choices as SIP requirements.
  • Retain the original bytes and all context required to re-run the ordinary receive validation path. Keep enough identity information for bounded duplicate handling and observability. The exact key is an Anchor implementation choice.
  • Admit only feat(message_validator): early RANDAO receiver rules: eligibility predicate, earliness window, ordering exemption, duty tri-state #1177's internal UnknownProposerEpoch outcome after all non-duty checks have passed. That internal outcome maps to the same wire-visible IGNORE as a receiver with retention disabled.
  • Close the Unknown-to-Known admission race. Recheck the current duty view after inserting the entry, or use a duty-view generation protocol with the same effect. If a complete view became visible after feat(message_validator): early RANDAO receiver rules: eligibility predicate, earliness window, ordering exemption, duty tri-state #1177 returned Unknown but before admission completed, claim the entry and immediately run full promotion revalidation against the current view instead of waiting for another watch notification. Admission and watch-driven promotion must not claim the same entry twice.
  • Do not use cause-based retention eligibility. Under refactor(duties_tracker): retain proposer-duty v2 response metadata #1183 and fix(duties_tracker): authoritative complete-schedule transitions for proposer assignment verdicts #1184, Unknown means only that Anchor has no retained complete schedule for the candidate's epoch. A failed or malformed refresh leaves the prior complete view authoritative when one exists.
  • Apply the existing receiver interest filter before admission. SIP-101 permits retention to be scoped to committees Anchor participates in.
  • Return the original gossip IGNORE on initial admission. The admission step itself must not dispatch, forward, penalize, write validation state, or call signature_collector. If the race check finds that the view is already Known, any immediate promotion is a separate full-revalidation pass and still does not change the original verdict or forward the original message.
  • Subscribe to fix(duties_tracker): authoritative complete-schedule transitions for proposer assignment verdicts #1184's watch. After a complete schedule is visible, select retained candidates for that epoch and re-run them through the full validation path with a promotion origin that emits no gossipsub verdict and never forwards the original.
  • Dispatch locally only when full revalidation accepts. If revalidation remains Unknown, keep or discard according to bounded local policy. If it becomes Known-unassigned, discard under Anchor's Unknown-only policy. If any non-duty rule fails, discard as required by the SIP. Local expiry or eviction may discard an entry earlier.
  • Ensure concurrent view replacements and promotion attempts cannot bypass full revalidation or dispatch an entry twice.
  • Record bounded, low-cardinality metrics for admission, local discard reason, promotion attempt, promotion success, and promotion failure.

Acceptance criteria

  • Retention can be disabled without changing the initial IGNORE verdict or cross-client behavior.
  • An otherwise-valid Unknown candidate can be retained before the target epoch's complete schedule arrives, including before wall-clock Gloas when its target slot is Gloas-eligible.
  • Initial retention causes no forwarding, peer penalty, ordinary validation-state mutation, signature collection, reconstruction-cache input, or local duty dispatch.
  • A complete schedule install wakes promotion only after the new view is visible.
  • If a complete schedule becomes visible between the Unknown classification and completed retention admission, the candidate is reconsidered exactly once without waiting for a later schedule install.
  • Promotion runs full validation and applies stateful rules exactly once before local dispatch.
  • A promotion attempt that remains Unknown is not treated as a mandatory hard failure; bounded local policy may retain, expire, evict, or discard it.
  • A promotion attempt that becomes Known-unassigned is discarded under Anchor's Unknown-only policy, while any non-duty validation failure requires discard.
  • Known-unassigned keeps the protocol IGNORE verdict but is not admitted under Anchor's initial policy. Bad operator signature, too-early, too-late, duplicate, malformed, and otherwise invalid messages are never admitted through this path.
  • Failed or malformed duty refreshes do not trigger promotion and do not turn a prior complete view into Unknown.
  • The cache has finite Anchor-local resource bounds. Its exact capacity and eviction behavior are not treated as wire-conformance requirements.
  • A promoted candidate is never retroactively forwarded and its original gossip verdict remains IGNORE.

Tests

Cover retention enabled and disabled with the same initial IGNORE; admission before the duty response; no admission for Known-unassigned under Anchor's initial policy; no admission for every non-duty failure class; no state, collector, forwarding, or dispatch side effects at admission; complete-view watch visibility; successful promotion; a repeated Unknown result following bounded local retention policy rather than mandatory failure discard; Known-unassigned and hard-failure discard; promotion before and after S under the ordinary lateness rule; failed and malformed refreshes; duplicate promotion suppression; cache capacity and local eviction behavior; restart clearing an in-memory cache; a complete install between the Unknown verdict and cache insertion; concurrent replacement while promotion selects entries; and assertions for no missed reconsideration or double dispatch.

Issues are directionally correct, not prescriptive. Verify symbols and the local cache policy at PR time.

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