Skip to content

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

@SherlockShemol

Description

@SherlockShemol

Description

The UpdateHighQC function in protocol/viewstates.go only checks if the new QC's block has a higher view than the current HighQC. It does not verify that the new QC extends the committed chain.

Impact

  • Safety: Not violated (VoteRule's bLock check provides defense in depth)
  • Liveness: At risk - node may try to propose on invalid forks
  • Resources: Wasted on processing invalid branches

Root Cause

func (s *ViewStates) UpdateHighQC(qc hotstuff.QuorumCert) (bool, error) {
    newBlock, ok := s.blockchain.Get(qc.BlockHash())
    if !ok {
        return false, fmt.Errorf("block not found")
    }
    s.mut.Lock()
    defer s.mut.Unlock()
    if newBlock.View() <= s.highQC.View() {  // ❌ Only checks View
        return false, nil
    }
    s.highQC = qc  // Updates without checking if extends committed chain
    return true, nil
}

Expected Behavior

UpdateHighQC should reject QCs whose blocks do not extend the committed chain.

Reproduction

See test case TestHighQCUpdateBug_Demonstration in twins/highqc_update_bug_test.go.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions