The global counterpart of #591's seam, and a harder failure: a single unauthenticated message halts the chain.
The consensus digest is Poseidon(header.output) and commits to nothing else — not frame_number. Channel-3 block ingress in activate_global_consensus_cw recorded digest → frame_number from unvalidated peer bytes, so any peer can pair a real frame's output with an arbitrary height and land it on that frame's digest. GlobalSeamProposer::propose then asks the leader provider to build at that height and gets "needs sync" on every view it leads. The clock-store fallback does not cover this: a poisoned entry is an index hit, not the miss the fallback was added for.
Worse than the app side in one respect — CwInboundRouter::route (cw_consensus_bridge.rs:102) forwards channel 3 with no sender check at all, so the bytes need not come from a peer the node has authenticated.
Repro: global_consensus_cw_survives_forged_parent_height_gossip in crates/quil-engine/tests/e2e_consensus.rs. Against unfixed source the chain finalizes frame 1 and dies, spinning views to 3000+ on prove_next_state failed … needs sync: consensus parent is frame 1, told 1000001 — after exactly one forged message.
Fixed in #607.
The global counterpart of #591's seam, and a harder failure: a single unauthenticated message halts the chain.
The consensus digest is
Poseidon(header.output)and commits to nothing else — notframe_number. Channel-3 block ingress inactivate_global_consensus_cwrecordeddigest → frame_numberfrom unvalidated peer bytes, so any peer can pair a real frame'soutputwith an arbitrary height and land it on that frame's digest.GlobalSeamProposer::proposethen asks the leader provider to build at that height and gets "needs sync" on every view it leads. The clock-store fallback does not cover this: a poisoned entry is an index hit, not the miss the fallback was added for.Worse than the app side in one respect —
CwInboundRouter::route(cw_consensus_bridge.rs:102) forwards channel 3 with no sender check at all, so the bytes need not come from a peer the node has authenticated.Repro:
global_consensus_cw_survives_forged_parent_height_gossipincrates/quil-engine/tests/e2e_consensus.rs. Against unfixed source the chain finalizes frame 1 and dies, spinning views to 3000+ onprove_next_state failed … needs sync: consensus parent is frame 1, told 1000001— after exactly one forged message.Fixed in #607.