github.com/Finschia/finschia-sdk@v0.48.1/x/evidence/keeper/infraction.go (about) 1 package keeper 2 3 import ( 4 "fmt" 5 6 sdk "github.com/Finschia/finschia-sdk/types" 7 8 "github.com/Finschia/finschia-sdk/x/evidence/types" 9 ) 10 11 // HandleEquivocationEvidence implements an equivocation evidence handler. Assuming the 12 // evidence is valid, the validator committing the misbehavior will be slashed, 13 // jailed and tombstoned. Once tombstoned, the validator will not be able to 14 // recover. Note, the evidence contains the block time and height at the time of 15 // the equivocation. 16 // 17 // The evidence is considered invalid if: 18 // - the evidence is too old 19 // - the validator is unbonded or does not exist 20 // - the signing info does not exist (will panic) 21 // - is already tombstoned 22 // 23 // TODO: Some of the invalid constraints listed above may need to be reconsidered 24 // in the case of a lunatic attack. 25 func (k Keeper) HandleEquivocationEvidence(ctx sdk.Context, evidence *types.Equivocation) { 26 logger := k.Logger(ctx) 27 consAddr := evidence.GetConsensusAddress() 28 29 if _, err := k.slashingKeeper.GetPubkey(ctx, consAddr.Bytes()); err != nil { 30 // Ignore evidence that cannot be handled. 31 // 32 // NOTE: We used to panic with: 33 // `panic(fmt.Sprintf("Validator consensus-address %v not found", consAddr))`, 34 // but this couples the expectations of the app to both Tendermint and 35 // the simulator. Both are expected to provide the full range of 36 // allowable but none of the disallowed evidence types. Instead of 37 // getting this coordination right, it is easier to relax the 38 // constraints and ignore evidence that cannot be handled. 39 return 40 } 41 42 // calculate the age of the evidence 43 infractionHeight := evidence.GetHeight() 44 infractionTime := evidence.GetTime() 45 ageDuration := ctx.BlockHeader().Time.Sub(infractionTime) 46 ageBlocks := ctx.BlockHeader().Height - infractionHeight 47 48 // Reject evidence if the double-sign is too old. Evidence is considered stale 49 // if the difference in time and number of blocks is greater than the allowed 50 // parameters defined. 51 cp := ctx.ConsensusParams() 52 if cp != nil && cp.Evidence != nil { 53 if ageDuration > cp.Evidence.MaxAgeDuration && ageBlocks > cp.Evidence.MaxAgeNumBlocks { 54 logger.Info( 55 "ignored equivocation; evidence too old", 56 "validator", consAddr, 57 "infraction_height", infractionHeight, 58 "max_age_num_blocks", cp.Evidence.MaxAgeNumBlocks, 59 "infraction_time", infractionTime, 60 "max_age_duration", cp.Evidence.MaxAgeDuration, 61 ) 62 return 63 } 64 } 65 66 validator := k.stakingKeeper.ValidatorByConsAddr(ctx, consAddr) 67 if validator == nil || validator.IsUnbonded() { 68 // Defensive: Simulation doesn't take unbonding periods into account, and 69 // Tendermint might break this assumption at some point. 70 return 71 } 72 73 if ok := k.slashingKeeper.HasValidatorSigningInfo(ctx, consAddr); !ok { 74 panic(fmt.Sprintf("expected signing info for validator %s but not found", consAddr)) 75 } 76 77 // ignore if the validator is already tombstoned 78 if k.slashingKeeper.IsTombstoned(ctx, consAddr) { 79 logger.Info( 80 "ignored equivocation; validator already tombstoned", 81 "validator", consAddr, 82 "infraction_height", infractionHeight, 83 "infraction_time", infractionTime, 84 ) 85 return 86 } 87 88 logger.Info( 89 "confirmed equivocation", 90 "validator", consAddr, 91 "infraction_height", infractionHeight, 92 "infraction_time", infractionTime, 93 ) 94 95 // We need to retrieve the stake distribution which signed the block, so we 96 // subtract ValidatorUpdateDelay from the evidence height. 97 // Note, that this *can* result in a negative "distributionHeight", up to 98 // -ValidatorUpdateDelay, i.e. at the end of the 99 // pre-genesis block (none) = at the beginning of the genesis block. 100 // That's fine since this is just used to filter unbonding delegations & redelegations. 101 distributionHeight := infractionHeight - sdk.ValidatorUpdateDelay 102 103 // Slash validator. The `power` is the int64 power of the validator as provided 104 // to/by Tendermint. This value is validator.Tokens as sent to Tendermint via 105 // ABCI, and now received as evidence. The fraction is passed in to separately 106 // to slash unbonding and rebonding delegations. 107 k.slashingKeeper.Slash( 108 ctx, 109 consAddr, 110 k.slashingKeeper.SlashFractionDoubleSign(ctx), 111 evidence.GetValidatorPower(), distributionHeight, 112 ) 113 114 // Jail the validator if not already jailed. This will begin unbonding the 115 // validator if not already unbonding (tombstoned). 116 if !validator.IsJailed() { 117 k.slashingKeeper.Jail(ctx, consAddr) 118 } 119 120 k.slashingKeeper.JailUntil(ctx, consAddr, types.DoubleSignJailEndTime) 121 k.slashingKeeper.Tombstone(ctx, consAddr) 122 k.SetEvidence(ctx, evidence) 123 }