Category: Coding Mistakes
Floating values result in nondeterminism
Medium Severity
Medium Impact
Medium Likelihood
Description
The BeforeValidatorSlashed
function uses float values. This may result in nondeterministic behavior of rounding in the floating values.
func (h Hooks) BeforeValidatorSlashed(ctx context.Context, valAddr sdk.ValAddress, fraction math.LegacyDec) error {
...
for _, threshold := range thresholds {
// if a certain threshold voting power is slashed in a single epoch, emit event and trigger hook
if float64(slashedVotingPower) < float64(totalVotingPower)*threshold && float64(totalVotingPower)*threshold <= float64(slashedVotingPower+thisVotingPower) {
slashedVals := h.k.GetSlashedValidators(ctx, epochNumber)
slashedVals = append(slashedVals, thisVal)
event := types.NewEventSlashThreshold(slashedVotingPower, totalVotingPower, slashedVals)
if err := sdkCtx.EventManager().EmitTypedEvent(&event); err != nil {
panic(err)
}
h.k.BeforeSlashThreshold(ctx, slashedVals)
}
}
}
Impact
In this edge case, if any state changes happen in the branch executed due to nondeterministic behavior, such as the h.k.BeforeSlashThreshold
hook, the chain will halt.
Recommendations
Modify the logic to not use floating-point values.
Remediation
This issue has been acknowledged by Babylon Labs, and a fix was implemented in commit 8dccf6cc↗.
This issue was remediated by changing the logic to use Dec
values instead of floating point variables.