github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/x/evidence/internal/keeper/infraction.go (about) 1 package keeper 2 3 import ( 4 "fmt" 5 6 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 7 8 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/evidence/internal/types" 9 ) 10 11 // HandleDoubleSign 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) HandleDoubleSign(ctx sdk.Context, evidence types.Equivocation) { 26 logger := k.Logger(ctx) 27 consAddr := evidence.GetConsensusAddress() 28 infractionHeight := evidence.GetHeight() 29 30 // calculate the age of the evidence 31 blockTime := ctx.BlockHeader().Time 32 age := blockTime.Sub(evidence.GetTime()) 33 34 if _, err := k.slashingKeeper.GetPubkey(ctx, consAddr.Bytes()); err != nil { 35 // Ignore evidence that cannot be handled. 36 // 37 // NOTE: We used to panic with: 38 // `panic(fmt.Sprintf("Validator consensus-address %v not found", consAddr))`, 39 // but this couples the expectations of the app to both Tendermint and 40 // the simulator. Both are expected to provide the full range of 41 // allowable but none of the disallowed evidence types. Instead of 42 // getting this coordination right, it is easier to relax the 43 // constraints and ignore evidence that cannot be handled. 44 return 45 } 46 47 // reject evidence if the double-sign is too old 48 if age > k.MaxEvidenceAge(ctx) { 49 logger.Info( 50 fmt.Sprintf( 51 "ignored double sign from %s at height %d, age of %d past max age of %d", 52 consAddr, infractionHeight, age, k.MaxEvidenceAge(ctx), 53 ), 54 ) 55 return 56 } 57 58 validator := k.stakingKeeper.ValidatorByConsAddr(ctx, consAddr) 59 if validator == nil || validator.IsUnbonded() { 60 // Defensive: Simulation doesn't take unbonding periods into account, and 61 // Tendermint might break this assumption at some point. 62 return 63 } 64 65 if ok := k.slashingKeeper.HasValidatorSigningInfo(ctx, consAddr); !ok { 66 panic(fmt.Sprintf("expected signing info for validator %s but not found", consAddr)) 67 } 68 69 // ignore if the validator is already tombstoned 70 if k.slashingKeeper.IsTombstoned(ctx, consAddr) { 71 logger.Info( 72 fmt.Sprintf( 73 "ignored double sign from %s at height %d, validator already tombstoned", 74 consAddr, infractionHeight, 75 ), 76 ) 77 return 78 } 79 80 logger.Info(fmt.Sprintf("confirmed double sign from %s at height %d, age of %d", consAddr, infractionHeight, age)) 81 82 // We need to retrieve the stake distribution which signed the block, so we 83 // subtract ValidatorUpdateDelay from the evidence height. 84 // Note, that this *can* result in a negative "distributionHeight", up to 85 // -ValidatorUpdateDelay, i.e. at the end of the 86 // pre-genesis block (none) = at the beginning of the genesis block. 87 // That's fine since this is just used to filter unbonding delegations & redelegations. 88 distributionHeight := infractionHeight - sdk.ValidatorUpdateDelay 89 90 // Slash validator. The `power` is the int64 power of the validator as provided 91 // to/by Tendermint. This value is validator.Tokens as sent to Tendermint via 92 // ABCI, and now received as evidence. The fraction is passed in to separately 93 // to slash unbonding and rebonding delegations. 94 k.slashingKeeper.Slash( 95 ctx, 96 consAddr, 97 k.slashingKeeper.SlashFractionDoubleSign(ctx), 98 evidence.GetValidatorPower(), distributionHeight, 99 ) 100 101 // Jail the validator if not already jailed. This will begin unbonding the 102 // validator if not already unbonding (tombstoned). 103 if !validator.IsJailed() { 104 k.slashingKeeper.Jail(ctx, consAddr) 105 } 106 107 k.slashingKeeper.JailUntil(ctx, consAddr, types.DoubleSignJailEndTime) 108 k.slashingKeeper.Tombstone(ctx, consAddr) 109 }