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

     1  package simulation
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"math/rand"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/cosmos/cosmos-sdk/baseapp"
    11  	"github.com/cosmos/cosmos-sdk/client"
    12  	"github.com/cosmos/cosmos-sdk/codec"
    13  	cdctypes "github.com/cosmos/cosmos-sdk/codec/types"
    14  	simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims"
    15  	sdk "github.com/cosmos/cosmos-sdk/types"
    16  	simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
    17  	"github.com/cosmos/cosmos-sdk/x/group"
    18  	"github.com/cosmos/cosmos-sdk/x/group/keeper"
    19  	"github.com/cosmos/cosmos-sdk/x/simulation"
    20  )
    21  
    22  var initialGroupID = uint64(100000000000000)
    23  
    24  // group message types
    25  var (
    26  	TypeMsgCreateGroup                     = sdk.MsgTypeURL(&group.MsgCreateGroup{})
    27  	TypeMsgUpdateGroupMembers              = sdk.MsgTypeURL(&group.MsgUpdateGroupMembers{})
    28  	TypeMsgUpdateGroupAdmin                = sdk.MsgTypeURL(&group.MsgUpdateGroupAdmin{})
    29  	TypeMsgUpdateGroupMetadata             = sdk.MsgTypeURL(&group.MsgUpdateGroupMetadata{})
    30  	TypeMsgCreateGroupWithPolicy           = sdk.MsgTypeURL(&group.MsgCreateGroupWithPolicy{})
    31  	TypeMsgCreateGroupPolicy               = sdk.MsgTypeURL(&group.MsgCreateGroupPolicy{})
    32  	TypeMsgUpdateGroupPolicyAdmin          = sdk.MsgTypeURL(&group.MsgUpdateGroupPolicyAdmin{})
    33  	TypeMsgUpdateGroupPolicyDecisionPolicy = sdk.MsgTypeURL(&group.MsgUpdateGroupPolicyDecisionPolicy{})
    34  	TypeMsgUpdateGroupPolicyMetadata       = sdk.MsgTypeURL(&group.MsgUpdateGroupPolicyMetadata{})
    35  	TypeMsgSubmitProposal                  = sdk.MsgTypeURL(&group.MsgSubmitProposal{})
    36  	TypeMsgWithdrawProposal                = sdk.MsgTypeURL(&group.MsgWithdrawProposal{})
    37  	TypeMsgVote                            = sdk.MsgTypeURL(&group.MsgVote{})
    38  	TypeMsgExec                            = sdk.MsgTypeURL(&group.MsgExec{})
    39  	TypeMsgLeaveGroup                      = sdk.MsgTypeURL(&group.MsgLeaveGroup{})
    40  )
    41  
    42  // Simulation operation weights constants
    43  const (
    44  	OpMsgCreateGroup                     = "op_weight_msg_create_group"
    45  	OpMsgUpdateGroupAdmin                = "op_weight_msg_update_group_admin"
    46  	OpMsgUpdateGroupMetadata             = "op_wieght_msg_update_group_metadata"
    47  	OpMsgUpdateGroupMembers              = "op_weight_msg_update_group_members"
    48  	OpMsgCreateGroupPolicy               = "op_weight_msg_create_group_account"
    49  	OpMsgCreateGroupWithPolicy           = "op_weight_msg_create_group_with_policy"
    50  	OpMsgUpdateGroupPolicyAdmin          = "op_weight_msg_update_group_account_admin"
    51  	OpMsgUpdateGroupPolicyDecisionPolicy = "op_weight_msg_update_group_account_decision_policy"
    52  	OpMsgUpdateGroupPolicyMetaData       = "op_weight_msg_update_group_account_metadata"
    53  	OpMsgSubmitProposal                  = "op_weight_msg_submit_proposal"
    54  	OpMsgWithdrawProposal                = "op_weight_msg_withdraw_proposal"
    55  	OpMsgVote                            = "op_weight_msg_vote"
    56  	OpMsgExec                            = "ops_weight_msg_exec"
    57  	OpMsgLeaveGroup                      = "ops_weight_msg_leave_group"
    58  )
    59  
    60  // If update group or group policy txn's executed, `SimulateMsgVote` & `SimulateMsgExec` txn's returns `noOp`.
    61  // That's why we have less weight for update group & group-policy txn's.
    62  const (
    63  	WeightMsgCreateGroup                     = 100
    64  	WeightMsgCreateGroupPolicy               = 50
    65  	WeightMsgSubmitProposal                  = 90
    66  	WeightMsgVote                            = 90
    67  	WeightMsgExec                            = 90
    68  	WeightMsgLeaveGroup                      = 5
    69  	WeightMsgUpdateGroupMetadata             = 5
    70  	WeightMsgUpdateGroupAdmin                = 5
    71  	WeightMsgUpdateGroupMembers              = 5
    72  	WeightMsgUpdateGroupPolicyAdmin          = 5
    73  	WeightMsgUpdateGroupPolicyDecisionPolicy = 5
    74  	WeightMsgUpdateGroupPolicyMetadata       = 5
    75  	WeightMsgWithdrawProposal                = 20
    76  	WeightMsgCreateGroupWithPolicy           = 50
    77  )
    78  
    79  // WeightedOperations returns all the operations from the module with their respective weights
    80  func WeightedOperations(
    81  	registry cdctypes.InterfaceRegistry,
    82  	appParams simtypes.AppParams, cdc codec.JSONCodec, txGen client.TxConfig,
    83  	ak group.AccountKeeper, bk group.BankKeeper, k keeper.Keeper,
    84  	appCdc cdctypes.AnyUnpacker,
    85  ) simulation.WeightedOperations {
    86  	var (
    87  		weightMsgCreateGroup                     int
    88  		weightMsgUpdateGroupAdmin                int
    89  		weightMsgUpdateGroupMetadata             int
    90  		weightMsgUpdateGroupMembers              int
    91  		weightMsgCreateGroupPolicy               int
    92  		weightMsgUpdateGroupPolicyAdmin          int
    93  		weightMsgUpdateGroupPolicyDecisionPolicy int
    94  		weightMsgUpdateGroupPolicyMetadata       int
    95  		weightMsgSubmitProposal                  int
    96  		weightMsgVote                            int
    97  		weightMsgExec                            int
    98  		weightMsgLeaveGroup                      int
    99  		weightMsgWithdrawProposal                int
   100  		weightMsgCreateGroupWithPolicy           int
   101  	)
   102  
   103  	appParams.GetOrGenerate(OpMsgCreateGroup, &weightMsgCreateGroup, nil, func(_ *rand.Rand) {
   104  		weightMsgCreateGroup = WeightMsgCreateGroup
   105  	})
   106  	appParams.GetOrGenerate(OpMsgCreateGroupPolicy, &weightMsgCreateGroupPolicy, nil, func(_ *rand.Rand) {
   107  		weightMsgCreateGroupPolicy = WeightMsgCreateGroupPolicy
   108  	})
   109  	appParams.GetOrGenerate(OpMsgLeaveGroup, &weightMsgLeaveGroup, nil, func(_ *rand.Rand) {
   110  		weightMsgLeaveGroup = WeightMsgLeaveGroup
   111  	})
   112  	appParams.GetOrGenerate(OpMsgCreateGroupWithPolicy, &weightMsgCreateGroupWithPolicy, nil, func(_ *rand.Rand) {
   113  		weightMsgCreateGroupWithPolicy = WeightMsgCreateGroupWithPolicy
   114  	})
   115  	appParams.GetOrGenerate(OpMsgSubmitProposal, &weightMsgSubmitProposal, nil, func(_ *rand.Rand) {
   116  		weightMsgSubmitProposal = WeightMsgSubmitProposal
   117  	})
   118  	appParams.GetOrGenerate(OpMsgVote, &weightMsgVote, nil, func(_ *rand.Rand) {
   119  		weightMsgVote = WeightMsgVote
   120  	})
   121  	appParams.GetOrGenerate(OpMsgExec, &weightMsgExec, nil, func(_ *rand.Rand) {
   122  		weightMsgExec = WeightMsgExec
   123  	})
   124  	appParams.GetOrGenerate(OpMsgUpdateGroupMetadata, &weightMsgUpdateGroupMetadata, nil, func(_ *rand.Rand) {
   125  		weightMsgUpdateGroupMetadata = WeightMsgUpdateGroupMetadata
   126  	})
   127  	appParams.GetOrGenerate(OpMsgUpdateGroupAdmin, &weightMsgUpdateGroupAdmin, nil, func(_ *rand.Rand) {
   128  		weightMsgUpdateGroupAdmin = WeightMsgUpdateGroupAdmin
   129  	})
   130  	appParams.GetOrGenerate(OpMsgUpdateGroupMembers, &weightMsgUpdateGroupMembers, nil, func(_ *rand.Rand) {
   131  		weightMsgUpdateGroupMembers = WeightMsgUpdateGroupMembers
   132  	})
   133  	appParams.GetOrGenerate(OpMsgUpdateGroupPolicyAdmin, &weightMsgUpdateGroupPolicyAdmin, nil, func(_ *rand.Rand) {
   134  		weightMsgUpdateGroupPolicyAdmin = WeightMsgUpdateGroupPolicyAdmin
   135  	})
   136  	appParams.GetOrGenerate(OpMsgUpdateGroupPolicyDecisionPolicy, &weightMsgUpdateGroupPolicyDecisionPolicy, nil, func(_ *rand.Rand) {
   137  		weightMsgUpdateGroupPolicyDecisionPolicy = WeightMsgUpdateGroupPolicyDecisionPolicy
   138  	})
   139  	appParams.GetOrGenerate(OpMsgUpdateGroupPolicyMetaData, &weightMsgUpdateGroupPolicyMetadata, nil, func(_ *rand.Rand) {
   140  		weightMsgUpdateGroupPolicyMetadata = WeightMsgUpdateGroupPolicyMetadata
   141  	})
   142  	appParams.GetOrGenerate(OpMsgWithdrawProposal, &weightMsgWithdrawProposal, nil, func(_ *rand.Rand) {
   143  		weightMsgWithdrawProposal = WeightMsgWithdrawProposal
   144  	})
   145  
   146  	pCdc := codec.NewProtoCodec(registry)
   147  
   148  	// create two proposals for weightedOperations
   149  	var createProposalOps simulation.WeightedOperations
   150  	for i := 0; i < 2; i++ {
   151  		createProposalOps = append(createProposalOps, simulation.NewWeightedOperation(
   152  			weightMsgSubmitProposal,
   153  			SimulateMsgSubmitProposal(pCdc, txGen, ak, bk, k),
   154  		))
   155  	}
   156  
   157  	wPreCreateProposalOps := simulation.WeightedOperations{
   158  		simulation.NewWeightedOperation(
   159  			weightMsgCreateGroup,
   160  			SimulateMsgCreateGroup(pCdc, txGen, ak, bk),
   161  		),
   162  		simulation.NewWeightedOperation(
   163  			weightMsgCreateGroupPolicy,
   164  			SimulateMsgCreateGroupPolicy(pCdc, txGen, ak, bk, k),
   165  		),
   166  		simulation.NewWeightedOperation(
   167  			weightMsgCreateGroupWithPolicy,
   168  			SimulateMsgCreateGroupWithPolicy(pCdc, txGen, ak, bk),
   169  		),
   170  	}
   171  
   172  	wPostCreateProposalOps := simulation.WeightedOperations{
   173  		simulation.NewWeightedOperation(
   174  			WeightMsgWithdrawProposal,
   175  			SimulateMsgWithdrawProposal(pCdc, txGen, ak, bk, k),
   176  		),
   177  		simulation.NewWeightedOperation(
   178  			weightMsgVote,
   179  			SimulateMsgVote(pCdc, txGen, ak, bk, k),
   180  		),
   181  		simulation.NewWeightedOperation(
   182  			weightMsgExec,
   183  			SimulateMsgExec(pCdc, txGen, ak, bk, k),
   184  		),
   185  		simulation.NewWeightedOperation(
   186  			weightMsgUpdateGroupMetadata,
   187  			SimulateMsgUpdateGroupMetadata(pCdc, txGen, ak, bk, k),
   188  		),
   189  		simulation.NewWeightedOperation(
   190  			weightMsgUpdateGroupAdmin,
   191  			SimulateMsgUpdateGroupAdmin(pCdc, txGen, ak, bk, k),
   192  		),
   193  		simulation.NewWeightedOperation(
   194  			weightMsgUpdateGroupMembers,
   195  			SimulateMsgUpdateGroupMembers(pCdc, txGen, ak, bk, k),
   196  		),
   197  		simulation.NewWeightedOperation(
   198  			weightMsgUpdateGroupPolicyAdmin,
   199  			SimulateMsgUpdateGroupPolicyAdmin(pCdc, txGen, ak, bk, k),
   200  		),
   201  		simulation.NewWeightedOperation(
   202  			weightMsgUpdateGroupPolicyDecisionPolicy,
   203  			SimulateMsgUpdateGroupPolicyDecisionPolicy(pCdc, txGen, ak, bk, k),
   204  		),
   205  		simulation.NewWeightedOperation(
   206  			weightMsgUpdateGroupPolicyMetadata,
   207  			SimulateMsgUpdateGroupPolicyMetadata(pCdc, txGen, ak, bk, k),
   208  		),
   209  		simulation.NewWeightedOperation(
   210  			weightMsgLeaveGroup,
   211  			SimulateMsgLeaveGroup(pCdc, txGen, k, ak, bk),
   212  		),
   213  	}
   214  
   215  	return append(wPreCreateProposalOps, append(createProposalOps, wPostCreateProposalOps...)...)
   216  }
   217  
   218  // SimulateMsgCreateGroup generates a MsgCreateGroup with random values
   219  func SimulateMsgCreateGroup(
   220  	cdc *codec.ProtoCodec,
   221  	txGen client.TxConfig,
   222  	ak group.AccountKeeper,
   223  	bk group.BankKeeper,
   224  ) simtypes.Operation {
   225  	return func(
   226  		r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accounts []simtypes.Account, chainID string,
   227  	) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
   228  		acc, _ := simtypes.RandomAcc(r, accounts)
   229  		account := ak.GetAccount(ctx, acc.Address)
   230  		accAddr := acc.Address.String()
   231  
   232  		spendableCoins := bk.SpendableCoins(ctx, account.GetAddress())
   233  		fees, err := simtypes.RandomFees(r, ctx, spendableCoins)
   234  		if err != nil {
   235  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgCreateGroup, "fee error"), nil, err
   236  		}
   237  
   238  		members := genGroupMembers(r, accounts)
   239  		msg := &group.MsgCreateGroup{Admin: accAddr, Members: members, Metadata: simtypes.RandStringOfLength(r, 10)}
   240  
   241  		tx, err := simtestutil.GenSignedMockTx(
   242  			r,
   243  			txGen,
   244  			[]sdk.Msg{msg},
   245  			fees,
   246  			simtestutil.DefaultGenTxGas,
   247  			chainID,
   248  			[]uint64{account.GetAccountNumber()},
   249  			[]uint64{account.GetSequence()},
   250  			acc.PrivKey,
   251  		)
   252  		if err != nil {
   253  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgCreateGroup, "unable to generate mock tx"), nil, err
   254  		}
   255  
   256  		_, _, err = app.SimDeliver(txGen.TxEncoder(), tx)
   257  		if err != nil {
   258  			return simtypes.NoOpMsg(group.ModuleName, sdk.MsgTypeURL(msg), "unable to deliver tx"), nil, err
   259  		}
   260  
   261  		return simtypes.NewOperationMsg(msg, true, ""), nil, err
   262  	}
   263  }
   264  
   265  // SimulateMsgCreateGroupWithPolicy generates a MsgCreateGroupWithPolicy with random values
   266  func SimulateMsgCreateGroupWithPolicy(
   267  	cdc *codec.ProtoCodec,
   268  	txGen client.TxConfig,
   269  	ak group.AccountKeeper,
   270  	bk group.BankKeeper,
   271  ) simtypes.Operation {
   272  	return func(
   273  		r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accounts []simtypes.Account, chainID string,
   274  	) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
   275  		acc, _ := simtypes.RandomAcc(r, accounts)
   276  		account := ak.GetAccount(ctx, acc.Address)
   277  		accAddr := acc.Address.String()
   278  
   279  		spendableCoins := bk.SpendableCoins(ctx, account.GetAddress())
   280  		fees, err := simtypes.RandomFees(r, ctx, spendableCoins)
   281  		if err != nil {
   282  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgCreateGroup, "fee error"), nil, err
   283  		}
   284  
   285  		members := genGroupMembers(r, accounts)
   286  		decisionPolicy := &group.ThresholdDecisionPolicy{
   287  			Threshold: fmt.Sprintf("%d", simtypes.RandIntBetween(r, 1, 10)),
   288  			Windows: &group.DecisionPolicyWindows{
   289  				VotingPeriod: time.Second * time.Duration(30*24*60*60),
   290  			},
   291  		}
   292  
   293  		msg := &group.MsgCreateGroupWithPolicy{
   294  			Admin:               accAddr,
   295  			Members:             members,
   296  			GroupMetadata:       simtypes.RandStringOfLength(r, 10),
   297  			GroupPolicyMetadata: simtypes.RandStringOfLength(r, 10),
   298  			GroupPolicyAsAdmin:  r.Float32() < 0.5,
   299  		}
   300  		msg.SetDecisionPolicy(decisionPolicy)
   301  		if err != nil {
   302  			return simtypes.NoOpMsg(group.ModuleName, sdk.MsgTypeURL(msg), "unable to set decision policy"), nil, err
   303  		}
   304  
   305  		tx, err := simtestutil.GenSignedMockTx(
   306  			r,
   307  			txGen,
   308  			[]sdk.Msg{msg},
   309  			fees,
   310  			simtestutil.DefaultGenTxGas,
   311  			chainID,
   312  			[]uint64{account.GetAccountNumber()},
   313  			[]uint64{account.GetSequence()},
   314  			acc.PrivKey,
   315  		)
   316  		if err != nil {
   317  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgCreateGroupWithPolicy, "unable to generate mock tx"), nil, err
   318  		}
   319  
   320  		_, _, err = app.SimDeliver(txGen.TxEncoder(), tx)
   321  		if err != nil {
   322  			return simtypes.NoOpMsg(group.ModuleName, sdk.MsgTypeURL(msg), "unable to deliver tx"), nil, err
   323  		}
   324  
   325  		return simtypes.NewOperationMsg(msg, true, ""), nil, nil
   326  	}
   327  }
   328  
   329  // SimulateMsgCreateGroupPolicy generates a NewMsgCreateGroupPolicy with random values
   330  func SimulateMsgCreateGroupPolicy(
   331  	cdc *codec.ProtoCodec,
   332  	txGen client.TxConfig,
   333  	ak group.AccountKeeper,
   334  	bk group.BankKeeper,
   335  	k keeper.Keeper,
   336  ) simtypes.Operation {
   337  	return func(
   338  		r *rand.Rand, app *baseapp.BaseApp, sdkCtx sdk.Context, accounts []simtypes.Account, chainID string,
   339  	) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
   340  		groupInfo, acc, account, err := randomGroup(r, k, ak, sdkCtx, accounts)
   341  		if err != nil {
   342  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgCreateGroupPolicy, ""), nil, err
   343  		}
   344  		if groupInfo == nil {
   345  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgCreateGroupPolicy, ""), nil, nil
   346  		}
   347  		groupID := groupInfo.Id
   348  
   349  		spendableCoins := bk.SpendableCoins(sdkCtx, account.GetAddress())
   350  		fees, err := simtypes.RandomFees(r, sdkCtx, spendableCoins)
   351  		if err != nil {
   352  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgCreateGroupPolicy, "fee error"), nil, err
   353  		}
   354  
   355  		msg, err := group.NewMsgCreateGroupPolicy(
   356  			acc.Address,
   357  			groupID,
   358  			simtypes.RandStringOfLength(r, 10),
   359  			&group.ThresholdDecisionPolicy{
   360  				Threshold: fmt.Sprintf("%d", simtypes.RandIntBetween(r, 1, 10)),
   361  				Windows: &group.DecisionPolicyWindows{
   362  					VotingPeriod: time.Second * time.Duration(30*24*60*60),
   363  				},
   364  			},
   365  		)
   366  		if err != nil {
   367  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgCreateGroupPolicy, err.Error()), nil, err
   368  		}
   369  
   370  		tx, err := simtestutil.GenSignedMockTx(
   371  			r,
   372  			txGen,
   373  			[]sdk.Msg{msg},
   374  			fees,
   375  			simtestutil.DefaultGenTxGas,
   376  			chainID,
   377  			[]uint64{account.GetAccountNumber()},
   378  			[]uint64{account.GetSequence()},
   379  			acc.PrivKey,
   380  		)
   381  		if err != nil {
   382  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgCreateGroupPolicy, "unable to generate mock tx"), nil, err
   383  		}
   384  
   385  		_, _, err = app.SimDeliver(txGen.TxEncoder(), tx)
   386  		if err != nil {
   387  			fmt.Printf("ERR DELIVER %v\n", err)
   388  			return simtypes.NoOpMsg(group.ModuleName, sdk.MsgTypeURL(msg), "unable to deliver tx"), nil, err
   389  		}
   390  
   391  		return simtypes.NewOperationMsg(msg, true, ""), nil, err
   392  	}
   393  }
   394  
   395  // SimulateMsgSubmitProposal generates a NewMsgSubmitProposal with random values
   396  func SimulateMsgSubmitProposal(
   397  	cdc *codec.ProtoCodec,
   398  	txGen client.TxConfig,
   399  	ak group.AccountKeeper,
   400  	bk group.BankKeeper,
   401  	k keeper.Keeper,
   402  ) simtypes.Operation {
   403  	return func(
   404  		r *rand.Rand, app *baseapp.BaseApp, sdkCtx sdk.Context, accounts []simtypes.Account, chainID string,
   405  	) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
   406  		g, groupPolicy, _, _, err := randomGroupPolicy(r, k, ak, sdkCtx, accounts)
   407  		if err != nil {
   408  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgSubmitProposal, ""), nil, err
   409  		}
   410  		if g == nil {
   411  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgSubmitProposal, "no group found"), nil, nil
   412  		}
   413  		if groupPolicy == nil {
   414  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgSubmitProposal, "no group policy found"), nil, nil
   415  		}
   416  		groupID := g.Id
   417  		groupPolicyAddr := groupPolicy.Address
   418  
   419  		// Return a no-op if we know the proposal cannot be created
   420  		policy, err := groupPolicy.GetDecisionPolicy()
   421  		if err != nil {
   422  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgSubmitProposal, ""), nil, nil
   423  		}
   424  		err = policy.Validate(*g, group.DefaultConfig())
   425  		if err != nil {
   426  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgSubmitProposal, ""), nil, nil
   427  		}
   428  
   429  		// Pick a random member from the group
   430  		acc, account, err := randomMember(sdkCtx, r, k, ak, accounts, groupID)
   431  		if err != nil {
   432  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgSubmitProposal, ""), nil, err
   433  		}
   434  		if account == nil {
   435  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgSubmitProposal, "no group member found"), nil, nil
   436  		}
   437  
   438  		spendableCoins := bk.SpendableCoins(sdkCtx, account.GetAddress())
   439  		fees, err := simtypes.RandomFees(r, sdkCtx, spendableCoins)
   440  		if err != nil {
   441  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgSubmitProposal, "fee error"), nil, err
   442  		}
   443  
   444  		msg := &group.MsgSubmitProposal{
   445  			GroupPolicyAddress: groupPolicyAddr,
   446  			Proposers:          []string{acc.Address.String()},
   447  			Metadata:           simtypes.RandStringOfLength(r, 10),
   448  			Title:              "Test Proposal",
   449  			Summary:            "Summary of the proposal",
   450  		}
   451  
   452  		tx, err := simtestutil.GenSignedMockTx(
   453  			r,
   454  			txGen,
   455  			[]sdk.Msg{msg},
   456  			fees,
   457  			simtestutil.DefaultGenTxGas,
   458  			chainID,
   459  			[]uint64{account.GetAccountNumber()},
   460  			[]uint64{account.GetSequence()},
   461  			acc.PrivKey,
   462  		)
   463  		if err != nil {
   464  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgSubmitProposal, "unable to generate mock tx"), nil, err
   465  		}
   466  
   467  		_, _, err = app.SimDeliver(txGen.TxEncoder(), tx)
   468  		if err != nil {
   469  			return simtypes.NoOpMsg(group.ModuleName, sdk.MsgTypeURL(msg), "unable to deliver tx"), nil, err
   470  		}
   471  
   472  		return simtypes.NewOperationMsg(msg, true, ""), nil, err
   473  	}
   474  }
   475  
   476  // SimulateMsgUpdateGroupAdmin generates a MsgUpdateGroupAdmin with random values
   477  func SimulateMsgUpdateGroupAdmin(
   478  	cdc *codec.ProtoCodec,
   479  	txGen client.TxConfig,
   480  	ak group.AccountKeeper,
   481  	bk group.BankKeeper,
   482  	k keeper.Keeper,
   483  ) simtypes.Operation {
   484  	return func(
   485  		r *rand.Rand, app *baseapp.BaseApp, sdkCtx sdk.Context, accounts []simtypes.Account, chainID string,
   486  	) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
   487  		groupInfo, acc, account, err := randomGroup(r, k, ak, sdkCtx, accounts)
   488  		if err != nil {
   489  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupAdmin, ""), nil, err
   490  		}
   491  		if groupInfo == nil {
   492  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupAdmin, ""), nil, nil
   493  		}
   494  		groupID := groupInfo.Id
   495  
   496  		spendableCoins := bk.SpendableCoins(sdkCtx, account.GetAddress())
   497  		fees, err := simtypes.RandomFees(r, sdkCtx, spendableCoins)
   498  		if err != nil {
   499  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupAdmin, "fee error"), nil, err
   500  		}
   501  
   502  		if len(accounts) == 1 {
   503  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupAdmin, "can't set a new admin with only one account"), nil, nil
   504  		}
   505  		newAdmin, _ := simtypes.RandomAcc(r, accounts)
   506  		// disallow setting current admin as new admin
   507  		for acc.PubKey.Equals(newAdmin.PubKey) {
   508  			newAdmin, _ = simtypes.RandomAcc(r, accounts)
   509  		}
   510  
   511  		msg := &group.MsgUpdateGroupAdmin{
   512  			GroupId:  groupID,
   513  			Admin:    account.GetAddress().String(),
   514  			NewAdmin: newAdmin.Address.String(),
   515  		}
   516  
   517  		tx, err := simtestutil.GenSignedMockTx(
   518  			r,
   519  			txGen,
   520  			[]sdk.Msg{msg},
   521  			fees,
   522  			simtestutil.DefaultGenTxGas,
   523  			chainID,
   524  			[]uint64{account.GetAccountNumber()},
   525  			[]uint64{account.GetSequence()},
   526  			acc.PrivKey,
   527  		)
   528  		if err != nil {
   529  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupAdmin, "unable to generate mock tx"), nil, err
   530  		}
   531  
   532  		_, _, err = app.SimDeliver(txGen.TxEncoder(), tx)
   533  		if err != nil {
   534  			return simtypes.NoOpMsg(group.ModuleName, sdk.MsgTypeURL(msg), "unable to deliver tx"), nil, err
   535  		}
   536  
   537  		return simtypes.NewOperationMsg(msg, true, ""), nil, err
   538  	}
   539  }
   540  
   541  // SimulateMsgUpdateGroupMetadata generates a MsgUpdateGroupMetadata with random values
   542  func SimulateMsgUpdateGroupMetadata(
   543  	cdc *codec.ProtoCodec,
   544  	txGen client.TxConfig,
   545  	ak group.AccountKeeper,
   546  	bk group.BankKeeper,
   547  	k keeper.Keeper,
   548  ) simtypes.Operation {
   549  	return func(
   550  		r *rand.Rand, app *baseapp.BaseApp, sdkCtx sdk.Context, accounts []simtypes.Account, chainID string,
   551  	) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
   552  		groupInfo, acc, account, err := randomGroup(r, k, ak, sdkCtx, accounts)
   553  		if err != nil {
   554  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupMetadata, ""), nil, err
   555  		}
   556  		if groupInfo == nil {
   557  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupMetadata, ""), nil, nil
   558  		}
   559  		groupID := groupInfo.Id
   560  
   561  		spendableCoins := bk.SpendableCoins(sdkCtx, account.GetAddress())
   562  		fees, err := simtypes.RandomFees(r, sdkCtx, spendableCoins)
   563  		if err != nil {
   564  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupMetadata, "fee error"), nil, err
   565  		}
   566  
   567  		msg := &group.MsgUpdateGroupMetadata{
   568  			GroupId:  groupID,
   569  			Admin:    account.GetAddress().String(),
   570  			Metadata: simtypes.RandStringOfLength(r, 10),
   571  		}
   572  
   573  		tx, err := simtestutil.GenSignedMockTx(
   574  			r,
   575  			txGen,
   576  			[]sdk.Msg{msg},
   577  			fees,
   578  			simtestutil.DefaultGenTxGas,
   579  			chainID,
   580  			[]uint64{account.GetAccountNumber()},
   581  			[]uint64{account.GetSequence()},
   582  			acc.PrivKey,
   583  		)
   584  		if err != nil {
   585  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupMetadata, "unable to generate mock tx"), nil, err
   586  		}
   587  
   588  		_, _, err = app.SimDeliver(txGen.TxEncoder(), tx)
   589  		if err != nil {
   590  			return simtypes.NoOpMsg(group.ModuleName, sdk.MsgTypeURL(msg), "unable to deliver tx"), nil, err
   591  		}
   592  
   593  		return simtypes.NewOperationMsg(msg, true, ""), nil, err
   594  	}
   595  }
   596  
   597  // SimulateMsgUpdateGroupMembers generates a MsgUpdateGroupMembers with random values
   598  func SimulateMsgUpdateGroupMembers(
   599  	cdc *codec.ProtoCodec,
   600  	txGen client.TxConfig,
   601  	ak group.AccountKeeper,
   602  	bk group.BankKeeper,
   603  	k keeper.Keeper,
   604  ) simtypes.Operation {
   605  	return func(
   606  		r *rand.Rand, app *baseapp.BaseApp, sdkCtx sdk.Context, accounts []simtypes.Account, chainID string,
   607  	) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
   608  		groupInfo, acc, account, err := randomGroup(r, k, ak, sdkCtx, accounts)
   609  		if err != nil {
   610  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupMembers, ""), nil, err
   611  		}
   612  		if groupInfo == nil {
   613  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupMembers, ""), nil, nil
   614  		}
   615  		groupID := groupInfo.Id
   616  
   617  		spendableCoins := bk.SpendableCoins(sdkCtx, account.GetAddress())
   618  		fees, err := simtypes.RandomFees(r, sdkCtx, spendableCoins)
   619  		if err != nil {
   620  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupMembers, "fee error"), nil, err
   621  		}
   622  
   623  		members := genGroupMembers(r, accounts)
   624  		ctx := sdk.UnwrapSDKContext(sdkCtx)
   625  		res, err := k.GroupMembers(ctx, &group.QueryGroupMembersRequest{GroupId: groupID})
   626  		if err != nil {
   627  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupMembers, "group members"), nil, err
   628  		}
   629  
   630  		// set existing random group member weight to zero to remove from the group
   631  		existigMembers := res.Members
   632  		if len(existigMembers) > 0 {
   633  			memberToRemove := existigMembers[r.Intn(len(existigMembers))]
   634  			var isDuplicateMember bool
   635  			for idx, m := range members {
   636  				if m.Address == memberToRemove.Member.Address {
   637  					members[idx].Weight = "0"
   638  					isDuplicateMember = true
   639  					break
   640  				}
   641  			}
   642  
   643  			if !isDuplicateMember {
   644  				m := memberToRemove.Member
   645  				m.Weight = "0"
   646  				members = append(members, group.MemberToMemberRequest(m))
   647  			}
   648  		}
   649  
   650  		msg := &group.MsgUpdateGroupMembers{
   651  			GroupId:       groupID,
   652  			Admin:         acc.Address.String(),
   653  			MemberUpdates: members,
   654  		}
   655  
   656  		tx, err := simtestutil.GenSignedMockTx(
   657  			r,
   658  			txGen,
   659  			[]sdk.Msg{msg},
   660  			fees,
   661  			simtestutil.DefaultGenTxGas,
   662  			chainID,
   663  			[]uint64{account.GetAccountNumber()},
   664  			[]uint64{account.GetSequence()},
   665  			acc.PrivKey,
   666  		)
   667  		if err != nil {
   668  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupMembers, "unable to generate mock tx"), nil, err
   669  		}
   670  
   671  		_, _, err = app.SimDeliver(txGen.TxEncoder(), tx)
   672  		if err != nil {
   673  			return simtypes.NoOpMsg(group.ModuleName, sdk.MsgTypeURL(msg), "unable to deliver tx"), nil, err
   674  		}
   675  
   676  		return simtypes.NewOperationMsg(msg, true, ""), nil, err
   677  	}
   678  }
   679  
   680  // SimulateMsgUpdateGroupPolicyAdmin generates a MsgUpdateGroupPolicyAdmin with random values
   681  func SimulateMsgUpdateGroupPolicyAdmin(
   682  	cdc *codec.ProtoCodec,
   683  	txGen client.TxConfig,
   684  	ak group.AccountKeeper,
   685  	bk group.BankKeeper,
   686  	k keeper.Keeper,
   687  ) simtypes.Operation {
   688  	return func(
   689  		r *rand.Rand, app *baseapp.BaseApp, sdkCtx sdk.Context, accounts []simtypes.Account, chainID string,
   690  	) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
   691  		_, groupPolicy, acc, account, err := randomGroupPolicy(r, k, ak, sdkCtx, accounts)
   692  		if err != nil {
   693  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupPolicyAdmin, ""), nil, err
   694  		}
   695  		if groupPolicy == nil {
   696  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupPolicyAdmin, "no group policy found"), nil, nil
   697  		}
   698  		groupPolicyAddr := groupPolicy.Address
   699  
   700  		spendableCoins := bk.SpendableCoins(sdkCtx, account.GetAddress())
   701  		fees, err := simtypes.RandomFees(r, sdkCtx, spendableCoins)
   702  		if err != nil {
   703  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupPolicyAdmin, "fee error"), nil, err
   704  		}
   705  
   706  		if len(accounts) == 1 {
   707  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupPolicyAdmin, "can't set a new admin with only one account"), nil, nil
   708  		}
   709  		newAdmin, _ := simtypes.RandomAcc(r, accounts)
   710  		// disallow setting current admin as new admin
   711  		for acc.PubKey.Equals(newAdmin.PubKey) {
   712  			newAdmin, _ = simtypes.RandomAcc(r, accounts)
   713  		}
   714  
   715  		msg := &group.MsgUpdateGroupPolicyAdmin{
   716  			Admin:              acc.Address.String(),
   717  			GroupPolicyAddress: groupPolicyAddr,
   718  			NewAdmin:           newAdmin.Address.String(),
   719  		}
   720  
   721  		tx, err := simtestutil.GenSignedMockTx(
   722  			r,
   723  			txGen,
   724  			[]sdk.Msg{msg},
   725  			fees,
   726  			simtestutil.DefaultGenTxGas,
   727  			chainID,
   728  			[]uint64{account.GetAccountNumber()},
   729  			[]uint64{account.GetSequence()},
   730  			acc.PrivKey,
   731  		)
   732  		if err != nil {
   733  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupPolicyAdmin, "unable to generate mock tx"), nil, err
   734  		}
   735  
   736  		_, _, err = app.SimDeliver(txGen.TxEncoder(), tx)
   737  		if err != nil {
   738  			return simtypes.NoOpMsg(group.ModuleName, sdk.MsgTypeURL(msg), "unable to deliver tx"), nil, err
   739  		}
   740  
   741  		return simtypes.NewOperationMsg(msg, true, ""), nil, err
   742  	}
   743  }
   744  
   745  // // SimulateMsgUpdateGroupPolicyDecisionPolicy generates a NewMsgUpdateGroupPolicyDecisionPolicy with random values
   746  func SimulateMsgUpdateGroupPolicyDecisionPolicy(
   747  	cdc *codec.ProtoCodec,
   748  	txGen client.TxConfig,
   749  	ak group.AccountKeeper,
   750  	bk group.BankKeeper,
   751  	k keeper.Keeper,
   752  ) simtypes.Operation {
   753  	return func(
   754  		r *rand.Rand, app *baseapp.BaseApp, sdkCtx sdk.Context, accounts []simtypes.Account, chainID string,
   755  	) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
   756  		_, groupPolicy, acc, account, err := randomGroupPolicy(r, k, ak, sdkCtx, accounts)
   757  		if err != nil {
   758  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupPolicyDecisionPolicy, ""), nil, err
   759  		}
   760  		if groupPolicy == nil {
   761  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupPolicyDecisionPolicy, "no group policy found"), nil, nil
   762  		}
   763  		groupPolicyAddr := groupPolicy.Address
   764  
   765  		spendableCoins := bk.SpendableCoins(sdkCtx, account.GetAddress())
   766  		fees, err := simtypes.RandomFees(r, sdkCtx, spendableCoins)
   767  		if err != nil {
   768  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupPolicyDecisionPolicy, "fee error"), nil, err
   769  		}
   770  
   771  		groupPolicyBech32, err := sdk.AccAddressFromBech32(groupPolicyAddr)
   772  		if err != nil {
   773  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupPolicyDecisionPolicy, fmt.Sprintf("fail to decide bech32 address: %s", err.Error())), nil, nil
   774  		}
   775  
   776  		msg, err := group.NewMsgUpdateGroupPolicyDecisionPolicy(acc.Address, groupPolicyBech32, &group.ThresholdDecisionPolicy{
   777  			Threshold: fmt.Sprintf("%d", simtypes.RandIntBetween(r, 1, 10)),
   778  			Windows: &group.DecisionPolicyWindows{
   779  				VotingPeriod: time.Second * time.Duration(simtypes.RandIntBetween(r, 100, 1000)),
   780  			},
   781  		})
   782  		if err != nil {
   783  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupPolicyDecisionPolicy, err.Error()), nil, err
   784  		}
   785  
   786  		tx, err := simtestutil.GenSignedMockTx(
   787  			r,
   788  			txGen,
   789  			[]sdk.Msg{msg},
   790  			fees,
   791  			simtestutil.DefaultGenTxGas,
   792  			chainID,
   793  			[]uint64{account.GetAccountNumber()},
   794  			[]uint64{account.GetSequence()},
   795  			acc.PrivKey,
   796  		)
   797  		if err != nil {
   798  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupPolicyDecisionPolicy, "unable to generate mock tx"), nil, err
   799  		}
   800  
   801  		_, _, err = app.SimDeliver(txGen.TxEncoder(), tx)
   802  		if err != nil {
   803  			return simtypes.NoOpMsg(group.ModuleName, sdk.MsgTypeURL(msg), "unable to deliver tx"), nil, err
   804  		}
   805  		return simtypes.NewOperationMsg(msg, true, ""), nil, err
   806  	}
   807  }
   808  
   809  // // SimulateMsgUpdateGroupPolicyMetadata generates a MsgUpdateGroupPolicyMetadata with random values
   810  func SimulateMsgUpdateGroupPolicyMetadata(
   811  	cdc *codec.ProtoCodec,
   812  	txGen client.TxConfig,
   813  	ak group.AccountKeeper,
   814  	bk group.BankKeeper,
   815  	k keeper.Keeper,
   816  ) simtypes.Operation {
   817  	return func(
   818  		r *rand.Rand, app *baseapp.BaseApp, sdkCtx sdk.Context, accounts []simtypes.Account, chainID string,
   819  	) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
   820  		_, groupPolicy, acc, account, err := randomGroupPolicy(r, k, ak, sdkCtx, accounts)
   821  		if err != nil {
   822  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupPolicyMetadata, ""), nil, err
   823  		}
   824  		if groupPolicy == nil {
   825  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupPolicyMetadata, "no group policy found"), nil, nil
   826  		}
   827  		groupPolicyAddr := groupPolicy.Address
   828  
   829  		spendableCoins := bk.SpendableCoins(sdkCtx, account.GetAddress())
   830  		fees, err := simtypes.RandomFees(r, sdkCtx, spendableCoins)
   831  		if err != nil {
   832  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupPolicyMetadata, "fee error"), nil, err
   833  		}
   834  
   835  		msg := &group.MsgUpdateGroupPolicyMetadata{
   836  			Admin:              acc.Address.String(),
   837  			GroupPolicyAddress: groupPolicyAddr,
   838  			Metadata:           simtypes.RandStringOfLength(r, 10),
   839  		}
   840  
   841  		tx, err := simtestutil.GenSignedMockTx(
   842  			r,
   843  			txGen,
   844  			[]sdk.Msg{msg},
   845  			fees,
   846  			simtestutil.DefaultGenTxGas,
   847  			chainID,
   848  			[]uint64{account.GetAccountNumber()},
   849  			[]uint64{account.GetSequence()},
   850  			acc.PrivKey,
   851  		)
   852  		if err != nil {
   853  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupPolicyMetadata, "unable to generate mock tx"), nil, err
   854  		}
   855  
   856  		_, _, err = app.SimDeliver(txGen.TxEncoder(), tx)
   857  		if err != nil {
   858  			return simtypes.NoOpMsg(group.ModuleName, sdk.MsgTypeURL(msg), "unable to deliver tx"), nil, err
   859  		}
   860  
   861  		return simtypes.NewOperationMsg(msg, true, ""), nil, err
   862  	}
   863  }
   864  
   865  // SimulateMsgWithdrawProposal generates a MsgWithdrawProposal with random values
   866  func SimulateMsgWithdrawProposal(
   867  	cdc *codec.ProtoCodec,
   868  	txGen client.TxConfig,
   869  	ak group.AccountKeeper,
   870  	bk group.BankKeeper,
   871  	k keeper.Keeper,
   872  ) simtypes.Operation {
   873  	return func(
   874  		r *rand.Rand, app *baseapp.BaseApp, sdkCtx sdk.Context, accounts []simtypes.Account, chainID string,
   875  	) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
   876  		g, groupPolicy, _, _, err := randomGroupPolicy(r, k, ak, sdkCtx, accounts)
   877  		if err != nil {
   878  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgWithdrawProposal, ""), nil, err
   879  		}
   880  		if g == nil {
   881  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgWithdrawProposal, "no group found"), nil, nil
   882  		}
   883  		if groupPolicy == nil {
   884  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgWithdrawProposal, "no group policy found"), nil, nil
   885  		}
   886  
   887  		groupPolicyAddr := groupPolicy.Address
   888  		policy, err := groupPolicy.GetDecisionPolicy()
   889  		if err != nil {
   890  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgWithdrawProposal, err.Error()), nil, nil
   891  		}
   892  		err = policy.Validate(*g, group.DefaultConfig())
   893  		if err != nil {
   894  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgWithdrawProposal, err.Error()), nil, nil
   895  		}
   896  
   897  		proposalsResult, err := k.ProposalsByGroupPolicy(sdkCtx, &group.QueryProposalsByGroupPolicyRequest{Address: groupPolicyAddr})
   898  		if err != nil {
   899  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgWithdrawProposal, "fail to query group info"), nil, err
   900  		}
   901  
   902  		proposals := proposalsResult.GetProposals()
   903  		if len(proposals) == 0 {
   904  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgWithdrawProposal, "no proposals found"), nil, nil
   905  		}
   906  
   907  		var proposal *group.Proposal
   908  		proposalID := -1
   909  
   910  		for _, p := range proposals {
   911  			if p.Status == group.PROPOSAL_STATUS_SUBMITTED {
   912  				timeout := p.VotingPeriodEnd
   913  				proposal = p
   914  				proposalID = int(p.Id)
   915  				if timeout.Before(sdkCtx.BlockTime()) || timeout.Equal(sdkCtx.BlockTime()) {
   916  					return simtypes.NoOpMsg(group.ModuleName, TypeMsgWithdrawProposal, "voting period ended: skipping"), nil, nil
   917  				}
   918  				break
   919  			}
   920  		}
   921  
   922  		// return no-op if no proposal found
   923  		if proposalID == -1 {
   924  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgWithdrawProposal, "no proposals found"), nil, nil
   925  		}
   926  
   927  		// select a random proposer
   928  		proposers := proposal.Proposers
   929  		n := randIntInRange(r, len(proposers))
   930  		proposerIdx := findAccount(accounts, proposers[n])
   931  		proposer := accounts[proposerIdx]
   932  		proposerAcc := ak.GetAccount(sdkCtx, proposer.Address)
   933  
   934  		spendableCoins := bk.SpendableCoins(sdkCtx, proposer.Address)
   935  		fees, err := simtypes.RandomFees(r, sdkCtx, spendableCoins)
   936  		if err != nil {
   937  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgWithdrawProposal, "fee error"), nil, err
   938  		}
   939  
   940  		msg := &group.MsgWithdrawProposal{
   941  			ProposalId: uint64(proposalID),
   942  			Address:    proposer.Address.String(),
   943  		}
   944  
   945  		tx, err := simtestutil.GenSignedMockTx(
   946  			r,
   947  			txGen,
   948  			[]sdk.Msg{msg},
   949  			fees,
   950  			simtestutil.DefaultGenTxGas,
   951  			chainID,
   952  			[]uint64{proposerAcc.GetAccountNumber()},
   953  			[]uint64{proposerAcc.GetSequence()},
   954  			proposer.PrivKey,
   955  		)
   956  		if err != nil {
   957  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupPolicyMetadata, "unable to generate mock tx"), nil, err
   958  		}
   959  
   960  		_, _, err = app.SimDeliver(txGen.TxEncoder(), tx)
   961  
   962  		if err != nil {
   963  			if strings.Contains(err.Error(), "group was modified") || strings.Contains(err.Error(), "group policy was modified") {
   964  				return simtypes.NoOpMsg(group.ModuleName, sdk.MsgTypeURL(msg), "no-op:group/group-policy was modified"), nil, nil
   965  			}
   966  			return simtypes.NoOpMsg(group.ModuleName, sdk.MsgTypeURL(msg), "unable to deliver tx"), nil, err
   967  		}
   968  
   969  		return simtypes.NewOperationMsg(msg, true, ""), nil, err
   970  	}
   971  }
   972  
   973  // SimulateMsgVote generates a MsgVote with random values
   974  func SimulateMsgVote(
   975  	cdc *codec.ProtoCodec,
   976  	txGen client.TxConfig,
   977  	ak group.AccountKeeper,
   978  	bk group.BankKeeper,
   979  	k keeper.Keeper,
   980  ) simtypes.Operation {
   981  	return func(
   982  		r *rand.Rand, app *baseapp.BaseApp, sdkCtx sdk.Context, accounts []simtypes.Account, chainID string,
   983  	) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
   984  		g, groupPolicy, _, _, err := randomGroupPolicy(r, k, ak, sdkCtx, accounts)
   985  		if err != nil {
   986  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgVote, ""), nil, err
   987  		}
   988  		if g == nil {
   989  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgVote, "no group found"), nil, nil
   990  		}
   991  		if groupPolicy == nil {
   992  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgVote, "no group policy found"), nil, nil
   993  		}
   994  		groupPolicyAddr := groupPolicy.Address
   995  
   996  		// Pick a random member from the group
   997  		acc, account, err := randomMember(sdkCtx, r, k, ak, accounts, g.Id)
   998  		if err != nil {
   999  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgVote, ""), nil, err
  1000  		}
  1001  		if account == nil {
  1002  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgVote, "no group member found"), nil, nil
  1003  		}
  1004  
  1005  		spendableCoins := bk.SpendableCoins(sdkCtx, account.GetAddress())
  1006  		fees, err := simtypes.RandomFees(r, sdkCtx, spendableCoins)
  1007  		if err != nil {
  1008  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgVote, "fee error"), nil, err
  1009  		}
  1010  
  1011  		proposalsResult, err := k.ProposalsByGroupPolicy(sdkCtx, &group.QueryProposalsByGroupPolicyRequest{Address: groupPolicyAddr})
  1012  		if err != nil {
  1013  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgVote, "fail to query group info"), nil, err
  1014  		}
  1015  		proposals := proposalsResult.GetProposals()
  1016  		if len(proposals) == 0 {
  1017  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgVote, "no proposals found"), nil, nil
  1018  		}
  1019  
  1020  		proposalID := -1
  1021  
  1022  		for _, p := range proposals {
  1023  			if p.Status == group.PROPOSAL_STATUS_SUBMITTED {
  1024  				timeout := p.VotingPeriodEnd
  1025  				proposalID = int(p.Id)
  1026  				if timeout.Before(sdkCtx.BlockTime()) || timeout.Equal(sdkCtx.BlockTime()) {
  1027  					return simtypes.NoOpMsg(group.ModuleName, TypeMsgVote, "voting period ended: skipping"), nil, nil
  1028  				}
  1029  				break
  1030  			}
  1031  		}
  1032  
  1033  		// return no-op if no proposal found
  1034  		if proposalID == -1 {
  1035  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgVote, "no proposals found"), nil, nil
  1036  		}
  1037  
  1038  		// Ensure member hasn't already voted
  1039  		res, _ := k.VoteByProposalVoter(sdkCtx, &group.QueryVoteByProposalVoterRequest{
  1040  			Voter:      acc.Address.String(),
  1041  			ProposalId: uint64(proposalID),
  1042  		})
  1043  		if res != nil {
  1044  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgVote, "member has already voted"), nil, nil
  1045  		}
  1046  
  1047  		msg := &group.MsgVote{
  1048  			ProposalId: uint64(proposalID),
  1049  			Voter:      acc.Address.String(),
  1050  			Option:     group.VOTE_OPTION_YES,
  1051  			Metadata:   simtypes.RandStringOfLength(r, 10),
  1052  		}
  1053  		tx, err := simtestutil.GenSignedMockTx(
  1054  			r,
  1055  			txGen,
  1056  			[]sdk.Msg{msg},
  1057  			fees,
  1058  			simtestutil.DefaultGenTxGas,
  1059  			chainID,
  1060  			[]uint64{account.GetAccountNumber()},
  1061  			[]uint64{account.GetSequence()},
  1062  			acc.PrivKey,
  1063  		)
  1064  		if err != nil {
  1065  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupPolicyMetadata, "unable to generate mock tx"), nil, err
  1066  		}
  1067  
  1068  		_, _, err = app.SimDeliver(txGen.TxEncoder(), tx)
  1069  
  1070  		if err != nil {
  1071  			if strings.Contains(err.Error(), "group was modified") || strings.Contains(err.Error(), "group policy was modified") {
  1072  				return simtypes.NoOpMsg(group.ModuleName, sdk.MsgTypeURL(msg), "no-op:group/group-policy was modified"), nil, nil
  1073  			}
  1074  			return simtypes.NoOpMsg(group.ModuleName, sdk.MsgTypeURL(msg), "unable to deliver tx"), nil, err
  1075  		}
  1076  
  1077  		return simtypes.NewOperationMsg(msg, true, ""), nil, err
  1078  	}
  1079  }
  1080  
  1081  // // SimulateMsgExec generates a MsgExec with random values
  1082  func SimulateMsgExec(
  1083  	cdc *codec.ProtoCodec,
  1084  	txGen client.TxConfig,
  1085  	ak group.AccountKeeper,
  1086  	bk group.BankKeeper,
  1087  	k keeper.Keeper,
  1088  ) simtypes.Operation {
  1089  	return func(
  1090  		r *rand.Rand, app *baseapp.BaseApp, sdkCtx sdk.Context, accounts []simtypes.Account, chainID string,
  1091  	) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
  1092  		_, groupPolicy, acc, account, err := randomGroupPolicy(r, k, ak, sdkCtx, accounts)
  1093  		if err != nil {
  1094  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgExec, ""), nil, err
  1095  		}
  1096  		if groupPolicy == nil {
  1097  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgExec, "no group policy found"), nil, nil
  1098  		}
  1099  		groupPolicyAddr := groupPolicy.Address
  1100  
  1101  		spendableCoins := bk.SpendableCoins(sdkCtx, account.GetAddress())
  1102  		fees, err := simtypes.RandomFees(r, sdkCtx, spendableCoins)
  1103  		if err != nil {
  1104  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgExec, "fee error"), nil, err
  1105  		}
  1106  
  1107  		proposalsResult, err := k.ProposalsByGroupPolicy(sdkCtx, &group.QueryProposalsByGroupPolicyRequest{Address: groupPolicyAddr})
  1108  		if err != nil {
  1109  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgExec, "fail to query group info"), nil, err
  1110  		}
  1111  		proposals := proposalsResult.GetProposals()
  1112  		if len(proposals) == 0 {
  1113  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgExec, "no proposals found"), nil, nil
  1114  		}
  1115  
  1116  		proposalID := -1
  1117  
  1118  		for _, proposal := range proposals {
  1119  			if proposal.Status == group.PROPOSAL_STATUS_ACCEPTED {
  1120  				proposalID = int(proposal.Id)
  1121  				break
  1122  			}
  1123  		}
  1124  
  1125  		// return no-op if no proposal found
  1126  		if proposalID == -1 {
  1127  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgExec, "no proposals found"), nil, nil
  1128  		}
  1129  
  1130  		msg := &group.MsgExec{
  1131  			ProposalId: uint64(proposalID),
  1132  			Executor:   acc.Address.String(),
  1133  		}
  1134  		tx, err := simtestutil.GenSignedMockTx(
  1135  			r,
  1136  			txGen,
  1137  			[]sdk.Msg{msg},
  1138  			fees,
  1139  			simtestutil.DefaultGenTxGas,
  1140  			chainID,
  1141  			[]uint64{account.GetAccountNumber()},
  1142  			[]uint64{account.GetSequence()},
  1143  			acc.PrivKey,
  1144  		)
  1145  		if err != nil {
  1146  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgUpdateGroupPolicyMetadata, "unable to generate mock tx"), nil, err
  1147  		}
  1148  
  1149  		_, _, err = app.SimDeliver(txGen.TxEncoder(), tx)
  1150  		if err != nil {
  1151  			if strings.Contains(err.Error(), "group was modified") || strings.Contains(err.Error(), "group policy was modified") {
  1152  				return simtypes.NoOpMsg(group.ModuleName, sdk.MsgTypeURL(msg), "no-op:group/group-policy was modified"), nil, nil
  1153  			}
  1154  			return simtypes.NoOpMsg(group.ModuleName, sdk.MsgTypeURL(msg), "unable to deliver tx"), nil, err
  1155  		}
  1156  
  1157  		return simtypes.NewOperationMsg(msg, true, ""), nil, err
  1158  	}
  1159  }
  1160  
  1161  // SimulateMsgLeaveGroup generates a MsgLeaveGroup with random values
  1162  func SimulateMsgLeaveGroup(
  1163  	cdc *codec.ProtoCodec,
  1164  	txGen client.TxConfig,
  1165  	k keeper.Keeper,
  1166  	ak group.AccountKeeper,
  1167  	bk group.BankKeeper,
  1168  ) simtypes.Operation {
  1169  	return func(
  1170  		r *rand.Rand, app *baseapp.BaseApp, sdkCtx sdk.Context, accounts []simtypes.Account, chainID string,
  1171  	) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
  1172  		groupInfo, policyInfo, _, _, err := randomGroupPolicy(r, k, ak, sdkCtx, accounts)
  1173  		if err != nil {
  1174  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgLeaveGroup, ""), nil, err
  1175  		}
  1176  
  1177  		if policyInfo == nil {
  1178  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgLeaveGroup, "no policy found"), nil, nil
  1179  		}
  1180  
  1181  		// Pick a random member from the group
  1182  		acc, account, err := randomMember(sdkCtx, r, k, ak, accounts, groupInfo.Id)
  1183  		if err != nil {
  1184  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgLeaveGroup, ""), nil, err
  1185  		}
  1186  		if account == nil {
  1187  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgLeaveGroup, "no group member found"), nil, nil
  1188  		}
  1189  
  1190  		spendableCoins := bk.SpendableCoins(sdkCtx, acc.Address)
  1191  		fees, err := simtypes.RandomFees(r, sdkCtx, spendableCoins)
  1192  		if err != nil {
  1193  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgLeaveGroup, "fee error"), nil, err
  1194  		}
  1195  
  1196  		msg := &group.MsgLeaveGroup{
  1197  			Address: acc.Address.String(),
  1198  			GroupId: groupInfo.Id,
  1199  		}
  1200  
  1201  		tx, err := simtestutil.GenSignedMockTx(
  1202  			r,
  1203  			txGen,
  1204  			[]sdk.Msg{msg},
  1205  			fees,
  1206  			simtestutil.DefaultGenTxGas,
  1207  			chainID,
  1208  			[]uint64{account.GetAccountNumber()},
  1209  			[]uint64{account.GetSequence()},
  1210  			acc.PrivKey,
  1211  		)
  1212  		if err != nil {
  1213  			return simtypes.NoOpMsg(group.ModuleName, TypeMsgLeaveGroup, "unable to generate mock tx"), nil, err
  1214  		}
  1215  
  1216  		_, _, err = app.SimDeliver(txGen.TxEncoder(), tx)
  1217  		if err != nil {
  1218  			return simtypes.NoOpMsg(group.ModuleName, sdk.MsgTypeURL(msg), err.Error()), nil, err
  1219  		}
  1220  
  1221  		return simtypes.NewOperationMsg(msg, true, ""), nil, err
  1222  	}
  1223  }
  1224  
  1225  func randomGroup(r *rand.Rand, k keeper.Keeper, ak group.AccountKeeper,
  1226  	ctx sdk.Context, accounts []simtypes.Account,
  1227  ) (groupInfo *group.GroupInfo, acc simtypes.Account, account sdk.AccountI, err error) {
  1228  	groupID := k.GetGroupSequence(ctx)
  1229  
  1230  	switch {
  1231  	case groupID > initialGroupID:
  1232  		// select a random ID between (initialGroupID, groupID]
  1233  		// if there is at least one group information, then the groupID at this time must be greater than or equal to 1
  1234  		groupID = uint64(simtypes.RandIntBetween(r, int(initialGroupID+1), int(groupID+1)))
  1235  
  1236  	default:
  1237  		// This is called on the first call to this function
  1238  		// in order to update the global variable
  1239  		initialGroupID = groupID
  1240  	}
  1241  
  1242  	// when groupID is 0, it proves that SimulateMsgCreateGroup has never been called. that is, no group exists in the chain
  1243  	if groupID == 0 {
  1244  		return nil, simtypes.Account{}, nil, nil
  1245  	}
  1246  
  1247  	res, err := k.GroupInfo(ctx, &group.QueryGroupInfoRequest{GroupId: groupID})
  1248  	if err != nil {
  1249  		return nil, simtypes.Account{}, nil, err
  1250  	}
  1251  
  1252  	groupInfo = res.Info
  1253  	groupAdmin := groupInfo.Admin
  1254  	found := -1
  1255  	for i := range accounts {
  1256  		if accounts[i].Address.String() == groupAdmin {
  1257  			found = i
  1258  			break
  1259  		}
  1260  	}
  1261  	if found < 0 {
  1262  		return nil, simtypes.Account{}, nil, nil
  1263  	}
  1264  	acc = accounts[found]
  1265  	account = ak.GetAccount(ctx, acc.Address)
  1266  	return groupInfo, acc, account, nil
  1267  }
  1268  
  1269  func randomGroupPolicy(r *rand.Rand, k keeper.Keeper, ak group.AccountKeeper,
  1270  	ctx sdk.Context, accounts []simtypes.Account,
  1271  ) (groupInfo *group.GroupInfo, groupPolicyInfo *group.GroupPolicyInfo, acc simtypes.Account, account sdk.AccountI, err error) {
  1272  	groupInfo, _, _, err = randomGroup(r, k, ak, ctx, accounts)
  1273  	if err != nil {
  1274  		return nil, nil, simtypes.Account{}, nil, err
  1275  	}
  1276  	if groupInfo == nil {
  1277  		return nil, nil, simtypes.Account{}, nil, nil
  1278  	}
  1279  	groupID := groupInfo.Id
  1280  
  1281  	result, err := k.GroupPoliciesByGroup(ctx, &group.QueryGroupPoliciesByGroupRequest{GroupId: groupID})
  1282  	if err != nil {
  1283  		return groupInfo, nil, simtypes.Account{}, nil, err
  1284  	}
  1285  
  1286  	n := randIntInRange(r, len(result.GroupPolicies))
  1287  	if n < 0 {
  1288  		return groupInfo, nil, simtypes.Account{}, nil, nil
  1289  	}
  1290  	groupPolicyInfo = result.GroupPolicies[n]
  1291  
  1292  	idx := findAccount(accounts, groupPolicyInfo.Admin)
  1293  	if idx < 0 {
  1294  		return groupInfo, nil, simtypes.Account{}, nil, nil
  1295  	}
  1296  	acc = accounts[idx]
  1297  	account = ak.GetAccount(ctx, acc.Address)
  1298  	return groupInfo, groupPolicyInfo, acc, account, nil
  1299  }
  1300  
  1301  func randomMember(ctx context.Context, r *rand.Rand, k keeper.Keeper, ak group.AccountKeeper,
  1302  	accounts []simtypes.Account, groupID uint64,
  1303  ) (acc simtypes.Account, account sdk.AccountI, err error) {
  1304  	res, err := k.GroupMembers(ctx, &group.QueryGroupMembersRequest{
  1305  		GroupId: groupID,
  1306  	})
  1307  	if err != nil {
  1308  		return simtypes.Account{}, nil, err
  1309  	}
  1310  	n := randIntInRange(r, len(res.Members))
  1311  	if n < 0 {
  1312  		return simtypes.Account{}, nil, err
  1313  	}
  1314  	idx := findAccount(accounts, res.Members[n].Member.Address)
  1315  	if idx < 0 {
  1316  		return simtypes.Account{}, nil, err
  1317  	}
  1318  	acc = accounts[idx]
  1319  	account = ak.GetAccount(sdk.UnwrapSDKContext(ctx), acc.Address)
  1320  	return acc, account, nil
  1321  }
  1322  
  1323  func randIntInRange(r *rand.Rand, l int) int {
  1324  	if l == 0 {
  1325  		return -1
  1326  	}
  1327  	if l == 1 {
  1328  		return 0
  1329  	}
  1330  	return simtypes.RandIntBetween(r, 0, l-1)
  1331  }
  1332  
  1333  func findAccount(accounts []simtypes.Account, addr string) (idx int) {
  1334  	idx = -1
  1335  	for i := range accounts {
  1336  		if accounts[i].Address.String() == addr {
  1337  			idx = i
  1338  			break
  1339  		}
  1340  	}
  1341  	return idx
  1342  }
  1343  
  1344  func genGroupMembers(r *rand.Rand, accounts []simtypes.Account) []group.MemberRequest {
  1345  	if len(accounts) == 1 {
  1346  		return []group.MemberRequest{
  1347  			{
  1348  				Address:  accounts[0].Address.String(),
  1349  				Weight:   fmt.Sprintf("%d", simtypes.RandIntBetween(r, 1, 10)),
  1350  				Metadata: simtypes.RandStringOfLength(r, 10),
  1351  			},
  1352  		}
  1353  	}
  1354  
  1355  	max := 5
  1356  	if len(accounts) < max {
  1357  		max = len(accounts)
  1358  	}
  1359  
  1360  	membersLen := simtypes.RandIntBetween(r, 1, max)
  1361  	members := make([]group.MemberRequest, membersLen)
  1362  
  1363  	for i := 0; i < membersLen; i++ {
  1364  		members[i] = group.MemberRequest{
  1365  			Address:  accounts[i].Address.String(),
  1366  			Weight:   fmt.Sprintf("%d", simtypes.RandIntBetween(r, 1, 10)),
  1367  			Metadata: simtypes.RandStringOfLength(r, 10),
  1368  		}
  1369  	}
  1370  
  1371  	return members
  1372  }