Slow Misty Iguana
Medium
When the total stake amount is 0(fp.totalVotingPower = 0), the block can never enter Finalized state and cannot be restored after being restake.
- At some point the total stake amount is 0.
- At some point the stake amount is 0.
- Since the total voting power is 0, the block can never be Finalized.
- The staker restakes BTC, but since the old block does not enter the Finalized state, the staked block cannot enter the Finalized state either.
ResumeFinalityProposal
cannot recover this situation.
halt of the chain
When the number of votes is greater than 2/3, the block will enter the Finalized
state:
func (k Keeper) TallyBlocks(ctx context.Context) {
......
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
}
The problem is that if totalPower = 0, the tally function returns false, so blocks can never be Finalized
.
This situation cannot be restored, even if totalPower
is reset ina later block, since the previous block is not Finalized
, the later block will not be Finalized
.
The ResumeFinalityProposal
is used to recover the abnormal block, but it also cannot handle this situation. The ResumeFinalityProposal
removes non-voting FPs, but block still cannot be Finalized
if totalPower
is 0.
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
+ return votedPower*3 >= totalPower*2
}