Skip to content

Conversation

@SherlockShemol
Copy link

@SherlockShemol SherlockShemol commented Nov 30, 2025

Summary

Add validation that Block.Parent() == Block.QuorumCert().BlockHash() in Voter.Verify() to prevent Byzantine leaders from creating malformed blocks.

The Bug

The protocol was missing a fundamental check: Block.Parent must equal Block.QC.BlockHash.

Without this check, a Byzantine leader can create a malformed block where:

  • Block.Parent points to an early/fork block
  • Block.QC points to the latest valid block (existing QC, no need to forge)

Attack Scenario

Honest chain: Genesis → A(V1) → B(V2) → C(V3) → D(V4) → E(V5)

Byzantine leader (View 6) creates MALFORMED block F:
  • F.Parent = A.Hash     ← Points to early block A, NOT E!
  • F.QC = QC(E)          ← Uses valid QC pointing to E (already exists!)
  • F.View = 6

Result: F.Parent ≠ F.QC.BlockHash
  Parent chain: F → A (skips B, C, D, E!)
  QC chain:     F.QC → E → D → C → B → A

Why Attack Works (Before Fix)

Step Action Why It Works
1 Byzantine creates malformed block NewBlock(parent, qc, ...) allows any combination
2 Sends via network BlockFromProto deserializes independently
3 Honest nodes verify VoteRule Liveness: qcBlock.View > bLock.View
4 Honest nodes vote! Voter.Verify had no Parent-QC check

Impact Without Fix

  1. Blockchain data structure inconsistency: Parent chain diverges from QC chain
  2. blockchain.Extends() returns incorrect results: It traverses Parent chain
  3. Liveness failure: Subsequent proposals inherit inconsistent state

The Fix

In protocol/consensus/voter.go, Verify() now checks:

if proposal.Block.Parent() != proposal.Block.QuorumCert().BlockHash() {
    return fmt.Errorf("block parent %s does not match QC block %s",
        proposal.Block.Parent().SmallString(),
        proposal.Block.QuorumCert().BlockHash().SmallString())
}

Test

twins/parent_qc_mismatch_test.go - Creates a malformed block and verifies Voter.Verify() correctly rejects it.

=== RUN   TestParentQCMismatch/ecdsa
    Voter.Verify correctly rejected malformed block: block parent vklOxXpi does not match QC block LHnEvFTW
--- PASS: TestParentQCMismatch (0.02s)

Fixes #283

@SherlockShemol SherlockShemol force-pushed the fix/highqc-update-extends-check branch from 5af44d7 to b7f6f1a Compare December 2, 2025 16:56
@SherlockShemol SherlockShemol changed the title fix: UpdateHighQC now rejects QCs that don't extend committed chain fix: add Parent-QC consistency check to prevent malformed blocks Dec 2, 2025
Add validation in Voter.Verify to ensure Block.Parent == Block.QC.BlockHash.

Without this check, a Byzantine leader could create malformed blocks where:
- Block.Parent points to an early block (e.g., Genesis)
- Block.QC points to a recent block (e.g., View 5)

This causes blockchain data structure inconsistency and incorrect
Extends() results, potentially leading to liveness failures.

Fixes relab#283
@SherlockShemol SherlockShemol force-pushed the fix/highqc-update-extends-check branch from b7f6f1a to d7616f8 Compare December 2, 2025 17:23
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.

Bug: Missing Parent-QC Consistency Check allows Byzantine to create malformed blocks

1 participant