Lenient slash behaviour
The reward system for observers is lenient. That is to say an observer is allowed to vote incorrectly on up to 50% of the votes, and they will still be rewarded; if they are wrong exactly 50% of the time, they get no rewards, but are not slashed; and ultimately if they get more than half of votes wrong, they are slashed.
While there is no security issue here, there is a lot of leeway for observers (e.g., in 1,000 votes, an observer is allowed to incorrectly vote on 499 of them). An alternative could be having a maximum number of incorrect guesses as a ratio of total guesses, depending on if this configuration is deemed insecure.
func DistributeObserverRewards(ctx sdk.Context, amount sdkmath.Int, keeper keeper.Keeper) error {
...
if observerRewardUnits == 0 {
finalDistributionList = append(finalDistributionList, &types.ObserverEmission{
EmissionType: types.EmissionType_Slash,
ObserverAddress: observerAddress.String(),
Amount: sdkmath.ZeroInt(),
})
continue
}
if observerRewardUnits < 0 {
slashAmount := keeper.GetParams(ctx).ObserverSlashAmount
keeper.SlashObserverEmission(ctx, observerAddress.String(), slashAmount)
finalDistributionList = append(finalDistributionList, &types.ObserverEmission{
EmissionType: types.EmissionType_Slash,
ObserverAddress: observerAddress.String(),
Amount: slashAmount,
})
continue
}
// Defensive check
if rewardPerUnit.GT(sdk.ZeroInt()) {
rewardAmount := rewardPerUnit.Mul(sdkmath.NewInt(observerRewardUnits))
keeper.AddObserverEmission(ctx, observerAddress.String(), rewardAmount)
finalDistributionList = append(finalDistributionList, &types.ObserverEmission{
EmissionType: types.EmissionType_Rewards,
ObserverAddress: observerAddress.String(),
Amount: rewardAmount,
})
}
...