Slow Misty Iguana
Medium
totalPower's inclusion of the slashed provider's voting power may result in a vote never reaching a 2/3 quorum
totalPower's inclusion of the slashed provider's voting power may result in a vote never reaching a 2/3 quorum
totalPower's inclusion of the slashed provider's voting power
There are providers being slashed
result in a vote never reaching a 2/3 quorum , blocks can never enter Finalize state and chains cannot work.
TheAddFinalitySig
function is used to add the vote, but if the provider is in theslashed
state, this function returns an error.
Therefore, the slashed provider cannot vote.
// AddFinalitySig adds a new vote to a given block
func (ms msgServer) AddFinalitySig(goCtx context.Context, req *types.MsgAddFinalitySig) (*types.MsgAddFinalitySigResponse, error) {
.......
if fp.IsSlashed() {
return nil, bstypes.ErrFpAlreadySlashed.Wrapf("finality provider public key: %s", fpPK.MarshalHex())
}
if fp.IsJailed() {
return nil, bstypes.ErrFpAlreadyJailed.Wrapf("finality provider public key: %s", fpPK.MarshalHex())
}
.......
}
But the problem is thattotalPower
is calculated based onVotingPowerTable
and does not subtract Slashed VotingPower
:
func (k Keeper) TallyBlocks(ctx context.Context) {
......
// get the finality provider set of this block
-> fpSet := k.GetVotingPowerTable(ctx, ib.Height)
switch {
case fpSet != nil && !ib.Finalized:
// has finality providers, non-finalised: tally and try to finalise the block
voterBTCPKs := k.GetVoters(ctx, ib.Height)
-> if tally(fpSet, voterBTCPKs) {
// if this block gets >2/3 votes, finalise it
k.finalizeBlock(ctx, ib)
} else {
// if not, then this block and all subsequent blocks should not be finalised
// thus, we need to break here
break finalizationLoop
}
......
}
func tally(fpSet map[string]uint64, voterBTCPKs map[string]struct{}) bool {
totalPower := uint64(0)
votedPower := uint64(0)
for pkStr, power := range fpSet {
totalPower += power
if _, ok := voterBTCPKs[pkStr]; ok {
votedPower += power
}
}
return votedPower*3 > totalPower*2
}
AddFinalitySig
can vote on multiple blocks, assuming that two blocks are voting at the same time,
The current block height is n+2, and theVotingPowerTable
now contains the voting power of both blocks n and n+1.
provider votes for block n, at which point the provider is slashed and his vote for block n is valid(block n is fine),
But for block n+1 this provider cannot vote, the problem is thattotalVotingPower
in block n+1 has not subtracted theVotingPower
of this provider.
If the provider has moreVotingPower
or if more providers are slashed, the vote will never reach a 2/3 quorum.
totalPower = totalPower - slashedVotingPower