v1.3.6 — Remove catch-up wave skipping (determinism fix pt.4)
Remove catch-up wave skipping (determinism fix pt.4)
The final piece of the cross-validator determinism pipeline: the
isCatchingUp code paths in bullshark.tryCommitLocked() that let each
validator unilaterally skip waves once its local DAG advanced 8+ rounds
past the leader round.
Because the DAG advances asynchronously across validators, different
nodes entered catch-up mode at different rounds and skipped different
waves, producing divergent committed sequences — exactly the same class
of fork the v1.3.1–v1.3.5 fixes were addressing, just via a path I
missed in earlier iterations.
Fixed paths
bullshark.go — three former isCatchingUp branches all removed:
-
leaderCert == nil+ catching up → unconditional skip
→ now falls through tocheckLeaderTimeoutLocked(DAG-based view
change, identical across validators). -
support >= QuorumSize+ catching up → commit bs.committedRound
WITHOUT emitting a CommitDecision, effectively dropping the
corresponding block on catching-up validators
→ now emits the same commit decision whether catching up or not. -
support < QuorumSize+ catching up → unconditional skip
→ now falls through tocheckInsufficientSupportTimeoutLocked
(DAG-based, identical across validators).
Testnet verification
Coordinated restart on the 4-validator Digital Ocean testnet. Chain
expected to remain in full consensus indefinitely across all validators.
Upgrade notes
Chain data MUST be wiped (consensus semantics change — existing chains
may have committed waves under the old catch-up logic that don't replay
cleanly under the new one).