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  }