-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge PR #5299: Migrate Equivocation Handling to x/evidence
- Loading branch information
1 parent
5be87e4
commit 7953b52
Showing
47 changed files
with
995 additions
and
381 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package evidence | ||
|
||
import ( | ||
"fmt" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
|
||
abci "github.com/tendermint/tendermint/abci/types" | ||
tmtypes "github.com/tendermint/tendermint/types" | ||
) | ||
|
||
// BeginBlocker iterates through and handles any newly discovered evidence of | ||
// misbehavior submitted by Tendermint. Currently, only equivocation is handled. | ||
func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, k Keeper) { | ||
for _, tmEvidence := range req.ByzantineValidators { | ||
switch tmEvidence.Type { | ||
case tmtypes.ABCIEvidenceTypeDuplicateVote: | ||
evidence := ConvertDuplicateVoteEvidence(tmEvidence) | ||
k.HandleDoubleSign(ctx, evidence.(Equivocation)) | ||
|
||
default: | ||
k.Logger(ctx).Error(fmt.Sprintf("ignored unknown evidence type: %s", tmEvidence.Type)) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
package keeper | ||
|
||
import ( | ||
"fmt" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
|
||
"github.com/cosmos/cosmos-sdk/x/evidence/internal/types" | ||
) | ||
|
||
// HandleDoubleSign implements an equivocation evidence handler. Assuming the | ||
// evidence is valid, the validator committing the misbehavior will be slashed, | ||
// jailed and tombstoned. Once tombstoned, the validator will not be able to | ||
// recover. Note, the evidence contains the block time and height at the time of | ||
// the equivocation. | ||
// | ||
// The evidence is considered invalid if: | ||
// - the evidence is too old | ||
// - the validator is unbonded or does not exist | ||
// - the signing info does not exist (will panic) | ||
// - is already tombstoned | ||
// | ||
// TODO: Some of the invalid constraints listed above may need to be reconsidered | ||
// in the case of a lunatic attack. | ||
func (k Keeper) HandleDoubleSign(ctx sdk.Context, evidence types.Equivocation) { | ||
logger := k.Logger(ctx) | ||
consAddr := evidence.GetConsensusAddress() | ||
infractionHeight := evidence.GetHeight() | ||
|
||
// calculate the age of the evidence | ||
blockTime := ctx.BlockHeader().Time | ||
age := blockTime.Sub(evidence.GetTime()) | ||
|
||
if _, err := k.slashingKeeper.GetPubkey(ctx, consAddr.Bytes()); err != nil { | ||
// Ignore evidence that cannot be handled. | ||
// | ||
// NOTE: We used to panic with: | ||
// `panic(fmt.Sprintf("Validator consensus-address %v not found", consAddr))`, | ||
// but this couples the expectations of the app to both Tendermint and | ||
// the simulator. Both are expected to provide the full range of | ||
// allowable but none of the disallowed evidence types. Instead of | ||
// getting this coordination right, it is easier to relax the | ||
// constraints and ignore evidence that cannot be handled. | ||
return | ||
} | ||
|
||
// reject evidence if the double-sign is too old | ||
if age > k.MaxEvidenceAge(ctx) { | ||
logger.Info( | ||
fmt.Sprintf( | ||
"ignored double sign from %s at height %d, age of %d past max age of %d", | ||
consAddr, infractionHeight, age, k.MaxEvidenceAge(ctx), | ||
), | ||
) | ||
return | ||
} | ||
|
||
validator := k.stakingKeeper.ValidatorByConsAddr(ctx, consAddr) | ||
if validator == nil || validator.IsUnbonded() { | ||
// Defensive: Simulation doesn't take unbonding periods into account, and | ||
// Tendermint might break this assumption at some point. | ||
return | ||
} | ||
|
||
if ok := k.slashingKeeper.HasValidatorSigningInfo(ctx, consAddr); !ok { | ||
panic(fmt.Sprintf("expected signing info for validator %s but not found", consAddr)) | ||
} | ||
|
||
// ignore if the validator is already tombstoned | ||
if k.slashingKeeper.IsTombstoned(ctx, consAddr) { | ||
logger.Info( | ||
fmt.Sprintf( | ||
"ignored double sign from %s at height %d, validator already tombstoned", | ||
consAddr, infractionHeight, | ||
), | ||
) | ||
return | ||
} | ||
|
||
logger.Info(fmt.Sprintf("confirmed double sign from %s at height %d, age of %d", consAddr, infractionHeight, age)) | ||
|
||
// We need to retrieve the stake distribution which signed the block, so we | ||
// subtract ValidatorUpdateDelay from the evidence height. | ||
// Note, that this *can* result in a negative "distributionHeight", up to | ||
// -ValidatorUpdateDelay, i.e. at the end of the | ||
// pre-genesis block (none) = at the beginning of the genesis block. | ||
// That's fine since this is just used to filter unbonding delegations & redelegations. | ||
distributionHeight := infractionHeight - sdk.ValidatorUpdateDelay | ||
|
||
// Slash validator. The `power` is the int64 power of the validator as provided | ||
// to/by Tendermint. This value is validator.Tokens as sent to Tendermint via | ||
// ABCI, and now received as evidence. The fraction is passed in to separately | ||
// to slash unbonding and rebonding delegations. | ||
k.slashingKeeper.Slash( | ||
ctx, | ||
consAddr, | ||
k.slashingKeeper.SlashFractionDoubleSign(ctx), | ||
evidence.GetValidatorPower(), distributionHeight, | ||
) | ||
|
||
// Jail the validator if not already jailed. This will begin unbonding the | ||
// validator if not already unbonding (tombstoned). | ||
if !validator.IsJailed() { | ||
k.slashingKeeper.Jail(ctx, consAddr) | ||
} | ||
|
||
k.slashingKeeper.JailUntil(ctx, consAddr, types.DoubleSignJailEndTime) | ||
k.slashingKeeper.Tombstone(ctx, consAddr) | ||
} |
Oops, something went wrong.