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  }