Skip to content

Conversation

@SherlockShemol
Copy link

Description

This PR fixes a safety vulnerability where the Linearizer could double-commit equivocating blocks at the same (Round, Author) slot.

Fixes #24498

Problem

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.

Solution

Added is_any_block_at_slot_committed(Slot) method to check if ANY block at a given (Round, Author) slot has been committed, regardless of digest:

.filter(|ancestor| {
    ancestor.round > gc_round
        && !dag_state.is_committed(ancestor)
        && !dag_state.is_any_block_at_slot_committed((*ancestor).into())
})

Changes

  • dag_state.rs: Add is_any_block_at_slot_committed() method
  • linearizer.rs: Add trait method and use it in linearize_sub_dag()
  • test_dag_builder.rs: Implement trait method for test mock
  • equivocation_commit_test.rs: Add test cases

Test Plan

  • cargo test -p consensus-core equivocation_commit - New tests pass
  • cargo test -p consensus-core linearizer - Existing tests pass

…rizer

The Linearizer could double-commit equivocating blocks at the same
(Round, Author) slot because is_committed() checks full BlockRef
including Digest. Two blocks with same slot but different digests
were treated as separate blocks.

Fix: Add is_any_block_at_slot_committed() check to filter ancestors
where any block at that slot has already been committed.

Attack scenario:
1. Byzantine validator creates Block A (Round 1), commits via main chain
2. Same validator creates Block B (Round 1, different digest)
3. Block B propagates through side chain
4. Later leader commits Block B even though slot was already committed

The fix ensures only one block per (Round, Author) slot can be committed.

Fixes MystenLabs#24498

Signed-off-by: SherlockShemol <[email protected]>
@SherlockShemol SherlockShemol requested a review from a team as a code owner December 3, 2025 04:10
@vercel
Copy link

vercel bot commented Dec 3, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
sui-docs Ready Ready Preview Comment Dec 3, 2025 4:12am
2 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
multisig-toolkit Ignored Ignored Preview Dec 3, 2025 4:12am
sui-kiosk Ignored Ignored Preview Dec 3, 2025 4:12am

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(consensus): Linearizer double-commits equivocating blocks at the same slot

1 participant