Invariants / CN-PROD-04

CN-PROD-04

CN derived enforced

Every CoordinatorEffect::BroadcastBlock reconstructs the AcceptedBlock from artifact.bytes through the BLUE self_accept authority against the pre-forge base, then admits it to the served ServedChainSnapshot via the single ServedChainHandle::push_atomic authority before the next slot tick. If the self_accept replay rejects, push_atomic is NOT called and the loop emits structured BroadcastPushError::SelfAcceptReplayRejected. ProducerLogEvent::BlockServed is emitted only for blocks present in the served snapshot. No silently-dropped (no-op) broadcast; only self-accepted forged blocks are served.

Source

docs/planning/phase4-n-t-invariants.md §1 (A4, A5); docs/clusters/PHASE4-N-T/cluster.md §1

Cluster
PHASE4-N-T
Introduced in
PHASE4-N-T

Enforcement trace

Tests 3

  • broadcast_pushes_self_accepted_block_to_served
  • broadcast_rejects_non_self_accepted_block
  • forge_to_served_block_fetch_roundtrip

CI 0

no CI script — gap

Cross-references

Strengthened in

Attack rationale

Cardano-specific: serving a block that failed self-accept (or silently dropping a forged block) would either propagate an invalid block to peers or advertise a chain the producer cannot actually serve. Gating push_atomic behind the self_accept replay and fail-closing on rejection makes 'served but not self-accepted' unrepresentable.

Evidence notes

S4 test broadcast_rejects_non_self_accepted_block (rejection -> no push, BroadcastPushError::SelfAcceptReplayRejected); S5 loopback test produce_forge_to_served_block_fetch_roundtrip (served block readable byte-identically via block-fetch). BlockServed is the existing closed ProducerLogEvent variant (producer_log.rs:154), emitted only for present blocks.