2020-10-16 05:42:48 -07:00
<!--
order: 6
-->
# BeginBlock
## Evidence Handling
Tendermint blocks can include
2021-05-21 02:32:01 -07:00
[Evidence ](https://github.com/tendermint/tendermint/blob/master/docs/spec/blockchain/blockchain.md#evidence ) that indicates if a validator committed malicious behavior. The relevant information is forwarded to the application as ABCI Evidence in `abci.RequestBeginBlock` so that the validator can be punished accordingly.
2020-10-16 05:42:48 -07:00
### Equivocation
2021-05-21 02:32:01 -07:00
Currently, the SDK handles two types of evidence inside the ABCI `BeginBlock` :
2020-10-16 05:42:48 -07:00
- `DuplicateVoteEvidence` ,
- `LightClientAttackEvidence` .
2021-05-21 02:32:01 -07:00
The evidence module handles these two evidence types the same way. First, the SDK converts the Tendermint concrete evidence type to a SDK `Evidence` interface using `Equivocation` as the concrete type.
2020-10-16 05:42:48 -07:00
```proto
// Equivocation implements the Evidence interface.
message Equivocation {
int64 height = 1;
google.protobuf.Timestamp time = 2;
int64 power = 3;
string consensus_address = 4;
}
```
For some `Equivocation` submitted in `block` to be valid, it must satisfy:
`Evidence.Timestamp >= block.Timestamp - MaxEvidenceAge`
2021-05-21 02:32:01 -07:00
Where:
2021-05-27 08:31:04 -07:00
- `Evidence.Timestamp` is the timestamp in the block at height `Evidence.Height`
2021-05-21 02:32:01 -07:00
- `block.Timestamp` is the current block timestamp.
2020-10-16 05:42:48 -07:00
If valid `Equivocation` evidence is included in a block, the validator's stake is
2021-05-27 08:31:04 -07:00
reduced (slashed) by `SlashFractionDoubleSign` as defined by the `x/slashing` module
2021-05-21 02:32:01 -07:00
of what their stake was when the infraction occurred, rather than when the evidence was discovered.
We want to "follow the stake", i.e., the stake that contributed to the infraction
2020-10-16 05:42:48 -07:00
should be slashed, even if it has since been redelegated or started unbonding.
2021-05-21 02:32:01 -07:00
In addition, the validator is permanently jailed and tombstoned to make it impossible for that
2020-10-16 05:42:48 -07:00
validator to ever re-enter the validator set.
The `Equivocation` evidence is handled as follows:
```go
func (k Keeper) HandleEquivocationEvidence(ctx sdk.Context, evidence *types.Equivocation) {
logger := k.Logger(ctx)
consAddr := evidence.GetConsensusAddress()
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
}
// calculate the age of the evidence
infractionHeight := evidence.GetHeight()
infractionTime := evidence.GetTime()
ageDuration := ctx.BlockHeader().Time.Sub(infractionTime)
ageBlocks := ctx.BlockHeader().Height - infractionHeight
// Reject evidence if the double-sign is too old. Evidence is considered stale
// if the difference in time and number of blocks is greater than the allowed
// parameters defined.
cp := ctx.ConsensusParams()
if cp != nil & & cp.Evidence != nil {
if ageDuration > cp.Evidence.MaxAgeDuration & & ageBlocks > cp.Evidence.MaxAgeNumBlocks {
logger.Info(
"ignored equivocation; evidence too old",
"validator", consAddr,
"infraction_height", infractionHeight,
"max_age_num_blocks", cp.Evidence.MaxAgeNumBlocks,
"infraction_time", infractionTime,
"max_age_duration", cp.Evidence.MaxAgeDuration,
)
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(
"ignored equivocation; validator already tombstoned",
"validator", consAddr,
"infraction_height", infractionHeight,
"infraction_time", infractionTime,
)
return
}
logger.Info(
"confirmed equivocation",
"validator", consAddr,
"infraction_height", infractionHeight,
"infraction_time", infractionTime,
)
// 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)
}
```
Note, the slashing, jailing, and tombstoning calls are delegated through the `x/slashing` module
2021-05-27 08:31:04 -07:00
that emits informative events and finally delegates calls to the `x/staking` module. See documentation
2021-05-21 02:32:01 -07:00
on slashing and jailing in [x/staking spec ](/.././cosmos-sdk/x/staking/spec/02_state_transitions.md ).