github.com/cosmos/cosmos-sdk@v0.50.10/x/staking/simulation/operations.go (about)

     1  package simulation
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"math/rand"
     7  
     8  	"cosmossdk.io/math"
     9  
    10  	"github.com/cosmos/cosmos-sdk/baseapp"
    11  	"github.com/cosmos/cosmos-sdk/client"
    12  	"github.com/cosmos/cosmos-sdk/codec"
    13  	"github.com/cosmos/cosmos-sdk/testutil"
    14  	sdk "github.com/cosmos/cosmos-sdk/types"
    15  	simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
    16  	"github.com/cosmos/cosmos-sdk/x/simulation"
    17  	"github.com/cosmos/cosmos-sdk/x/staking/keeper"
    18  	"github.com/cosmos/cosmos-sdk/x/staking/types"
    19  )
    20  
    21  // Simulation operation weights constants
    22  const (
    23  	DefaultWeightMsgCreateValidator           int = 100
    24  	DefaultWeightMsgEditValidator             int = 5
    25  	DefaultWeightMsgDelegate                  int = 100
    26  	DefaultWeightMsgUndelegate                int = 100
    27  	DefaultWeightMsgBeginRedelegate           int = 100
    28  	DefaultWeightMsgCancelUnbondingDelegation int = 100
    29  
    30  	OpWeightMsgCreateValidator           = "op_weight_msg_create_validator"
    31  	OpWeightMsgEditValidator             = "op_weight_msg_edit_validator"
    32  	OpWeightMsgDelegate                  = "op_weight_msg_delegate"
    33  	OpWeightMsgUndelegate                = "op_weight_msg_undelegate"
    34  	OpWeightMsgBeginRedelegate           = "op_weight_msg_begin_redelegate"
    35  	OpWeightMsgCancelUnbondingDelegation = "op_weight_msg_cancel_unbonding_delegation"
    36  )
    37  
    38  // WeightedOperations returns all the operations from the module with their respective weights
    39  func WeightedOperations(
    40  	appParams simtypes.AppParams,
    41  	cdc codec.JSONCodec,
    42  	txGen client.TxConfig,
    43  	ak types.AccountKeeper,
    44  	bk types.BankKeeper,
    45  	k *keeper.Keeper,
    46  ) simulation.WeightedOperations {
    47  	var (
    48  		weightMsgCreateValidator           int
    49  		weightMsgEditValidator             int
    50  		weightMsgDelegate                  int
    51  		weightMsgUndelegate                int
    52  		weightMsgBeginRedelegate           int
    53  		weightMsgCancelUnbondingDelegation int
    54  	)
    55  
    56  	appParams.GetOrGenerate(OpWeightMsgCreateValidator, &weightMsgCreateValidator, nil, func(_ *rand.Rand) {
    57  		weightMsgCreateValidator = DefaultWeightMsgCreateValidator
    58  	})
    59  
    60  	appParams.GetOrGenerate(OpWeightMsgEditValidator, &weightMsgEditValidator, nil, func(_ *rand.Rand) {
    61  		weightMsgEditValidator = DefaultWeightMsgEditValidator
    62  	})
    63  
    64  	appParams.GetOrGenerate(OpWeightMsgDelegate, &weightMsgDelegate, nil, func(_ *rand.Rand) {
    65  		weightMsgDelegate = DefaultWeightMsgDelegate
    66  	})
    67  
    68  	appParams.GetOrGenerate(OpWeightMsgUndelegate, &weightMsgUndelegate, nil, func(_ *rand.Rand) {
    69  		weightMsgUndelegate = DefaultWeightMsgUndelegate
    70  	})
    71  
    72  	appParams.GetOrGenerate(OpWeightMsgBeginRedelegate, &weightMsgBeginRedelegate, nil, func(_ *rand.Rand) {
    73  		weightMsgBeginRedelegate = DefaultWeightMsgBeginRedelegate
    74  	})
    75  
    76  	appParams.GetOrGenerate(OpWeightMsgCancelUnbondingDelegation, &weightMsgCancelUnbondingDelegation, nil, func(_ *rand.Rand) {
    77  		weightMsgCancelUnbondingDelegation = DefaultWeightMsgCancelUnbondingDelegation
    78  	})
    79  
    80  	return simulation.WeightedOperations{
    81  		simulation.NewWeightedOperation(
    82  			weightMsgCreateValidator,
    83  			SimulateMsgCreateValidator(txGen, ak, bk, k),
    84  		),
    85  		simulation.NewWeightedOperation(
    86  			weightMsgEditValidator,
    87  			SimulateMsgEditValidator(txGen, ak, bk, k),
    88  		),
    89  		simulation.NewWeightedOperation(
    90  			weightMsgDelegate,
    91  			SimulateMsgDelegate(txGen, ak, bk, k),
    92  		),
    93  		simulation.NewWeightedOperation(
    94  			weightMsgUndelegate,
    95  			SimulateMsgUndelegate(txGen, ak, bk, k),
    96  		),
    97  		simulation.NewWeightedOperation(
    98  			weightMsgBeginRedelegate,
    99  			SimulateMsgBeginRedelegate(txGen, ak, bk, k),
   100  		),
   101  		simulation.NewWeightedOperation(
   102  			weightMsgCancelUnbondingDelegation,
   103  			SimulateMsgCancelUnbondingDelegate(txGen, ak, bk, k),
   104  		),
   105  	}
   106  }
   107  
   108  // SimulateMsgCreateValidator generates a MsgCreateValidator with random values
   109  func SimulateMsgCreateValidator(
   110  	txGen client.TxConfig,
   111  	ak types.AccountKeeper,
   112  	bk types.BankKeeper,
   113  	k *keeper.Keeper,
   114  ) simtypes.Operation {
   115  	return func(
   116  		r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
   117  	) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
   118  		msgType := sdk.MsgTypeURL(&types.MsgCreateValidator{})
   119  
   120  		simAccount, _ := simtypes.RandomAcc(r, accs)
   121  		address := sdk.ValAddress(simAccount.Address)
   122  
   123  		// ensure the validator doesn't exist already
   124  		_, err := k.GetValidator(ctx, address)
   125  		if err == nil {
   126  			return simtypes.NoOpMsg(types.ModuleName, msgType, "validator already exists"), nil, nil
   127  		}
   128  
   129  		denom, err := k.BondDenom(ctx)
   130  		if err != nil {
   131  			return simtypes.NoOpMsg(types.ModuleName, msgType, "bond denom not found"), nil, err
   132  		}
   133  
   134  		balance := bk.GetBalance(ctx, simAccount.Address, denom).Amount
   135  		if !balance.IsPositive() {
   136  			return simtypes.NoOpMsg(types.ModuleName, msgType, "balance is negative"), nil, nil
   137  		}
   138  
   139  		amount, err := simtypes.RandPositiveInt(r, balance)
   140  		if err != nil {
   141  			return simtypes.NoOpMsg(types.ModuleName, msgType, "unable to generate positive amount"), nil, err
   142  		}
   143  
   144  		selfDelegation := sdk.NewCoin(denom, amount)
   145  
   146  		account := ak.GetAccount(ctx, simAccount.Address)
   147  		spendable := bk.SpendableCoins(ctx, account.GetAddress())
   148  
   149  		var fees sdk.Coins
   150  
   151  		coins, hasNeg := spendable.SafeSub(selfDelegation)
   152  		if !hasNeg {
   153  			fees, err = simtypes.RandomFees(r, ctx, coins)
   154  			if err != nil {
   155  				return simtypes.NoOpMsg(types.ModuleName, msgType, "unable to generate fees"), nil, err
   156  			}
   157  		}
   158  
   159  		description := types.NewDescription(
   160  			simtypes.RandStringOfLength(r, 10),
   161  			simtypes.RandStringOfLength(r, 10),
   162  			simtypes.RandStringOfLength(r, 10),
   163  			simtypes.RandStringOfLength(r, 10),
   164  			simtypes.RandStringOfLength(r, 10),
   165  		)
   166  
   167  		maxCommission := math.LegacyNewDecWithPrec(int64(simtypes.RandIntBetween(r, 0, 100)), 2)
   168  		commission := types.NewCommissionRates(
   169  			simtypes.RandomDecAmount(r, maxCommission),
   170  			maxCommission,
   171  			simtypes.RandomDecAmount(r, maxCommission),
   172  		)
   173  
   174  		msg, err := types.NewMsgCreateValidator(address.String(), simAccount.ConsKey.PubKey(), selfDelegation, description, commission, math.OneInt())
   175  		if err != nil {
   176  			return simtypes.NoOpMsg(types.ModuleName, sdk.MsgTypeURL(msg), "unable to create CreateValidator message"), nil, err
   177  		}
   178  
   179  		txCtx := simulation.OperationInput{
   180  			R:             r,
   181  			App:           app,
   182  			TxGen:         txGen,
   183  			Cdc:           nil,
   184  			Msg:           msg,
   185  			Context:       ctx,
   186  			SimAccount:    simAccount,
   187  			AccountKeeper: ak,
   188  			ModuleName:    types.ModuleName,
   189  		}
   190  
   191  		return simulation.GenAndDeliverTx(txCtx, fees)
   192  	}
   193  }
   194  
   195  // SimulateMsgEditValidator generates a MsgEditValidator with random values
   196  func SimulateMsgEditValidator(
   197  	txGen client.TxConfig,
   198  	ak types.AccountKeeper,
   199  	bk types.BankKeeper,
   200  	k *keeper.Keeper,
   201  ) simtypes.Operation {
   202  	return func(
   203  		r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
   204  	) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
   205  		msgType := sdk.MsgTypeURL(&types.MsgEditValidator{})
   206  
   207  		vals, err := k.GetAllValidators(ctx)
   208  		if err != nil {
   209  			return simtypes.NoOpMsg(types.ModuleName, msgType, "unable to get validators"), nil, err
   210  		}
   211  
   212  		if len(vals) == 0 {
   213  			return simtypes.NoOpMsg(types.ModuleName, msgType, "number of validators equal zero"), nil, nil
   214  		}
   215  
   216  		val, ok := testutil.RandSliceElem(r, vals)
   217  		if !ok {
   218  			return simtypes.NoOpMsg(types.ModuleName, msgType, "unable to pick a validator"), nil, nil
   219  		}
   220  
   221  		address := val.GetOperator()
   222  		newCommissionRate := simtypes.RandomDecAmount(r, val.Commission.MaxRate)
   223  
   224  		if err := val.Commission.ValidateNewRate(newCommissionRate, ctx.BlockHeader().Time); err != nil {
   225  			// skip as the commission is invalid
   226  			return simtypes.NoOpMsg(types.ModuleName, msgType, "invalid commission rate"), nil, nil
   227  		}
   228  
   229  		bz, err := k.ValidatorAddressCodec().StringToBytes(val.GetOperator())
   230  		if err != nil {
   231  			return simtypes.NoOpMsg(types.ModuleName, msgType, "error getting validator address bytes"), nil, err
   232  		}
   233  
   234  		simAccount, found := simtypes.FindAccount(accs, sdk.AccAddress(bz))
   235  		if !found {
   236  			return simtypes.NoOpMsg(types.ModuleName, msgType, "unable to find account"), nil, fmt.Errorf("validator %s not found", val.GetOperator())
   237  		}
   238  
   239  		account := ak.GetAccount(ctx, simAccount.Address)
   240  		spendable := bk.SpendableCoins(ctx, account.GetAddress())
   241  
   242  		description := types.NewDescription(
   243  			simtypes.RandStringOfLength(r, 10),
   244  			simtypes.RandStringOfLength(r, 10),
   245  			simtypes.RandStringOfLength(r, 10),
   246  			simtypes.RandStringOfLength(r, 10),
   247  			simtypes.RandStringOfLength(r, 10),
   248  		)
   249  
   250  		msg := types.NewMsgEditValidator(address, description, &newCommissionRate, nil)
   251  
   252  		txCtx := simulation.OperationInput{
   253  			R:               r,
   254  			App:             app,
   255  			TxGen:           txGen,
   256  			Cdc:             nil,
   257  			Msg:             msg,
   258  			Context:         ctx,
   259  			SimAccount:      simAccount,
   260  			AccountKeeper:   ak,
   261  			Bankkeeper:      bk,
   262  			ModuleName:      types.ModuleName,
   263  			CoinsSpentInMsg: spendable,
   264  		}
   265  
   266  		return simulation.GenAndDeliverTxWithRandFees(txCtx)
   267  	}
   268  }
   269  
   270  // SimulateMsgDelegate generates a MsgDelegate with random values
   271  func SimulateMsgDelegate(
   272  	txGen client.TxConfig,
   273  	ak types.AccountKeeper,
   274  	bk types.BankKeeper,
   275  	k *keeper.Keeper,
   276  ) simtypes.Operation {
   277  	return func(
   278  		r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
   279  	) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
   280  		msgType := sdk.MsgTypeURL(&types.MsgDelegate{})
   281  		denom, err := k.BondDenom(ctx)
   282  		if err != nil {
   283  			return simtypes.NoOpMsg(types.ModuleName, msgType, "bond denom not found"), nil, err
   284  		}
   285  
   286  		vals, err := k.GetAllValidators(ctx)
   287  		if err != nil {
   288  			return simtypes.NoOpMsg(types.ModuleName, msgType, "unable to get validators"), nil, err
   289  		}
   290  
   291  		if len(vals) == 0 {
   292  			return simtypes.NoOpMsg(types.ModuleName, msgType, "number of validators equal zero"), nil, nil
   293  		}
   294  
   295  		simAccount, _ := simtypes.RandomAcc(r, accs)
   296  		val, ok := testutil.RandSliceElem(r, vals)
   297  		if !ok {
   298  			return simtypes.NoOpMsg(types.ModuleName, msgType, "unable to pick a validator"), nil, nil
   299  		}
   300  
   301  		if val.InvalidExRate() {
   302  			return simtypes.NoOpMsg(types.ModuleName, msgType, "validator's invalid echange rate"), nil, nil
   303  		}
   304  
   305  		amount := bk.GetBalance(ctx, simAccount.Address, denom).Amount
   306  		if !amount.IsPositive() {
   307  			return simtypes.NoOpMsg(types.ModuleName, msgType, "balance is negative"), nil, nil
   308  		}
   309  
   310  		amount, err = simtypes.RandPositiveInt(r, amount)
   311  		if err != nil {
   312  			return simtypes.NoOpMsg(types.ModuleName, msgType, "unable to generate positive amount"), nil, err
   313  		}
   314  
   315  		bondAmt := sdk.NewCoin(denom, amount)
   316  
   317  		account := ak.GetAccount(ctx, simAccount.Address)
   318  		spendable := bk.SpendableCoins(ctx, account.GetAddress())
   319  
   320  		var fees sdk.Coins
   321  
   322  		coins, hasNeg := spendable.SafeSub(bondAmt)
   323  		if !hasNeg {
   324  			fees, err = simtypes.RandomFees(r, ctx, coins)
   325  			if err != nil {
   326  				return simtypes.NoOpMsg(types.ModuleName, msgType, "unable to generate fees"), nil, err
   327  			}
   328  		}
   329  
   330  		msg := types.NewMsgDelegate(simAccount.Address.String(), val.GetOperator(), bondAmt)
   331  
   332  		txCtx := simulation.OperationInput{
   333  			R:             r,
   334  			App:           app,
   335  			TxGen:         txGen,
   336  			Cdc:           nil,
   337  			Msg:           msg,
   338  			Context:       ctx,
   339  			SimAccount:    simAccount,
   340  			AccountKeeper: ak,
   341  			ModuleName:    types.ModuleName,
   342  		}
   343  
   344  		return simulation.GenAndDeliverTx(txCtx, fees)
   345  	}
   346  }
   347  
   348  // SimulateMsgUndelegate generates a MsgUndelegate with random values
   349  func SimulateMsgUndelegate(
   350  	txGen client.TxConfig,
   351  	ak types.AccountKeeper,
   352  	bk types.BankKeeper,
   353  	k *keeper.Keeper,
   354  ) simtypes.Operation {
   355  	return func(
   356  		r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
   357  	) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
   358  		msgType := sdk.MsgTypeURL(&types.MsgUndelegate{})
   359  
   360  		vals, err := k.GetAllValidators(ctx)
   361  		if err != nil {
   362  			return simtypes.NoOpMsg(types.ModuleName, msgType, "unable to get validators"), nil, err
   363  		}
   364  
   365  		if len(vals) == 0 {
   366  			return simtypes.NoOpMsg(types.ModuleName, msgType, "number of validators equal zero"), nil, nil
   367  		}
   368  
   369  		val, ok := testutil.RandSliceElem(r, vals)
   370  		if !ok {
   371  			return simtypes.NoOpMsg(types.ModuleName, msgType, "validator is not ok"), nil, nil
   372  		}
   373  
   374  		valAddr, err := k.ValidatorAddressCodec().StringToBytes(val.GetOperator())
   375  		if err != nil {
   376  			return simtypes.NoOpMsg(types.ModuleName, msgType, "error getting validator address bytes"), nil, err
   377  		}
   378  		delegations, err := k.GetValidatorDelegations(ctx, valAddr)
   379  		if err != nil {
   380  			return simtypes.NoOpMsg(types.ModuleName, msgType, "error getting validator delegations"), nil, nil
   381  		}
   382  
   383  		if delegations == nil {
   384  			return simtypes.NoOpMsg(types.ModuleName, msgType, "keeper does have any delegation entries"), nil, nil
   385  		}
   386  
   387  		// get random delegator from validator
   388  		delegation := delegations[r.Intn(len(delegations))]
   389  		delAddr := delegation.GetDelegatorAddr()
   390  
   391  		delAddrBz, err := ak.AddressCodec().StringToBytes(delAddr)
   392  		if err != nil {
   393  			return simtypes.NoOpMsg(types.ModuleName, msgType, "error getting delegator address bytes"), nil, err
   394  		}
   395  
   396  		hasMaxUD, err := k.HasMaxUnbondingDelegationEntries(ctx, delAddrBz, valAddr)
   397  		if err != nil {
   398  			return simtypes.NoOpMsg(types.ModuleName, msgType, "error getting max unbonding delegation entries"), nil, err
   399  		}
   400  
   401  		if hasMaxUD {
   402  			return simtypes.NoOpMsg(types.ModuleName, msgType, "keeper does have a max unbonding delegation entries"), nil, nil
   403  		}
   404  
   405  		totalBond := val.TokensFromShares(delegation.GetShares()).TruncateInt()
   406  		if !totalBond.IsPositive() {
   407  			return simtypes.NoOpMsg(types.ModuleName, msgType, "total bond is negative"), nil, nil
   408  		}
   409  
   410  		unbondAmt, err := simtypes.RandPositiveInt(r, totalBond)
   411  		if err != nil {
   412  			return simtypes.NoOpMsg(types.ModuleName, msgType, "invalid unbond amount"), nil, err
   413  		}
   414  
   415  		if unbondAmt.IsZero() {
   416  			return simtypes.NoOpMsg(types.ModuleName, msgType, "unbond amount is zero"), nil, nil
   417  		}
   418  
   419  		bondDenom, err := k.BondDenom(ctx)
   420  		if err != nil {
   421  			return simtypes.NoOpMsg(types.ModuleName, msgType, "bond denom not found"), nil, err
   422  		}
   423  
   424  		msg := types.NewMsgUndelegate(
   425  			delAddr, val.GetOperator(), sdk.NewCoin(bondDenom, unbondAmt),
   426  		)
   427  
   428  		// need to retrieve the simulation account associated with delegation to retrieve PrivKey
   429  		var simAccount simtypes.Account
   430  
   431  		for _, simAcc := range accs {
   432  			if simAcc.Address.Equals(sdk.AccAddress(delAddrBz)) {
   433  				simAccount = simAcc
   434  				break
   435  			}
   436  		}
   437  		// if simaccount.PrivKey == nil, delegation address does not exist in accs. However, since smart contracts and module accounts can stake, we can ignore the error
   438  		if simAccount.PrivKey == nil {
   439  			return simtypes.NoOpMsg(types.ModuleName, sdk.MsgTypeURL(msg), "account private key is nil"), nil, nil
   440  		}
   441  
   442  		account := ak.GetAccount(ctx, delAddrBz)
   443  		spendable := bk.SpendableCoins(ctx, account.GetAddress())
   444  
   445  		txCtx := simulation.OperationInput{
   446  			R:               r,
   447  			App:             app,
   448  			TxGen:           txGen,
   449  			Cdc:             nil,
   450  			Msg:             msg,
   451  			Context:         ctx,
   452  			SimAccount:      simAccount,
   453  			AccountKeeper:   ak,
   454  			Bankkeeper:      bk,
   455  			ModuleName:      types.ModuleName,
   456  			CoinsSpentInMsg: spendable,
   457  		}
   458  
   459  		return simulation.GenAndDeliverTxWithRandFees(txCtx)
   460  	}
   461  }
   462  
   463  // SimulateMsgCancelUnbondingDelegate generates a MsgCancelUnbondingDelegate with random values
   464  func SimulateMsgCancelUnbondingDelegate(
   465  	txGen client.TxConfig,
   466  	ak types.AccountKeeper,
   467  	bk types.BankKeeper,
   468  	k *keeper.Keeper,
   469  ) simtypes.Operation {
   470  	return func(
   471  		r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
   472  	) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
   473  		msgType := sdk.MsgTypeURL(&types.MsgCancelUnbondingDelegation{})
   474  
   475  		vals, err := k.GetAllValidators(ctx)
   476  		if err != nil {
   477  			return simtypes.NoOpMsg(types.ModuleName, msgType, "unable to get validators"), nil, err
   478  		}
   479  
   480  		if len(vals) == 0 {
   481  			return simtypes.NoOpMsg(types.ModuleName, msgType, "number of validators equal zero"), nil, nil
   482  		}
   483  
   484  		simAccount, _ := simtypes.RandomAcc(r, accs)
   485  		val, ok := testutil.RandSliceElem(r, vals)
   486  		if !ok {
   487  			return simtypes.NoOpMsg(types.ModuleName, msgType, "validator is not ok"), nil, nil
   488  		}
   489  
   490  		if val.IsJailed() || val.InvalidExRate() {
   491  			return simtypes.NoOpMsg(types.ModuleName, msgType, "validator is jailed"), nil, nil
   492  		}
   493  
   494  		valAddr, err := k.ValidatorAddressCodec().StringToBytes(val.GetOperator())
   495  		if err != nil {
   496  			return simtypes.NoOpMsg(types.ModuleName, msgType, "error getting validator address bytes"), nil, err
   497  		}
   498  		unbondingDelegation, err := k.GetUnbondingDelegation(ctx, simAccount.Address, valAddr)
   499  		if err != nil {
   500  			return simtypes.NoOpMsg(types.ModuleName, msgType, "account does have any unbonding delegation"), nil, nil
   501  		}
   502  
   503  		// This is a temporary fix to make staking simulation pass. We should fetch
   504  		// the first unbondingDelegationEntry that matches the creationHeight, because
   505  		// currently the staking msgServer chooses the first unbondingDelegationEntry
   506  		// with the matching creationHeight.
   507  		//
   508  		// ref: https://github.com/cosmos/cosmos-sdk/issues/12932
   509  		creationHeight := unbondingDelegation.Entries[r.Intn(len(unbondingDelegation.Entries))].CreationHeight
   510  
   511  		var unbondingDelegationEntry types.UnbondingDelegationEntry
   512  
   513  		for _, entry := range unbondingDelegation.Entries {
   514  			if entry.CreationHeight == creationHeight {
   515  				unbondingDelegationEntry = entry
   516  				break
   517  			}
   518  		}
   519  
   520  		if unbondingDelegationEntry.CompletionTime.Before(ctx.BlockTime()) {
   521  			return simtypes.NoOpMsg(types.ModuleName, msgType, "unbonding delegation is already processed"), nil, nil
   522  		}
   523  
   524  		if !unbondingDelegationEntry.Balance.IsPositive() {
   525  			return simtypes.NoOpMsg(types.ModuleName, msgType, "delegator receiving balance is negative"), nil, nil
   526  		}
   527  
   528  		cancelBondAmt := simtypes.RandomAmount(r, unbondingDelegationEntry.Balance)
   529  
   530  		if cancelBondAmt.IsZero() {
   531  			return simtypes.NoOpMsg(types.ModuleName, msgType, "cancelBondAmt amount is zero"), nil, nil
   532  		}
   533  
   534  		bondDenom, err := k.BondDenom(ctx)
   535  		if err != nil {
   536  			return simtypes.NoOpMsg(types.ModuleName, msgType, "bond denom not found"), nil, err
   537  		}
   538  
   539  		msg := types.NewMsgCancelUnbondingDelegation(
   540  			simAccount.Address.String(), val.GetOperator(), unbondingDelegationEntry.CreationHeight, sdk.NewCoin(bondDenom, cancelBondAmt),
   541  		)
   542  
   543  		spendable := bk.SpendableCoins(ctx, simAccount.Address)
   544  
   545  		txCtx := simulation.OperationInput{
   546  			R:               r,
   547  			App:             app,
   548  			TxGen:           txGen,
   549  			Cdc:             nil,
   550  			Msg:             msg,
   551  			Context:         ctx,
   552  			SimAccount:      simAccount,
   553  			AccountKeeper:   ak,
   554  			Bankkeeper:      bk,
   555  			ModuleName:      types.ModuleName,
   556  			CoinsSpentInMsg: spendable,
   557  		}
   558  
   559  		return simulation.GenAndDeliverTxWithRandFees(txCtx)
   560  	}
   561  }
   562  
   563  // SimulateMsgBeginRedelegate generates a MsgBeginRedelegate with random values
   564  func SimulateMsgBeginRedelegate(
   565  	txGen client.TxConfig,
   566  	ak types.AccountKeeper,
   567  	bk types.BankKeeper,
   568  	k *keeper.Keeper,
   569  ) simtypes.Operation {
   570  	return func(
   571  		r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
   572  	) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
   573  		msgType := sdk.MsgTypeURL(&types.MsgBeginRedelegate{})
   574  
   575  		allVals, err := k.GetAllValidators(ctx)
   576  		if err != nil {
   577  			return simtypes.NoOpMsg(types.ModuleName, msgType, "unable to get validators"), nil, err
   578  		}
   579  
   580  		if len(allVals) == 0 {
   581  			return simtypes.NoOpMsg(types.ModuleName, msgType, "number of validators equal zero"), nil, nil
   582  		}
   583  
   584  		srcVal, ok := testutil.RandSliceElem(r, allVals)
   585  		if !ok {
   586  			return simtypes.NoOpMsg(types.ModuleName, msgType, "unable to pick validator"), nil, nil
   587  		}
   588  
   589  		srcAddr, err := k.ValidatorAddressCodec().StringToBytes(srcVal.GetOperator())
   590  		if err != nil {
   591  			return simtypes.NoOpMsg(types.ModuleName, msgType, "error getting validator address bytes"), nil, err
   592  		}
   593  		delegations, err := k.GetValidatorDelegations(ctx, srcAddr)
   594  		if err != nil {
   595  			return simtypes.NoOpMsg(types.ModuleName, msgType, "error getting validator delegations"), nil, nil
   596  		}
   597  
   598  		if delegations == nil {
   599  			return simtypes.NoOpMsg(types.ModuleName, msgType, "keeper does have any delegation entries"), nil, nil
   600  		}
   601  
   602  		// get random delegator from src validator
   603  		delegation := delegations[r.Intn(len(delegations))]
   604  		delAddr := delegation.GetDelegatorAddr()
   605  
   606  		delAddrBz, err := ak.AddressCodec().StringToBytes(delAddr)
   607  		if err != nil {
   608  			return simtypes.NoOpMsg(types.ModuleName, msgType, "error getting delegator address bytes"), nil, err
   609  		}
   610  
   611  		hasRecRedel, err := k.HasReceivingRedelegation(ctx, delAddrBz, srcAddr)
   612  		if err != nil {
   613  			return simtypes.NoOpMsg(types.ModuleName, msgType, "error getting receiving redelegation"), nil, err
   614  		}
   615  
   616  		if hasRecRedel {
   617  			return simtypes.NoOpMsg(types.ModuleName, msgType, "receveing redelegation is not allowed"), nil, nil // skip
   618  		}
   619  
   620  		// get random destination validator
   621  		destVal, ok := testutil.RandSliceElem(r, allVals)
   622  		if !ok {
   623  			return simtypes.NoOpMsg(types.ModuleName, msgType, "unable to pick validator"), nil, nil
   624  		}
   625  
   626  		destAddr, err := k.ValidatorAddressCodec().StringToBytes(destVal.GetOperator())
   627  		if err != nil {
   628  			return simtypes.NoOpMsg(types.ModuleName, msgType, "error getting validator address bytes"), nil, err
   629  		}
   630  		hasMaxRedel, err := k.HasMaxRedelegationEntries(ctx, delAddrBz, srcAddr, destAddr)
   631  		if err != nil {
   632  			return simtypes.NoOpMsg(types.ModuleName, msgType, "error getting max redelegation entries"), nil, err
   633  		}
   634  
   635  		if bytes.Equal(srcAddr, destAddr) || destVal.InvalidExRate() || hasMaxRedel {
   636  			return simtypes.NoOpMsg(types.ModuleName, msgType, "checks failed"), nil, nil
   637  		}
   638  
   639  		totalBond := srcVal.TokensFromShares(delegation.GetShares()).TruncateInt()
   640  		if !totalBond.IsPositive() {
   641  			return simtypes.NoOpMsg(types.ModuleName, msgType, "total bond is negative"), nil, nil
   642  		}
   643  
   644  		redAmt, err := simtypes.RandPositiveInt(r, totalBond)
   645  		if err != nil {
   646  			return simtypes.NoOpMsg(types.ModuleName, msgType, "unable to generate positive amount"), nil, err
   647  		}
   648  
   649  		if redAmt.IsZero() {
   650  			return simtypes.NoOpMsg(types.ModuleName, msgType, "amount is zero"), nil, nil
   651  		}
   652  
   653  		// check if the shares truncate to zero
   654  		shares, err := srcVal.SharesFromTokens(redAmt)
   655  		if err != nil {
   656  			return simtypes.NoOpMsg(types.ModuleName, msgType, "invalid shares"), nil, err
   657  		}
   658  
   659  		if srcVal.TokensFromShares(shares).TruncateInt().IsZero() {
   660  			return simtypes.NoOpMsg(types.ModuleName, msgType, "shares truncate to zero"), nil, nil // skip
   661  		}
   662  
   663  		// need to retrieve the simulation account associated with delegation to retrieve PrivKey
   664  		var simAccount simtypes.Account
   665  
   666  		for _, simAcc := range accs {
   667  			if simAcc.Address.Equals(sdk.AccAddress(delAddrBz)) {
   668  				simAccount = simAcc
   669  				break
   670  			}
   671  		}
   672  
   673  		// if simaccount.PrivKey == nil, delegation address does not exist in accs. However, since smart contracts and module accounts can stake, we can ignore the error
   674  		if simAccount.PrivKey == nil {
   675  			return simtypes.NoOpMsg(types.ModuleName, msgType, "account private key is nil"), nil, nil
   676  		}
   677  
   678  		account := ak.GetAccount(ctx, delAddrBz)
   679  		spendable := bk.SpendableCoins(ctx, account.GetAddress())
   680  
   681  		bondDenom, err := k.BondDenom(ctx)
   682  		if err != nil {
   683  			return simtypes.NoOpMsg(types.ModuleName, msgType, "bond denom not found"), nil, err
   684  		}
   685  
   686  		msg := types.NewMsgBeginRedelegate(
   687  			delAddr, srcVal.GetOperator(), destVal.GetOperator(),
   688  			sdk.NewCoin(bondDenom, redAmt),
   689  		)
   690  
   691  		txCtx := simulation.OperationInput{
   692  			R:               r,
   693  			App:             app,
   694  			TxGen:           txGen,
   695  			Cdc:             nil,
   696  			Msg:             msg,
   697  			Context:         ctx,
   698  			SimAccount:      simAccount,
   699  			AccountKeeper:   ak,
   700  			Bankkeeper:      bk,
   701  			ModuleName:      types.ModuleName,
   702  			CoinsSpentInMsg: spendable,
   703  		}
   704  
   705  		return simulation.GenAndDeliverTxWithRandFees(txCtx)
   706  	}
   707  }