Bugfix; update slashing spec
This commit is contained in:
parent
ec53a14b57
commit
83f7a4cb7b
|
@ -93,14 +93,14 @@ for val in block.Validators:
|
||||||
|
|
||||||
index := signInfo.IndexOffset % SIGNED_BLOCKS_WINDOW
|
index := signInfo.IndexOffset % SIGNED_BLOCKS_WINDOW
|
||||||
signInfo.IndexOffset++
|
signInfo.IndexOffset++
|
||||||
previous = SigningBitArray.Get(val.Address, index)
|
previous = MissedBlockBitArray.Get(val.Address, index)
|
||||||
|
|
||||||
// update counter if array has changed
|
// update counter if array has changed
|
||||||
if !previous and val in block.AbsentValidators:
|
if !previous and val in block.AbsentValidators:
|
||||||
SigningBitArray.Set(val.Address, index, true)
|
MissedBlockBitArray.Set(val.Address, index, true)
|
||||||
signInfo.MissedBlocksCounter++
|
signInfo.MissedBlocksCounter++
|
||||||
else if previous and val not in block.AbsentValidators:
|
else if previous and val not in block.AbsentValidators:
|
||||||
SigningBitArray.Set(val.Address, index, false)
|
MissedBlockBitArray.Set(val.Address, index, false)
|
||||||
signInfo.MissedBlocksCounter--
|
signInfo.MissedBlocksCounter--
|
||||||
// else previous == val not in block.AbsentValidators, no change
|
// else previous == val not in block.AbsentValidators, no change
|
||||||
|
|
||||||
|
@ -111,7 +111,9 @@ for val in block.Validators:
|
||||||
maxMissed = SIGNED_BLOCKS_WINDOW / 2
|
maxMissed = SIGNED_BLOCKS_WINDOW / 2
|
||||||
if height > minHeight AND signInfo.MissedBlocksCounter > maxMissed:
|
if height > minHeight AND signInfo.MissedBlocksCounter > maxMissed:
|
||||||
signInfo.JailedUntil = block.Time + DOWNTIME_UNBOND_DURATION
|
signInfo.JailedUntil = block.Time + DOWNTIME_UNBOND_DURATION
|
||||||
|
signInfo.IndexOffset = 0
|
||||||
|
signInfo.MissedBlocksCounter = 0
|
||||||
|
clearMissedBlockBitArray()
|
||||||
slash & unbond the validator
|
slash & unbond the validator
|
||||||
|
|
||||||
SigningInfo.Set(val.Address, signInfo)
|
SigningInfo.Set(val.Address, signInfo)
|
||||||
|
|
|
@ -12,6 +12,17 @@ and `SlashedSoFar` of `0`:
|
||||||
```
|
```
|
||||||
onValidatorBonded(address sdk.ValAddress)
|
onValidatorBonded(address sdk.ValAddress)
|
||||||
|
|
||||||
|
signingInfo, found = getValidatorSigningInfo(address)
|
||||||
|
if !found {
|
||||||
|
signingInfo = ValidatorSigningInfo {
|
||||||
|
StartHeight : CurrentHeight,
|
||||||
|
IndexOffset : 0,
|
||||||
|
JailedUntil : time.Unix(0, 0),
|
||||||
|
MissedBloskCounter : 0
|
||||||
|
}
|
||||||
|
setValidatorSigningInfo(signingInfo)
|
||||||
|
}
|
||||||
|
|
||||||
slashingPeriod = SlashingPeriod{
|
slashingPeriod = SlashingPeriod{
|
||||||
ValidatorAddr : address,
|
ValidatorAddr : address,
|
||||||
StartHeight : CurrentHeight,
|
StartHeight : CurrentHeight,
|
||||||
|
|
|
@ -17,18 +17,18 @@ Information about validator activity is tracked in a `ValidatorSigningInfo`.
|
||||||
It is indexed in the store as follows:
|
It is indexed in the store as follows:
|
||||||
|
|
||||||
- SigningInfo: ` 0x01 | ValTendermintAddr -> amino(valSigningInfo)`
|
- SigningInfo: ` 0x01 | ValTendermintAddr -> amino(valSigningInfo)`
|
||||||
- SigningBitArray: ` 0x02 | ValTendermintAddr | LittleEndianUint64(signArrayIndex) -> VarInt(didSign)`
|
- MissedBlocksBitArray: ` 0x02 | ValTendermintAddr | LittleEndianUint64(signArrayIndex) -> VarInt(didMiss)`
|
||||||
|
|
||||||
The first map allows us to easily lookup the recent signing info for a
|
The first map allows us to easily lookup the recent signing info for a
|
||||||
validator, according to the Tendermint validator address. The second map acts as
|
validator, according to the Tendermint validator address. The second map acts as
|
||||||
a bit-array of size `SIGNED_BLOCKS_WINDOW` that tells us if the validator signed for a given index in the bit-array.
|
a bit-array of size `SIGNED_BLOCKS_WINDOW` that tells us if the validator missed the block for a given index in the bit-array.
|
||||||
|
|
||||||
The index in the bit-array is given as little endian uint64.
|
The index in the bit-array is given as little endian uint64.
|
||||||
|
|
||||||
The result is a `varint` that takes on `0` or `1`, where `0` indicates the
|
The result is a `varint` that takes on `0` or `1`, where `0` indicates the
|
||||||
validator did not sign the corresponding block, and `1` indicates they did.
|
validator did not miss (did sign) the corresponding block, and `1` indicates they missed the block (did not sign).
|
||||||
|
|
||||||
Note that the SigningBitArray is not explicitly initialized up-front. Keys are
|
Note that the MissedBlocksBitArray is not explicitly initialized up-front. Keys are
|
||||||
added as we progress through the first `SIGNED_BLOCKS_WINDOW` blocks for a newly
|
added as we progress through the first `SIGNED_BLOCKS_WINDOW` blocks for a newly
|
||||||
bonded validator.
|
bonded validator.
|
||||||
|
|
||||||
|
|
|
@ -25,10 +25,6 @@ handleMsgUnjail(tx TxUnjail)
|
||||||
if block time < info.JailedUntil
|
if block time < info.JailedUntil
|
||||||
fail with "Validator still jailed, cannot unjail until period has expired"
|
fail with "Validator still jailed, cannot unjail until period has expired"
|
||||||
|
|
||||||
// Update the start height so the validator won't be immediately unbonded again
|
|
||||||
info.StartHeight = BlockHeight
|
|
||||||
setValidatorSigningInfo(info)
|
|
||||||
|
|
||||||
validator.Jailed = false
|
validator.Jailed = false
|
||||||
setValidator(validator)
|
setValidator(validator)
|
||||||
|
|
||||||
|
|
|
@ -46,11 +46,7 @@ func handleMsgUnjail(ctx sdk.Context, msg MsgUnjail, k Keeper) sdk.Result {
|
||||||
return ErrValidatorJailed(k.codespace).Result()
|
return ErrValidatorJailed(k.codespace).Result()
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the starting height so the validator can't be immediately jailed
|
// unjail the validator
|
||||||
// again
|
|
||||||
info.StartHeight = ctx.BlockHeight()
|
|
||||||
k.setValidatorSigningInfo(ctx, consAddr, info)
|
|
||||||
|
|
||||||
k.validatorSet.Unjail(ctx, consAddr)
|
k.validatorSet.Unjail(ctx, consAddr)
|
||||||
|
|
||||||
tags := sdk.NewTags("action", []byte("unjail"), "validator", []byte(msg.ValidatorAddr.String()))
|
tags := sdk.NewTags("action", []byte("unjail"), "validator", []byte(msg.ValidatorAddr.String()))
|
||||||
|
|
|
@ -16,8 +16,8 @@ func (k Keeper) onValidatorBonded(ctx sdk.Context, address sdk.ConsAddress) {
|
||||||
JailedUntil: time.Unix(0, 0),
|
JailedUntil: time.Unix(0, 0),
|
||||||
MissedBlocksCounter: 0,
|
MissedBlocksCounter: 0,
|
||||||
}
|
}
|
||||||
|
k.setValidatorSigningInfo(ctx, address, signingInfo)
|
||||||
}
|
}
|
||||||
k.setValidatorSigningInfo(ctx, address, signingInfo)
|
|
||||||
|
|
||||||
// Create a new slashing period when a validator is bonded
|
// Create a new slashing period when a validator is bonded
|
||||||
slashingPeriod := ValidatorSlashingPeriod{
|
slashingPeriod := ValidatorSlashingPeriod{
|
||||||
|
|
|
@ -245,10 +245,10 @@ func TestHandleAbsentValidator(t *testing.T) {
|
||||||
pool = sk.GetPool(ctx)
|
pool = sk.GetPool(ctx)
|
||||||
require.Equal(t, amtInt-slashAmt-secondSlashAmt, pool.BondedTokens.RoundInt64())
|
require.Equal(t, amtInt-slashAmt-secondSlashAmt, pool.BondedTokens.RoundInt64())
|
||||||
|
|
||||||
// validator start height should have been changed
|
// validator start height should not have been changed
|
||||||
info, found = keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address()))
|
info, found = keeper.getValidatorSigningInfo(ctx, sdk.ConsAddress(val.Address()))
|
||||||
require.True(t, found)
|
require.True(t, found)
|
||||||
require.Equal(t, height, info.StartHeight)
|
require.Equal(t, int64(0), info.StartHeight)
|
||||||
// we've missed 2 blocks more than the maximum, so the counter was reset to 0 at 1 block more and is now 1
|
// we've missed 2 blocks more than the maximum, so the counter was reset to 0 at 1 block more and is now 1
|
||||||
require.Equal(t, int64(1), info.MissedBlocksCounter)
|
require.Equal(t, int64(1), info.MissedBlocksCounter)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue