func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validator) types.Validator {
	params := k.GetParams(ctx)
	k.DeleteValidatorByPowerIndex(ctx, validator)
	if validator.Status != sdk.Bonded {
		panic(fmt.Sprintf("should not already be unbonded or unbonding, validator: %v\n", validator))
	}
	validator = validator.UpdateStatus(sdk.Unbonding)
	validator.UnbondingCompletionTime = ctx.BlockHeader().Time.Add(params.UnbondingTime)
	validator.UnbondingHeight = ctx.BlockHeader().Height
	k.SetValidator(ctx, validator)
	k.SetValidatorByPowerIndex(ctx, validator)
	k.InsertValidatorQueue(ctx, validator)
	k.AfterValidatorBeginUnbonding(ctx, validator.ConsAddress(), validator.OperatorAddress)
	return validator
}
perform all the store operations for when a validator begins unbonding
package keeper
import (
	"bytes"
	"fmt"
	"sort"
	abci "github.com/tendermint/tendermint/abci/types"
	"github.com/Dipper-Labs/Dipper-Protocol/app/v0/staking/types"
	sdk "github.com/Dipper-Labs/Dipper-Protocol/types"
)
func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []abci.ValidatorUpdate) {
	logger := k.Logger(ctx)
	store := ctx.KVStore(k.storeKey)
	maxValidators := k.GetParams(ctx).MaxValidators
	totalPower := sdk.ZeroInt()
	amtFromBondedToNotBonded, amtFromNotBondedToBonded := sdk.ZeroInt(), sdk.ZeroInt()
	last := k.getLastValidatorsByAddr(ctx)
	iterator := sdk.KVStoreReversePrefixIterator(store, types.ValidatorsByPowerIndexKey)
	defer iterator.Close()
	for count := 0; iterator.Valid() && count < int(maxValidators); iterator.Next() {
		valAddr := sdk.ValAddress(iterator.Value())
		validator := k.mustGetValidator(ctx, valAddr)
		if validator.Jailed {
			panic("should never retrieve a jailed validator from the power store")
		}
		if validator.PotentialConsensusPower() == 0 {
			break
		}
		logger.Info(fmt.Sprintf("voting power:  %d", validator.PotentialConsensusPower()))
		switch {
		case validator.IsUnbonded():
			validator = k.unbondedToBonded(ctx, validator)
			amtFromNotBondedToBonded = amtFromNotBondedToBonded.Add(validator.GetTokens())
		case validator.IsUnbonding():
			validator = k.unbondingToBonded(ctx, validator)
			amtFromNotBondedToBonded = amtFromNotBondedToBonded.Add(validator.GetTokens())
		case validator.IsBonded():
		default:
			panic("unexpected validator status")
		}
		var valAddrBytes [sdk.AddrLen]byte
		copy(valAddrBytes[:], valAddr[:])
		oldPowerBytes, found := last[valAddrBytes]
		newPower := validator.ConsensusPower()
		newPowerBytes := k.cdc.MustMarshalBinaryLengthPrefixed(newPower)
		if !found || !bytes.Equal(oldPowerBytes, newPowerBytes) {
			updates = append(updates, validator.ABCIValidatorUpdate())
			k.SetLastValidatorPower(ctx, valAddr, newPower)
		}
		delete(last, valAddrBytes)
		count++
		totalPower = totalPower.Add(sdk.NewInt(newPower))
	}
	noLongerBonded := sortNoLongerBonded(last)
	for _, valAddrBytes := range noLongerBonded {
		validator := k.mustGetValidator(ctx, sdk.ValAddress(valAddrBytes))
		validator = k.bondedToUnbonding(ctx, validator)
		amtFromBondedToNotBonded = amtFromBondedToNotBonded.Add(validator.GetTokens())
		k.DeleteLastValidatorPower(ctx, validator.GetOperator())
		updates = append(updates, validator.ABCIValidatorUpdateZero())
	}
	switch {
	case amtFromNotBondedToBonded.GT(amtFromBondedToNotBonded):
		k.notBondedTokensToBonded(ctx, amtFromNotBondedToBonded.Sub(amtFromBondedToNotBonded))
	case amtFromNotBondedToBonded.LT(amtFromBondedToNotBonded):
		k.bondedTokensToNotBonded(ctx, amtFromBondedToNotBonded.Sub(amtFromNotBondedToBonded))
	default:
	}
	if len(updates) > 0 {
		k.SetLastTotalPower(ctx, totalPower)
		for _, item := range updates {
			logger.Info(fmt.Sprintf("validator: %x, power: %d", item.GetPubKey().Data, item.Power))
		}
	}
	return updates
}
func (k Keeper) bondedToUnbonding(ctx sdk.Context, validator types.Validator) types.Validator {
	if !validator.IsBonded() {
		panic(fmt.Sprintf("bad state transition bondedToUnbonding, validator: %v\n", validator))
	}
	return k.beginUnbondingValidator(ctx, validator)
}
func (k Keeper) unbondingToBonded(ctx sdk.Context, validator types.Validator) types.Validator {
	if !validator.IsUnbonding() {
		panic(fmt.Sprintf("bad state transition unbondingToBonded, validator: %v\n", validator))
	}
	return k.bondValidator(ctx, validator)
}
func (k Keeper) unbondedToBonded(ctx sdk.Context, validator types.Validator) types.Validator {
	if !validator.IsUnbonded() {
		panic(fmt.Sprintf("bad state transition unbondedToBonded, validator: %v\n", validator))
	}
	return k.bondValidator(ctx, validator)
}
func (k Keeper) unbondingToUnbonded(ctx sdk.Context, validator types.Validator) types.Validator {
	if !validator.IsUnbonding() {
		panic(fmt.Sprintf("bad state transition unbondingToBonded, validator: %v\n", validator))
	}
	return k.completeUnbondingValidator(ctx, validator)
}
func (k Keeper) jailValidator(ctx sdk.Context, validator types.Validator) {
	if validator.Jailed {
		panic(fmt.Sprintf("cannot jail already jailed validator, validator: %v\n", validator))
	}
	validator.Jailed = true
	k.SetValidator(ctx, validator)
	k.DeleteValidatorByPowerIndex(ctx, validator)
}
func (k Keeper) unjailValidator(ctx sdk.Context, validator types.Validator) {
	if !validator.Jailed {
		panic(fmt.Sprintf("cannot unjail already unjailed validator, validator: %v\n", validator))
	}
	validator.Jailed = false
	k.SetValidator(ctx, validator)
	k.SetValidatorByPowerIndex(ctx, validator)
}
func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types.Validator {
	k.DeleteValidatorByPowerIndex(ctx, validator)
	validator = validator.UpdateStatus(sdk.Bonded)
	k.SetValidator(ctx, validator)
	k.SetValidatorByPowerIndex(ctx, validator)
	k.DeleteValidatorQueue(ctx, validator)
	k.AfterValidatorBonded(ctx, validator.ConsAddress(), validator.OperatorAddress)
	return validator
}