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