github.com/Finschia/finschia-sdk@v0.48.1/x/evidence/spec/06_begin_block.md (about) 1 <!-- 2 order: 6 3 --> 4 5 # BeginBlock 6 7 ## Evidence Handling 8 9 Tendermint blocks can include 10 [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. 11 12 ### Equivocation 13 14 Currently, the SDK handles two types of evidence inside the ABCI `BeginBlock`: 15 16 - `DuplicateVoteEvidence`, 17 - `LightClientAttackEvidence`. 18 19 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. 20 21 ```proto 22 // Equivocation implements the Evidence interface. 23 message Equivocation { 24 int64 height = 1; 25 google.protobuf.Timestamp time = 2; 26 int64 power = 3; 27 string consensus_address = 4; 28 } 29 ``` 30 31 For some `Equivocation` submitted in `block` to be valid, it must satisfy: 32 33 `Evidence.Timestamp >= block.Timestamp - MaxEvidenceAge` 34 35 Where: 36 37 - `Evidence.Timestamp` is the timestamp in the block at height `Evidence.Height` 38 - `block.Timestamp` is the current block timestamp. 39 40 If valid `Equivocation` evidence is included in a block, the validator's stake is 41 reduced (slashed) by `SlashFractionDoubleSign` as defined by the `x/slashing` module 42 of what their stake was when the infraction occurred, rather than when the evidence was discovered. 43 We want to "follow the stake", i.e., the stake that contributed to the infraction 44 should be slashed, even if it has since been redelegated or started unbonding. 45 46 In addition, the validator is permanently jailed and tombstoned to make it impossible for that 47 validator to ever re-enter the validator set. 48 49 The `Equivocation` evidence is handled as follows: 50 51 ```go 52 func (k Keeper) HandleEquivocationEvidence(ctx sdk.Context, evidence *types.Equivocation) { 53 logger := k.Logger(ctx) 54 consAddr := evidence.GetConsensusAddress() 55 56 if _, err := k.slashingKeeper.GetPubkey(ctx, consAddr.Bytes()); err != nil { 57 // Ignore evidence that cannot be handled. 58 // 59 // NOTE: We used to panic with: 60 // `panic(fmt.Sprintf("Validator consensus-address %v not found", consAddr))`, 61 // but this couples the expectations of the app to both Tendermint and 62 // the simulator. Both are expected to provide the full range of 63 // allowable but none of the disallowed evidence types. Instead of 64 // getting this coordination right, it is easier to relax the 65 // constraints and ignore evidence that cannot be handled. 66 return 67 } 68 69 // calculate the age of the evidence 70 infractionHeight := evidence.GetHeight() 71 infractionTime := evidence.GetTime() 72 ageDuration := ctx.BlockHeader().Time.Sub(infractionTime) 73 ageBlocks := ctx.BlockHeader().Height - infractionHeight 74 75 // Reject evidence if the double-sign is too old. Evidence is considered stale 76 // if the difference in time and number of blocks is greater than the allowed 77 // parameters defined. 78 cp := ctx.ConsensusParams() 79 if cp != nil && cp.Evidence != nil { 80 if ageDuration > cp.Evidence.MaxAgeDuration && ageBlocks > cp.Evidence.MaxAgeNumBlocks { 81 logger.Info( 82 "ignored equivocation; evidence too old", 83 "validator", consAddr, 84 "infraction_height", infractionHeight, 85 "max_age_num_blocks", cp.Evidence.MaxAgeNumBlocks, 86 "infraction_time", infractionTime, 87 "max_age_duration", cp.Evidence.MaxAgeDuration, 88 ) 89 return 90 } 91 } 92 93 validator := k.stakingKeeper.ValidatorByConsAddr(ctx, consAddr) 94 if validator == nil || validator.IsUnbonded() { 95 // Defensive: Simulation doesn't take unbonding periods into account, and 96 // Tendermint might break this assumption at some point. 97 return 98 } 99 100 if ok := k.slashingKeeper.HasValidatorSigningInfo(ctx, consAddr); !ok { 101 panic(fmt.Sprintf("expected signing info for validator %s but not found", consAddr)) 102 } 103 104 // ignore if the validator is already tombstoned 105 if k.slashingKeeper.IsTombstoned(ctx, consAddr) { 106 logger.Info( 107 "ignored equivocation; validator already tombstoned", 108 "validator", consAddr, 109 "infraction_height", infractionHeight, 110 "infraction_time", infractionTime, 111 ) 112 return 113 } 114 115 logger.Info( 116 "confirmed equivocation", 117 "validator", consAddr, 118 "infraction_height", infractionHeight, 119 "infraction_time", infractionTime, 120 ) 121 122 // We need to retrieve the stake distribution which signed the block, so we 123 // subtract ValidatorUpdateDelay from the evidence height. 124 // Note, that this *can* result in a negative "distributionHeight", up to 125 // -ValidatorUpdateDelay, i.e. at the end of the 126 // pre-genesis block (none) = at the beginning of the genesis block. 127 // That's fine since this is just used to filter unbonding delegations & redelegations. 128 distributionHeight := infractionHeight - sdk.ValidatorUpdateDelay 129 130 // Slash validator. The `power` is the int64 power of the validator as provided 131 // to/by Tendermint. This value is validator.Tokens as sent to Tendermint via 132 // ABCI, and now received as evidence. The fraction is passed in to separately 133 // to slash unbonding and rebonding delegations. 134 k.slashingKeeper.Slash( 135 ctx, 136 consAddr, 137 k.slashingKeeper.SlashFractionDoubleSign(ctx), 138 evidence.GetValidatorPower(), distributionHeight, 139 ) 140 141 // Jail the validator if not already jailed. This will begin unbonding the 142 // validator if not already unbonding (tombstoned). 143 if !validator.IsJailed() { 144 k.slashingKeeper.Jail(ctx, consAddr) 145 } 146 147 k.slashingKeeper.JailUntil(ctx, consAddr, types.DoubleSignJailEndTime) 148 k.slashingKeeper.Tombstone(ctx, consAddr) 149 } 150 ``` 151 152 Note, the slashing, jailing, and tombstoning calls are delegated through the `x/slashing` module 153 that emits informative events and finally delegates calls to the `x/staking` module. See documentation 154 on slashing and jailing in [x/staking spec](/.././cosmos-sdk/x/staking/spec/02_state_transitions.md).