github.com/Finschia/finschia-sdk@v0.48.1/x/staking/keeper/val_state_change.go (about) 1 package keeper 2 3 import ( 4 "bytes" 5 "fmt" 6 "sort" 7 8 gogotypes "github.com/gogo/protobuf/types" 9 abci "github.com/tendermint/tendermint/abci/types" 10 11 sdk "github.com/Finschia/finschia-sdk/types" 12 "github.com/Finschia/finschia-sdk/x/staking/types" 13 ) 14 15 // BlockValidatorUpdates calculates the ValidatorUpdates for the current block 16 // Called in each EndBlock 17 func (k Keeper) BlockValidatorUpdates(ctx sdk.Context) []abci.ValidatorUpdate { 18 // Calculate validator set changes. 19 // 20 // NOTE: ApplyAndReturnValidatorSetUpdates has to come before 21 // UnbondAllMatureValidatorQueue. 22 // This fixes a bug when the unbonding period is instant (is the case in 23 // some of the tests). The test expected the validator to be completely 24 // unbonded after the Endblocker (go from Bonded -> Unbonding during 25 // ApplyAndReturnValidatorSetUpdates and then Unbonding -> Unbonded during 26 // UnbondAllMatureValidatorQueue). 27 validatorUpdates, err := k.ApplyAndReturnValidatorSetUpdates(ctx) 28 if err != nil { 29 panic(err) 30 } 31 32 // unbond all mature validators from the unbonding queue 33 k.UnbondAllMatureValidators(ctx) 34 35 // Remove all mature unbonding delegations from the ubd queue. 36 matureUnbonds := k.DequeueAllMatureUBDQueue(ctx, ctx.BlockHeader().Time) 37 for _, dvPair := range matureUnbonds { 38 addr, err := sdk.ValAddressFromBech32(dvPair.ValidatorAddress) 39 if err != nil { 40 panic(err) 41 } 42 delegatorAddress := sdk.MustAccAddressFromBech32(dvPair.DelegatorAddress) 43 44 balances, err := k.CompleteUnbonding(ctx, delegatorAddress, addr) 45 if err != nil { 46 continue 47 } 48 49 ctx.EventManager().EmitEvent( 50 sdk.NewEvent( 51 types.EventTypeCompleteUnbonding, 52 sdk.NewAttribute(sdk.AttributeKeyAmount, balances.String()), 53 sdk.NewAttribute(types.AttributeKeyValidator, dvPair.ValidatorAddress), 54 sdk.NewAttribute(types.AttributeKeyDelegator, dvPair.DelegatorAddress), 55 ), 56 ) 57 } 58 59 // Remove all mature redelegations from the red queue. 60 matureRedelegations := k.DequeueAllMatureRedelegationQueue(ctx, ctx.BlockHeader().Time) 61 for _, dvvTriplet := range matureRedelegations { 62 valSrcAddr, err := sdk.ValAddressFromBech32(dvvTriplet.ValidatorSrcAddress) 63 if err != nil { 64 panic(err) 65 } 66 valDstAddr, err := sdk.ValAddressFromBech32(dvvTriplet.ValidatorDstAddress) 67 if err != nil { 68 panic(err) 69 } 70 delegatorAddress := sdk.MustAccAddressFromBech32(dvvTriplet.DelegatorAddress) 71 72 balances, err := k.CompleteRedelegation( 73 ctx, 74 delegatorAddress, 75 valSrcAddr, 76 valDstAddr, 77 ) 78 if err != nil { 79 continue 80 } 81 82 ctx.EventManager().EmitEvent( 83 sdk.NewEvent( 84 types.EventTypeCompleteRedelegation, 85 sdk.NewAttribute(sdk.AttributeKeyAmount, balances.String()), 86 sdk.NewAttribute(types.AttributeKeyDelegator, dvvTriplet.DelegatorAddress), 87 sdk.NewAttribute(types.AttributeKeySrcValidator, dvvTriplet.ValidatorSrcAddress), 88 sdk.NewAttribute(types.AttributeKeyDstValidator, dvvTriplet.ValidatorDstAddress), 89 ), 90 ) 91 } 92 93 return validatorUpdates 94 } 95 96 // ApplyAndReturnValidatorSetUpdates applies and return accumulated updates to the bonded validator set. Also, 97 // * Updates the active valset as keyed by LastValidatorPowerKey. 98 // * Updates the total power as keyed by LastTotalPowerKey. 99 // * Updates validator status' according to updated powers. 100 // * Updates the fee pool bonded vs not-bonded tokens. 101 // * Updates relevant indices. 102 // It gets called once after genesis, another time maybe after genesis transactions, 103 // then once at every EndBlock. 104 // 105 // CONTRACT: Only validators with non-zero power or zero-power that were bonded 106 // at the previous block height or were removed from the validator set entirely 107 // are returned to Tendermint. 108 func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []abci.ValidatorUpdate, err error) { 109 params := k.GetParams(ctx) 110 maxValidators := params.MaxValidators 111 powerReduction := k.PowerReduction(ctx) 112 totalPower := sdk.ZeroInt() 113 amtFromBondedToNotBonded, amtFromNotBondedToBonded := sdk.ZeroInt(), sdk.ZeroInt() 114 115 // Retrieve the last validator set. 116 // The persistent set is updated later in this function. 117 // (see LastValidatorPowerKey). 118 last, err := k.getLastValidatorsByAddr(ctx) 119 if err != nil { 120 return nil, err 121 } 122 123 // Iterate over validators, highest power to lowest. 124 iterator := k.ValidatorsPowerStoreIterator(ctx) 125 defer iterator.Close() 126 127 for count := 0; iterator.Valid() && count < int(maxValidators); iterator.Next() { 128 // everything that is iterated in this loop is becoming or already a 129 // part of the bonded validator set 130 valAddr := sdk.ValAddress(iterator.Value()) 131 validator := k.mustGetValidator(ctx, valAddr) 132 133 if validator.Jailed { 134 panic("should never retrieve a jailed validator from the power store") 135 } 136 137 // if we get to a zero-power validator (which we don't bond), 138 // there are no more possible bonded validators 139 if validator.PotentialConsensusPower(k.PowerReduction(ctx)) == 0 { 140 break 141 } 142 143 // apply the appropriate state change if necessary 144 switch { 145 case validator.IsUnbonded(): 146 validator, err = k.unbondedToBonded(ctx, validator) 147 if err != nil { 148 return 149 } 150 amtFromNotBondedToBonded = amtFromNotBondedToBonded.Add(validator.GetTokens()) 151 case validator.IsUnbonding(): 152 validator, err = k.unbondingToBonded(ctx, validator) 153 if err != nil { 154 return 155 } 156 amtFromNotBondedToBonded = amtFromNotBondedToBonded.Add(validator.GetTokens()) 157 case validator.IsBonded(): 158 // no state change 159 default: 160 panic("unexpected validator status") 161 } 162 163 // fetch the old power bytes 164 valAddrStr, err := sdk.Bech32ifyAddressBytes(sdk.GetConfig().GetBech32ValidatorAddrPrefix(), valAddr) 165 if err != nil { 166 return nil, err 167 } 168 oldPowerBytes, found := last[valAddrStr] 169 newPower := validator.ConsensusPower(powerReduction) 170 newPowerBytes := k.cdc.MustMarshal(&gogotypes.Int64Value{Value: newPower}) 171 172 // update the validator set if power has changed 173 if !found || !bytes.Equal(oldPowerBytes, newPowerBytes) { 174 updates = append(updates, validator.ABCIValidatorUpdate(powerReduction)) 175 176 k.SetLastValidatorPower(ctx, valAddr, newPower) 177 } 178 179 delete(last, valAddrStr) 180 count++ 181 182 totalPower = totalPower.Add(sdk.NewInt(newPower)) 183 } 184 185 noLongerBonded, err := sortNoLongerBonded(last) 186 if err != nil { 187 return nil, err 188 } 189 190 for _, valAddrBytes := range noLongerBonded { 191 validator := k.mustGetValidator(ctx, sdk.ValAddress(valAddrBytes)) 192 validator, err = k.bondedToUnbonding(ctx, validator) 193 if err != nil { 194 return 195 } 196 amtFromBondedToNotBonded = amtFromBondedToNotBonded.Add(validator.GetTokens()) 197 k.DeleteLastValidatorPower(ctx, validator.GetOperator()) 198 updates = append(updates, validator.ABCIValidatorUpdateZero()) 199 } 200 201 // Update the pools based on the recent updates in the validator set: 202 // - The tokens from the non-bonded candidates that enter the new validator set need to be transferred 203 // to the Bonded pool. 204 // - The tokens from the bonded validators that are being kicked out from the validator set 205 // need to be transferred to the NotBonded pool. 206 switch { 207 // Compare and subtract the respective amounts to only perform one transfer. 208 // This is done in order to avoid doing multiple updates inside each iterator/loop. 209 case amtFromNotBondedToBonded.GT(amtFromBondedToNotBonded): 210 k.notBondedTokensToBonded(ctx, amtFromNotBondedToBonded.Sub(amtFromBondedToNotBonded)) 211 case amtFromNotBondedToBonded.LT(amtFromBondedToNotBonded): 212 k.bondedTokensToNotBonded(ctx, amtFromBondedToNotBonded.Sub(amtFromNotBondedToBonded)) 213 default: // equal amounts of tokens; no update required 214 } 215 216 // set total power on lookup index if there are any updates 217 if len(updates) > 0 { 218 k.SetLastTotalPower(ctx, totalPower) 219 } 220 221 return updates, err 222 } 223 224 // Validator state transitions 225 226 func (k Keeper) bondedToUnbonding(ctx sdk.Context, validator types.Validator) (types.Validator, error) { 227 if !validator.IsBonded() { 228 panic(fmt.Sprintf("bad state transition bondedToUnbonding, validator: %v\n", validator)) 229 } 230 231 return k.beginUnbondingValidator(ctx, validator) 232 } 233 234 func (k Keeper) unbondingToBonded(ctx sdk.Context, validator types.Validator) (types.Validator, error) { 235 if !validator.IsUnbonding() { 236 panic(fmt.Sprintf("bad state transition unbondingToBonded, validator: %v\n", validator)) 237 } 238 239 return k.bondValidator(ctx, validator) 240 } 241 242 func (k Keeper) unbondedToBonded(ctx sdk.Context, validator types.Validator) (types.Validator, error) { 243 if !validator.IsUnbonded() { 244 panic(fmt.Sprintf("bad state transition unbondedToBonded, validator: %v\n", validator)) 245 } 246 247 return k.bondValidator(ctx, validator) 248 } 249 250 // UnbondingToUnbonded switches a validator from unbonding state to unbonded state 251 func (k Keeper) UnbondingToUnbonded(ctx sdk.Context, validator types.Validator) types.Validator { 252 if !validator.IsUnbonding() { 253 panic(fmt.Sprintf("bad state transition unbondingToUnbonded, validator: %v\n", validator)) 254 } 255 256 return k.completeUnbondingValidator(ctx, validator) 257 } 258 259 // send a validator to jail 260 func (k Keeper) jailValidator(ctx sdk.Context, validator types.Validator) { 261 if validator.Jailed { 262 panic(fmt.Sprintf("cannot jail already jailed validator, validator: %v\n", validator)) 263 } 264 265 validator.Jailed = true 266 k.SetValidator(ctx, validator) 267 k.DeleteValidatorByPowerIndex(ctx, validator) 268 } 269 270 // remove a validator from jail 271 func (k Keeper) unjailValidator(ctx sdk.Context, validator types.Validator) { 272 if !validator.Jailed { 273 panic(fmt.Sprintf("cannot unjail already unjailed validator, validator: %v\n", validator)) 274 } 275 276 validator.Jailed = false 277 k.SetValidator(ctx, validator) 278 k.SetValidatorByPowerIndex(ctx, validator) 279 } 280 281 // perform all the store operations for when a validator status becomes bonded 282 func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) (types.Validator, error) { 283 // delete the validator by power index, as the key will change 284 k.DeleteValidatorByPowerIndex(ctx, validator) 285 286 validator = validator.UpdateStatus(types.Bonded) 287 288 // save the now bonded validator record to the two referenced stores 289 k.SetValidator(ctx, validator) 290 k.SetValidatorByPowerIndex(ctx, validator) 291 292 // delete from queue if present 293 k.DeleteValidatorQueue(ctx, validator) 294 295 // trigger hook 296 consAddr, err := validator.GetConsAddr() 297 if err != nil { 298 return validator, err 299 } 300 k.AfterValidatorBonded(ctx, consAddr, validator.GetOperator()) 301 302 return validator, err 303 } 304 305 // perform all the store operations for when a validator begins unbonding 306 func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validator) (types.Validator, error) { 307 params := k.GetParams(ctx) 308 309 // delete the validator by power index, as the key will change 310 k.DeleteValidatorByPowerIndex(ctx, validator) 311 312 // sanity check 313 if validator.Status != types.Bonded { 314 panic(fmt.Sprintf("should not already be unbonded or unbonding, validator: %v\n", validator)) 315 } 316 317 validator = validator.UpdateStatus(types.Unbonding) 318 319 // set the unbonding completion time and completion height appropriately 320 validator.UnbondingTime = ctx.BlockHeader().Time.Add(params.UnbondingTime) 321 validator.UnbondingHeight = ctx.BlockHeader().Height 322 323 // save the now unbonded validator record and power index 324 k.SetValidator(ctx, validator) 325 k.SetValidatorByPowerIndex(ctx, validator) 326 327 // Adds to unbonding validator queue 328 k.InsertUnbondingValidatorQueue(ctx, validator) 329 330 // trigger hook 331 consAddr, err := validator.GetConsAddr() 332 if err != nil { 333 return validator, err 334 } 335 k.AfterValidatorBeginUnbonding(ctx, consAddr, validator.GetOperator()) 336 337 return validator, nil 338 } 339 340 // perform all the store operations for when a validator status becomes unbonded 341 func (k Keeper) completeUnbondingValidator(ctx sdk.Context, validator types.Validator) types.Validator { 342 validator = validator.UpdateStatus(types.Unbonded) 343 k.SetValidator(ctx, validator) 344 345 return validator 346 } 347 348 // map of operator bech32-addresses to serialized power 349 // We use bech32 strings here, because we can't have slices as keys: map[[]byte][]byte 350 type validatorsByAddr map[string][]byte 351 352 // get the last validator set 353 func (k Keeper) getLastValidatorsByAddr(ctx sdk.Context) (validatorsByAddr, error) { 354 last := make(validatorsByAddr) 355 356 iterator := k.LastValidatorsIterator(ctx) 357 defer iterator.Close() 358 359 for ; iterator.Valid(); iterator.Next() { 360 // extract the validator address from the key (prefix is 1-byte, addrLen is 1-byte) 361 valAddr := types.AddressFromLastValidatorPowerKey(iterator.Key()) 362 valAddrStr, err := sdk.Bech32ifyAddressBytes(sdk.GetConfig().GetBech32ValidatorAddrPrefix(), valAddr) 363 if err != nil { 364 return nil, err 365 } 366 367 powerBytes := iterator.Value() 368 last[valAddrStr] = make([]byte, len(powerBytes)) 369 copy(last[valAddrStr], powerBytes) 370 } 371 372 return last, nil 373 } 374 375 // given a map of remaining validators to previous bonded power 376 // returns the list of validators to be unbonded, sorted by operator address 377 func sortNoLongerBonded(last validatorsByAddr) ([][]byte, error) { 378 // sort the map keys for determinism 379 noLongerBonded := make([][]byte, len(last)) 380 index := 0 381 382 for valAddrStr := range last { 383 valAddrBytes, err := sdk.ValAddressFromBech32(valAddrStr) 384 if err != nil { 385 return nil, err 386 } 387 noLongerBonded[index] = valAddrBytes 388 index++ 389 } 390 // sorted by address - order doesn't matter 391 sort.SliceStable(noLongerBonded, func(i, j int) bool { 392 // -1 means strictly less than 393 return bytes.Compare(noLongerBonded[i], noLongerBonded[j]) == -1 394 }) 395 396 return noLongerBonded, nil 397 }