Count missed blocks instead of signed blocks

This commit is contained in:
Christopher Goes 2018-10-12 00:04:44 +02:00
parent b55f29f72d
commit 5fd7297e25
7 changed files with 37 additions and 35 deletions

View File

@ -53,7 +53,7 @@ func TestJailedValidatorDelegations(t *testing.T) {
StartHeight: int64(0),
IndexOffset: int64(0),
JailedUntil: time.Unix(0, 0),
SignedBlocksCounter: int64(0),
MissedBlocksCounter: int64(0),
}
slashingKeeper.setValidatorSigningInfo(ctx, consAddr, newInfo)

View File

@ -14,7 +14,7 @@ func (k Keeper) onValidatorBonded(ctx sdk.Context, address sdk.ConsAddress) {
StartHeight: ctx.BlockHeight(),
IndexOffset: 0,
JailedUntil: time.Unix(0, 0),
SignedBlocksCounter: 0,
MissedBlocksCounter: 0,
}
k.setValidatorSigningInfo(ctx, address, signingInfo)
}

View File

@ -110,23 +110,25 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, addr crypto.Address, p
// This counter just tracks the sum of the bit array
// That way we avoid needing to read/write the whole array each time
previous := k.getValidatorSigningBitArray(ctx, consAddr, index)
if previous == signed {
missed := !signed
if previous == missed {
// Array value at this index has not changed, no need to update counter
} else if previous && !signed {
// Array value has changed from signed to unsigned, decrement counter
k.setValidatorSigningBitArray(ctx, consAddr, index, false)
signInfo.SignedBlocksCounter--
} else if !previous && signed {
// Array value has changed from unsigned to signed, increment counter
} else if !previous && missed {
// Array value has changed from not missed to missed, increment counter
k.setValidatorSigningBitArray(ctx, consAddr, index, true)
signInfo.SignedBlocksCounter++
signInfo.MissedBlocksCounter++
} else if previous && !missed {
// Array value has changed from missed to not missed, decrement counter
k.setValidatorSigningBitArray(ctx, consAddr, index, false)
signInfo.MissedBlocksCounter--
}
if !signed {
logger.Info(fmt.Sprintf("Absent validator %s at height %d, %d signed, threshold %d", addr, height, signInfo.SignedBlocksCounter, k.MinSignedPerWindow(ctx)))
if missed {
logger.Info(fmt.Sprintf("Absent validator %s at height %d, %d missed, threshold %d", addr, height, signInfo.MissedBlocksCounter, k.MinSignedPerWindow(ctx)))
}
minHeight := signInfo.StartHeight + k.SignedBlocksWindow(ctx)
if height > minHeight && signInfo.SignedBlocksCounter < k.MinSignedPerWindow(ctx) {
maxMissed := k.SignedBlocksWindow(ctx) - k.MinSignedPerWindow(ctx)
if height > minHeight && signInfo.MissedBlocksCounter > maxMissed {
validator := k.validatorSet.ValidatorByConsAddr(ctx, consAddr)
if validator != nil && !validator.GetJailed() {
// Downtime confirmed: slash and jail the validator

View File

@ -148,7 +148,7 @@ func TestHandleAbsentValidator(t *testing.T) {
require.True(t, found)
require.Equal(t, int64(0), info.StartHeight)
require.Equal(t, int64(0), info.IndexOffset)
require.Equal(t, int64(0), info.SignedBlocksCounter)
require.Equal(t, int64(0), info.MissedBlocksCounter)
height := int64(0)
// 1000 first blocks OK
@ -159,7 +159,7 @@ func TestHandleAbsentValidator(t *testing.T) {
info, found = keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address()))
require.True(t, found)
require.Equal(t, int64(0), info.StartHeight)
require.Equal(t, keeper.SignedBlocksWindow(ctx), info.SignedBlocksCounter)
require.Equal(t, int64(0), info.MissedBlocksCounter)
// 500 blocks missed
for ; height < keeper.SignedBlocksWindow(ctx)+(keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx)); height++ {
@ -169,7 +169,7 @@ func TestHandleAbsentValidator(t *testing.T) {
info, found = keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address()))
require.True(t, found)
require.Equal(t, int64(0), info.StartHeight)
require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx), info.SignedBlocksCounter)
require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx), info.MissedBlocksCounter)
// validator should be bonded still
validator, _ := sk.GetValidatorByConsAddr(ctx, sdk.GetConsAddress(val))
@ -183,7 +183,7 @@ func TestHandleAbsentValidator(t *testing.T) {
info, found = keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address()))
require.True(t, found)
require.Equal(t, int64(0), info.StartHeight)
require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx)-1, info.SignedBlocksCounter)
require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx)+1, info.MissedBlocksCounter)
// end block
stake.EndBlocker(ctx, sk)
@ -204,7 +204,7 @@ func TestHandleAbsentValidator(t *testing.T) {
info, found = keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address()))
require.True(t, found)
require.Equal(t, int64(0), info.StartHeight)
require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx)-2, info.SignedBlocksCounter)
require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx)+2, info.MissedBlocksCounter)
// end block
stake.EndBlocker(ctx, sk)
@ -246,7 +246,7 @@ func TestHandleAbsentValidator(t *testing.T) {
require.True(t, found)
require.Equal(t, height, info.StartHeight)
// we've missed 2 blocks more than the maximum
require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx)-2, info.SignedBlocksCounter)
require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx)+2, info.MissedBlocksCounter)
// validator should not be immediately jailed again
height++
@ -308,7 +308,7 @@ func TestHandleNewValidator(t *testing.T) {
require.True(t, found)
require.Equal(t, keeper.SignedBlocksWindow(ctx)+1, info.StartHeight)
require.Equal(t, int64(2), info.IndexOffset)
require.Equal(t, int64(1), info.SignedBlocksCounter)
require.Equal(t, int64(1), info.MissedBlocksCounter)
require.Equal(t, time.Unix(0, 0).UTC(), info.JailedUntil)
// validator should be bonded still, should not have been jailed or slashed

View File

@ -48,25 +48,25 @@ func (k Keeper) setValidatorSigningBitArray(ctx sdk.Context, address sdk.ConsAdd
}
// Construct a new `ValidatorSigningInfo` struct
func NewValidatorSigningInfo(startHeight int64, indexOffset int64, jailedUntil time.Time, signedBlocksCounter int64) ValidatorSigningInfo {
func NewValidatorSigningInfo(startHeight int64, indexOffset int64, jailedUntil time.Time, missedBlocksCounter int64) ValidatorSigningInfo {
return ValidatorSigningInfo{
StartHeight: startHeight,
IndexOffset: indexOffset,
JailedUntil: jailedUntil,
SignedBlocksCounter: signedBlocksCounter,
MissedBlocksCounter: missedBlocksCounter,
}
}
// Signing info for a validator
type ValidatorSigningInfo struct {
StartHeight int64 `json:"start_height"` // height at which validator was first a candidate OR was unjailed
IndexOffset int64 `json:"index_offset"` // index offset into signed block bit array
JailedUntil time.Time `json:"jailed_until"` // timestamp validator cannot be unjailed until
SignedBlocksCounter int64 `json:"signed_blocks_counter"` // signed blocks counter (to avoid scanning the array every time)
StartHeight int64 `json:"start_height"` // height at which validator was first a candidate OR was unjailed
IndexOffset int64 `json:"index_offset"` // index offset into signed block bit array
JailedUntil time.Time `json:"jailed_until"` // timestamp validator cannot be unjailed until
MissedBlocksCounter int64 `json:"misseded_blocks_counter"` // missed blocks counter (to avoid scanning the array every time)
}
// Return human readable signing info
func (i ValidatorSigningInfo) HumanReadableString() string {
return fmt.Sprintf("Start height: %d, index offset: %d, jailed until: %v, signed blocks counter: %d",
i.StartHeight, i.IndexOffset, i.JailedUntil, i.SignedBlocksCounter)
return fmt.Sprintf("Start height: %d, index offset: %d, jailed until: %v, missed blocks counter: %d",
i.StartHeight, i.IndexOffset, i.JailedUntil, i.MissedBlocksCounter)
}

View File

@ -17,7 +17,7 @@ func TestGetSetValidatorSigningInfo(t *testing.T) {
StartHeight: int64(4),
IndexOffset: int64(3),
JailedUntil: time.Unix(2, 0),
SignedBlocksCounter: int64(10),
MissedBlocksCounter: int64(10),
}
keeper.setValidatorSigningInfo(ctx, sdk.ConsAddress(addrs[0]), newInfo)
info, found = keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(addrs[0]))
@ -25,14 +25,14 @@ func TestGetSetValidatorSigningInfo(t *testing.T) {
require.Equal(t, info.StartHeight, int64(4))
require.Equal(t, info.IndexOffset, int64(3))
require.Equal(t, info.JailedUntil, time.Unix(2, 0).UTC())
require.Equal(t, info.SignedBlocksCounter, int64(10))
require.Equal(t, info.MissedBlocksCounter, int64(10))
}
func TestGetSetValidatorSigningBitArray(t *testing.T) {
ctx, _, _, _, keeper := createTestInput(t)
signed := keeper.getValidatorSigningBitArray(ctx, sdk.ConsAddress(addrs[0]), 0)
require.False(t, signed) // treat empty key as unsigned
missed := keeper.getValidatorSigningBitArray(ctx, sdk.ConsAddress(addrs[0]), 0)
require.False(t, missed) // treat empty key as not missed
keeper.setValidatorSigningBitArray(ctx, sdk.ConsAddress(addrs[0]), 0, true)
signed = keeper.getValidatorSigningBitArray(ctx, sdk.ConsAddress(addrs[0]), 0)
require.True(t, signed) // now should be signed
missed = keeper.getValidatorSigningBitArray(ctx, sdk.ConsAddress(addrs[0]), 0)
require.True(t, missed) // now should be missed
}

View File

@ -45,7 +45,7 @@ func TestBeginBlocker(t *testing.T) {
require.Equal(t, ctx.BlockHeight(), info.StartHeight)
require.Equal(t, int64(1), info.IndexOffset)
require.Equal(t, time.Unix(0, 0).UTC(), info.JailedUntil)
require.Equal(t, int64(1), info.SignedBlocksCounter)
require.Equal(t, int64(0), info.MissedBlocksCounter)
height := int64(0)