Skip to content

Latest commit

 

History

History
76 lines (45 loc) · 2.7 KB

016.md

File metadata and controls

76 lines (45 loc) · 2.7 KB

Petite Fleece Cheetah

High

Slashing logic for finality providers does not work correctly in some cases

Summary

The problem is that the current implementation of the slashing functionality allows finality providers to skip some blocks and not get slashed eventually.

Root Cause

The root cause lies in the fact that the minHeight parameter is calculated the following way:

	minHeight := signInfo.StartHeight + signedBlocksWindow

So if the maxMissed values is set to 1 or 2, and there is a signedBlocksWindow equal to 10, for example, the non-genesis finality provider can basically skip some blocks in the current signedBlocksWindow and avoid being punished for sluggishness even though he can vote for the next height after which he's been added.

Internal Pre-conditions

External Pre-conditions

An attacker needs to be a non-genesis finality provider and skip the blocks

Attack Path

FP can miss voting for blocks without being jailed.

Impact

Some finality providers can escape voting even though they have to vote in the finality round.

PoC

Consider the current implementation:

https://github.com/sherlock-audit/2024-12-babylon/blob/main/babylon/x/finality/keeper/liveness.go#L79-84

	minHeight := signInfo.StartHeight + signedBlocksWindow
	maxMissed := signedBlocksWindow - minSignedPerWindow

	// if the number of missed block reaches the threshold within the sliding window
	// jail the finality provider
	if height > minHeight && signInfo.MissedBlocksCounter > maxMissed {

The FP is slashed in the case if the height is greater than the minHeight and MissedBlocksCounter is greater than maxMissed value. The problem is that non-genesis providers can start voting the one block after the startHeight:

https://github.com/sherlock-audit/2024-12-babylon/blob/main/babylon/x/finality/keeper/liveness.go#L139-141

	// A genesis finality provider will start at index 0, whereas a non-genesis finality provider's
	// startHeight will be the block they become active for, but the first block they vote on will be
	// one later. (And thus their first vote is at index 1)

So let's say there are the following params:

signedBlocksWindow = 10
startHeight = 17
maxMissed = 1

In this case, FP can start voting at block 18. Even though the maxMissed parameter is set to 1, they can easily miss all the remaining blocks for this window even though the maxMissed value is set to 1 due to the fact that their minHeight is set to startHeight + 10 (in this example). They can then sign the blocks with such indices in the next window and decrement the counter.

Mitigation

Consider implementing the special logic for the non-genesis finality providers.