github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/staking/keeper/val_state.go (about)

     1  package keeper
     2  
     3  import (
     4  	"fmt"
     5  
     6  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
     7  	abci "github.com/fibonacci-chain/fbc/libs/tendermint/abci/types"
     8  	"github.com/fibonacci-chain/fbc/libs/tendermint/libs/log"
     9  	"github.com/fibonacci-chain/fbc/x/staking/types"
    10  )
    11  
    12  // KickOutAndReturnValidatorSetUpdates shows the main logic when a validator is kicked out of validator-set in an epoch
    13  func (k Keeper) KickOutAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []abci.ValidatorUpdate) {
    14  	logger := k.Logger(ctx)
    15  	// 1.get the last validator set
    16  	lastBondedVals := k.getLastValidatorsByAddr(ctx)
    17  	logMap(logger, lastBondedVals, "LastBondedValAddrs")
    18  
    19  	// 2.get the abandoned validator addrs
    20  	abandonedValAddrs := k.getAbandonedValidatorAddrs(ctx)
    21  	logSlice(logger, abandonedValAddrs, "AbandonedValAddrs")
    22  
    23  	store := ctx.KVStore(k.storeKey)
    24  	totalPower := k.GetLastTotalPower(ctx)
    25  
    26  	// 3.look for the ahead candidate and promote it
    27  	iterator := sdk.KVStoreReversePrefixIterator(store, types.ValidatorsByPowerIndexKey)
    28  	defer iterator.Close()
    29  	for abandonedNum := len(abandonedValAddrs); iterator.Valid() && abandonedNum > 0; iterator.Next() {
    30  		valAddr := iterator.Value()
    31  		// get the key of map
    32  		valKey := getLastValidatorsMapKey(valAddr)
    33  
    34  		// look for the ahead candidate
    35  		_, found := lastBondedVals[valKey]
    36  		if found {
    37  			// not the val to promote
    38  			continue
    39  		}
    40  		// promote the candidate
    41  		validator := k.mustGetValidator(ctx, valAddr)
    42  		// if we get to a zero-power validator without shares, just pass
    43  		if validator.PotentialConsensusPowerByShares() == 0 {
    44  			continue
    45  		}
    46  
    47  		switch {
    48  		case validator.IsUnbonded():
    49  			validator = k.unbondedToBonded(ctx, validator)
    50  		case validator.IsUnbonding():
    51  			validator = k.unbondingToBonded(ctx, validator)
    52  		case validator.IsBonded():
    53  			panic("Panic. Candidate validator is not allowed to be in bonded status")
    54  		default:
    55  			panic("unexpected validator status")
    56  		}
    57  
    58  		// calculate the new power of candidate validator
    59  		newPower := validator.ConsensusPowerByShares()
    60  		// update the validator to tendermint
    61  		updates = append(updates, validator.ABCIValidatorUpdateByShares())
    62  		// set validator power on lookup index
    63  		k.SetLastValidatorPower(ctx, valAddr, newPower)
    64  		// cumsum the total power
    65  		totalPower = totalPower.Add(sdk.NewInt(newPower))
    66  
    67  		abandonedNum--
    68  	}
    69  
    70  	// 4.discharge the abandoned validators
    71  	for _, valAddr := range abandonedValAddrs {
    72  		validator := k.mustGetValidator(ctx, valAddr)
    73  		switch {
    74  		case validator.IsUnbonded():
    75  			logger.Debug(fmt.Sprintf("validator %s is already in the unboned status", validator.OperatorAddress.String()))
    76  		case validator.IsUnbonding():
    77  			logger.Debug(fmt.Sprintf("validator %s is already in the unbonding status", validator.OperatorAddress.String()))
    78  		case validator.IsBonded(): // bonded to unbonding
    79  			k.bondedToUnbonding(ctx, validator)
    80  			// delete from the bonded validator index
    81  			k.DeleteLastValidatorPower(ctx, validator.GetOperator())
    82  			// update the validator set
    83  			updates = append(updates, validator.ABCIValidatorUpdateZero())
    84  			// reduce the total power
    85  			valKey := getLastValidatorsMapKey(valAddr)
    86  			oldPowerBytes, found := lastBondedVals[valKey]
    87  			if !found {
    88  				panic("Never occur")
    89  			}
    90  			var oldPower int64
    91  			k.cdcMarshl.GetCdc().MustUnmarshalBinaryLengthPrefixed(oldPowerBytes, &oldPower)
    92  			totalPower = totalPower.Sub(sdk.NewInt(oldPower))
    93  		default:
    94  			panic("unexpected validator status")
    95  		}
    96  	}
    97  
    98  	// 5. update the total power of this block to store
    99  	k.SetLastTotalPower(ctx, totalPower)
   100  
   101  	return updates
   102  }
   103  
   104  // getLastValidatorsMapKey gets the map key of last validator-set from val address
   105  func getLastValidatorsMapKey(valAddr sdk.ValAddress) (key [sdk.AddrLen]byte) {
   106  	copy(key[:], valAddr[:])
   107  	return
   108  }
   109  
   110  func logMap(logger log.Logger, valMap validatorsByAddr, title string) {
   111  	logger.Debug(title)
   112  	for i := range valMap {
   113  		logger.Debug(sdk.ValAddress(i[:]).String())
   114  	}
   115  }
   116  
   117  func logSlice(logger log.Logger, valAddrs []sdk.ValAddress, title string) {
   118  	logger.Debug(title)
   119  	for _, addr := range valAddrs {
   120  		logger.Debug(addr.String())
   121  	}
   122  }
   123  
   124  // AppendAbandonedValidatorAddrs appends validator addresses to kick out
   125  func (k Keeper) AppendAbandonedValidatorAddrs(ctx sdk.Context, ConsAddr sdk.ConsAddress) {
   126  	validator := k.mustGetValidatorByConsAddr(ctx, ConsAddr)
   127  	abandonedValAddr := k.getAbandonedValidatorAddrs(ctx)
   128  	// if there are several validators to destroy in one block
   129  	abandonedValAddr = append(abandonedValAddr, validator.OperatorAddress)
   130  	bytes := k.cdcMarshl.GetCdc().MustMarshalBinaryLengthPrefixed(abandonedValAddr)
   131  	ctx.KVStore(k.storeKey).Set(types.ValidatorAbandonedKey, bytes)
   132  }
   133  
   134  // getAbandonedValidatorAddrs gets the abandoned validator addresses
   135  func (k Keeper) getAbandonedValidatorAddrs(ctx sdk.Context) (abandonedValAddr []sdk.ValAddress) {
   136  	bytes := ctx.KVStore(k.storeKey).Get(types.ValidatorAbandonedKey)
   137  	if len(bytes) == 0 {
   138  		return
   139  	}
   140  
   141  	k.cdcMarshl.GetCdc().MustUnmarshalBinaryLengthPrefixed(bytes, &abandonedValAddr)
   142  	return
   143  }
   144  
   145  // DeleteAbandonedValidatorAddrs deletes the abandoned validator addresses
   146  func (k Keeper) DeleteAbandonedValidatorAddrs(ctx sdk.Context) {
   147  	ctx.KVStore(k.storeKey).Delete(types.ValidatorAbandonedKey)
   148  }
   149  
   150  // IsKickedOut tells whether there're jailed validators to kick out in an epoch
   151  func (k Keeper) IsKickedOut(ctx sdk.Context) bool {
   152  	store := ctx.KVStore(k.storeKey)
   153  	bytes := store.Get(types.ValidatorAbandonedKey)
   154  	return len(bytes) != 0
   155  }