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.
Description
The
UpdateHighQCfunction inprotocol/viewstates.goonly 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
Root Cause
Expected Behavior
UpdateHighQCshould reject QCs whose blocks do not extend the committed chain.Reproduction
See test case
TestHighQCUpdateBug_Demonstrationintwins/highqc_update_bug_test.go.