-
Notifications
You must be signed in to change notification settings - Fork 11.7k
Open
Description
Summary
The Linearizer can double-commit equivocating blocks at the same (Round, Author) slot due to incorrect commit status checking.
Problem Description
In linearize_sub_dag(), the commit status check uses is_committed(BlockRef) which includes the Digest:
.filter(|ancestor| {
ancestor.round > gc_round && !dag_state.is_committed(ancestor)
})Since two equivocating blocks have different digests, they are treated as different blocks. If Block A is committed first, is_committed(Block B) still returns false, allowing Block B to be committed later through a different DAG path.
Attack Scenario
- Byzantine validator V1 creates Block A (Round 1) and broadcasts to 60% of nodes
- Block A is committed via main chain
- V1 creates Block B (Round 1, same slot, different digest) and broadcasts to remaining 40%
- Some honest node (only received B) creates a block referencing B
- Block B propagates and passes BlockVerifier (signature is valid)
- A later Leader references Block B through a side chain
- When that Leader is committed, Linearizer traverses to Block B
is_committed(Block B)returnsfalse(different digest)- Block B is committed even though Block A was already committed!
Production Impact
consensus_gc_depth = 60in production (from sui-protocol-config)- This gives attackers a ~30-60 second window to execute the attack
- Violates consensus safety: same (Round, Author) slot committed twice
- Requires only 1 Byzantine validator (within f tolerance)
Proposed Fix
Add is_any_block_at_slot_committed(Slot) check to filter out ancestors where any block at that slot has already been committed:
.filter(|ancestor| {
ancestor.round > gc_round
&& !dag_state.is_committed(ancestor)
&& !dag_state.is_any_block_at_slot_committed((*ancestor).into())
})Why This Is Not a False Positive
Unlike issue #24475 which used invalid AuthorityIndex that BlockVerifier rejects:
- Equivocating blocks are valid VerifiedBlocks - BlockVerifier does NOT check for equivocation
- DagState intentionally accepts equivocating blocks - Only self-equivocation is blocked
- Production config allows attack - gc_depth=60 provides ample time window
Security Impact
- Severity: High (Safety violation)
- Attack Vector: Network (1 Byzantine validator)
- Impact: Same slot committed twice, violating consensus uniqueness
Metadata
Metadata
Assignees
Labels
No labels