mirror of
https://github.com/luxfi/consensus.git
synced 2026-09-24 00:26:58 +00:00
reportCertEquivocation logged a second, conflicting finality cert at an already-finalized height with Logger.Crit. In luxfi/log, Crit -> Fatal -> os.Exit(1). The per-height guard (AcceptViaCert -> ErrHeightAlreadyFinalized) has ALREADY preserved safety by REJECTING the second cert (no double-Accept, no fork) before this runs, so the Crit converted a correctly-handled safety event into a FLEET-WIDE LIVENESS KILL: every honest node that observes the gossiped conflicting cert calls os.Exit and the whole network goes down at once. It also made the slashing-evidence recording dead code (process exited before the loop ran), so the Byzantine voters were never slashed. Downgrade Crit -> Error. Safety is unchanged (the reject already happened); the equivocation is now logged and the DoubleVote evidence is actually recorded so the offender is slashed. A safety event must never be a self-DoS. Adds TestEquivocation_RealLogger_NoFleetWideExit: runs the two-cert-at-one- height scenario under a REAL logger (the existing tests use log.Noop(), whose IsZero()==true skipped the log call) in an isolated subprocess so an os.Exit(1) is observable. Negative control verified: with Crit the child exits 1 and the test FAILS; with Error it rejects the second cert, records evidence, and exits 0.