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 }