-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
R4R: Downtime slashing off-by-one-block fix #1805
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -65,6 +65,7 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, pubkey crypto.PubKey, infracti | |
} | ||
|
||
// handle a validator signature, must be called once per validator per block | ||
// nolint gocyclo | ||
func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, power int64, signed bool) { | ||
logger := ctx.Logger().With("module", "x/slashing") | ||
height := ctx.BlockHeight() | ||
|
@@ -101,11 +102,19 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, | |
} | ||
minHeight := signInfo.StartHeight + k.SignedBlocksWindow(ctx) | ||
if height > minHeight && signInfo.SignedBlocksCounter < k.MinSignedPerWindow(ctx) { | ||
// Downtime confirmed, slash, revoke, and jail the validator | ||
logger.Info(fmt.Sprintf("Validator %s past min height of %d and below signed blocks threshold of %d", pubkey.Address(), minHeight, k.MinSignedPerWindow(ctx))) | ||
k.validatorSet.Slash(ctx, pubkey, height, power, k.SlashFractionDowntime(ctx)) | ||
k.validatorSet.Revoke(ctx, pubkey) | ||
signInfo.JailedUntil = ctx.BlockHeader().Time + k.DowntimeUnbondDuration(ctx) | ||
validator := k.validatorSet.ValidatorByPubKey(ctx, pubkey) | ||
if validator != nil && !validator.GetRevoked() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. shouldn't we be checking this sooner? we are we even bothering fetching and updating the signInfo if he's no longer a validator ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, I'm not sure. If the validator was just revoked, technically they still should have signed the block in which they were revoked, so I left in the usual accounting logic for that. I think we could safely remove it though. |
||
// Downtime confirmed, slash, revoke, and jail the validator | ||
logger.Info(fmt.Sprintf("Validator %s past min height of %d and below signed blocks threshold of %d", | ||
pubkey.Address(), minHeight, k.MinSignedPerWindow(ctx))) | ||
k.validatorSet.Slash(ctx, pubkey, height, power, k.SlashFractionDowntime(ctx)) | ||
k.validatorSet.Revoke(ctx, pubkey) | ||
signInfo.JailedUntil = ctx.BlockHeader().Time + k.DowntimeUnbondDuration(ctx) | ||
} else { | ||
// Validator was (a) not found or (b) already revoked, don't slash | ||
logger.Info(fmt.Sprintf("Validator %s would have been slashed for downtime, but was either not found in store or already revoked", | ||
pubkey.Address())) | ||
} | ||
} | ||
|
||
// Set the updated signing info | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,8 @@ package keeper | |
import ( | ||
"fmt" | ||
|
||
"github.com/tendermint/tendermint/crypto" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
"github.com/cosmos/cosmos-sdk/x/stake/types" | ||
) | ||
|
@@ -57,6 +59,15 @@ func (k Keeper) Validator(ctx sdk.Context, address sdk.AccAddress) sdk.Validator | |
return val | ||
} | ||
|
||
// get the sdk.validator for a particular pubkey | ||
func (k Keeper) ValidatorByPubKey(ctx sdk.Context, pubkey crypto.PubKey) sdk.Validator { | ||
val, found := k.GetValidatorByPubKey(ctx, pubkey) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure I understand the question - There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Apologies, went through the code and realized the interface was updated. |
||
if !found { | ||
return nil | ||
} | ||
return val | ||
} | ||
|
||
// total power from the bond | ||
func (k Keeper) TotalPower(ctx sdk.Context) sdk.Rat { | ||
pool := k.GetPool(ctx) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're planning to actually not send the pubkey in BeginBlock, only the address (tendermint/tendermint#1712). Is that going to be a problem? It means we need to do the lookup by validator address!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We'll need to change the staking store then, at the moment the secondary index is by raw public key bytes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cc @rigelrozanski but AFAIK this should be fine