github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/slashing/internal/keeper/infractions.go (about)

     1  package keeper
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/fibonacci-chain/fbc/libs/tendermint/crypto"
     7  
     8  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
     9  	"github.com/fibonacci-chain/fbc/x/slashing/internal/types"
    10  )
    11  
    12  // HandleValidatorSignature handles a validator signature, must be called once per validator per block.
    13  func (k Keeper) HandleValidatorSignature(ctx sdk.Context, addr crypto.Address, power int64, signed bool) {
    14  	logger := k.Logger(ctx)
    15  	height := ctx.BlockHeight()
    16  
    17  	// fetch the validator public key
    18  	consAddr := sdk.ConsAddress(addr)
    19  	if _, err := k.GetPubkey(ctx, addr); err != nil {
    20  		panic(fmt.Sprintf("Validator consensus-address %s not found", consAddr))
    21  	}
    22  
    23  	// fetch signing info
    24  	signInfo, found := k.GetValidatorSigningInfo(ctx, consAddr)
    25  	if !found {
    26  		panic(fmt.Sprintf("Expected signing info for validator %s but not found", consAddr))
    27  	}
    28  
    29  	// this is a relative index, so it counts blocks the validator *should* have signed
    30  	// will use the 0-value default signing info if not present, except for start height
    31  	index := signInfo.IndexOffset % k.SignedBlocksWindow(ctx)
    32  	signInfo.IndexOffset++
    33  
    34  	// Update signed block bit array & counter
    35  	// This counter just tracks the sum of the bit array
    36  	// That way we avoid needing to read/write the whole array each time
    37  	previous := k.GetValidatorMissedBlockBitArray(ctx, consAddr, index)
    38  	missed := !signed
    39  	switch {
    40  	case !previous && missed:
    41  		// Array value has changed from not missed to missed, increment counter
    42  		k.SetValidatorMissedBlockBitArray(ctx, consAddr, index, true)
    43  		signInfo.MissedBlocksCounter++
    44  	case previous && !missed:
    45  		// Array value has changed from missed to not missed, decrement counter
    46  		k.SetValidatorMissedBlockBitArray(ctx, consAddr, index, false)
    47  		signInfo.MissedBlocksCounter--
    48  	default:
    49  		// Array value at this index has not changed, no need to update counter
    50  	}
    51  
    52  	if missed {
    53  		ctx.EventManager().EmitEvent(
    54  			sdk.NewEvent(
    55  				types.EventTypeLiveness,
    56  				sdk.NewAttribute(types.AttributeKeyAddress, consAddr.String()),
    57  				sdk.NewAttribute(types.AttributeKeyMissedBlocks, fmt.Sprintf("%d", signInfo.MissedBlocksCounter)),
    58  				sdk.NewAttribute(types.AttributeKeyHeight, fmt.Sprintf("%d", height)),
    59  			),
    60  		)
    61  
    62  		logger.Info(
    63  			fmt.Sprintf("Absent validator %s at height %d, %d missed, threshold %d", consAddr, height, signInfo.MissedBlocksCounter, k.MinSignedPerWindow(ctx)))
    64  	}
    65  
    66  	minHeight := signInfo.StartHeight + k.SignedBlocksWindow(ctx)
    67  	maxMissed := k.SignedBlocksWindow(ctx) - k.MinSignedPerWindow(ctx)
    68  
    69  	// if we are past the minimum height and the validator has missed too many blocks, punish them
    70  	if height > minHeight && signInfo.MissedBlocksCounter > maxMissed {
    71  		validator := k.sk.ValidatorByConsAddr(ctx, consAddr)
    72  		if validator != nil && !validator.IsJailed() {
    73  
    74  			// Downtime confirmed: slash and jail the validator
    75  			logger.Info(fmt.Sprintf("Validator %s past min height of %d and below signed blocks threshold of %d",
    76  				consAddr, minHeight, k.MinSignedPerWindow(ctx)))
    77  
    78  			// We need to retrieve the stake distribution which signed the block, so we subtract ValidatorUpdateDelay from the evidence height,
    79  			// and subtract an additional 1 since this is the LastCommit.
    80  			// Note that this *can* result in a negative "distributionHeight" up to -ValidatorUpdateDelay-1,
    81  			// i.e. at the end of the pre-genesis block (none) = at the beginning of the genesis block.
    82  			// That's fine since this is just used to filter unbonding delegations & redelegations.
    83  			//distributionHeight := height - sdk.ValidatorUpdateDelay - 1
    84  
    85  			ctx.EventManager().EmitEvent(
    86  				sdk.NewEvent(
    87  					types.EventTypeSlash,
    88  					sdk.NewAttribute(types.AttributeKeyAddress, consAddr.String()),
    89  					sdk.NewAttribute(types.AttributeKeyPower, fmt.Sprintf("%d", power)),
    90  					sdk.NewAttribute(types.AttributeKeyReason, types.AttributeValueMissingSignature),
    91  					sdk.NewAttribute(types.AttributeKeyJailed, consAddr.String()),
    92  				),
    93  			)
    94  			//don't slashing tokens, just jail the validator
    95  			//k.sk.Slash(ctx, consAddr, distributionHeight, power, k.SlashFractionDowntime(ctx))
    96  			k.sk.Jail(ctx, consAddr)
    97  			k.GetStakingKeeper().AppendAbandonedValidatorAddrs(ctx, consAddr)
    98  
    99  			signInfo.JailedUntil = ctx.BlockHeader().Time.Add(k.DowntimeJailDuration(ctx))
   100  
   101  			// We need to reset the counter & array so that the validator won't be immediately slashed for downtime upon rebonding.
   102  			signInfo.MissedBlocksCounter = 0
   103  			signInfo.IndexOffset = 0
   104  			k.clearValidatorMissedBlockBitArray(ctx, consAddr)
   105  		} else {
   106  			// Validator was (a) not found or (b) already jailed, don't slash
   107  			logger.Info(
   108  				fmt.Sprintf("Validator %s would have been slashed for downtime, but was either not found in store or already jailed", consAddr),
   109  			)
   110  		}
   111  	}
   112  
   113  	// Set the updated signing info
   114  	k.SetValidatorSigningInfo(ctx, consAddr, signInfo)
   115  }