github.com/Finschia/finschia-sdk@v0.49.1/x/authz/simulation/operations.go (about) 1 package simulation 2 3 import ( 4 "math/rand" 5 6 "github.com/Finschia/finschia-sdk/baseapp" 7 "github.com/Finschia/finschia-sdk/codec" 8 cdctypes "github.com/Finschia/finschia-sdk/codec/types" 9 "github.com/Finschia/finschia-sdk/simapp/helpers" 10 simappparams "github.com/Finschia/finschia-sdk/simapp/params" 11 sdk "github.com/Finschia/finschia-sdk/types" 12 sdkerrors "github.com/Finschia/finschia-sdk/types/errors" 13 simtypes "github.com/Finschia/finschia-sdk/types/simulation" 14 "github.com/Finschia/finschia-sdk/x/authz" 15 "github.com/Finschia/finschia-sdk/x/authz/keeper" 16 banktype "github.com/Finschia/finschia-sdk/x/bank/types" 17 "github.com/Finschia/finschia-sdk/x/simulation" 18 ) 19 20 // authz message types 21 var ( 22 TypeMsgGrant = sdk.MsgTypeURL(&authz.MsgGrant{}) 23 TypeMsgRevoke = sdk.MsgTypeURL(&authz.MsgRevoke{}) 24 TypeMsgExec = sdk.MsgTypeURL(&authz.MsgExec{}) 25 ) 26 27 // Simulation operation weights constants 28 const ( 29 OpWeightMsgGrant = "op_weight_msg_grant" 30 OpWeightRevoke = "op_weight_msg_revoke" 31 OpWeightExec = "op_weight_msg_execute" 32 ) 33 34 // authz operations weights 35 const ( 36 WeightGrant = 100 37 WeightRevoke = 90 38 WeightExec = 90 39 ) 40 41 // WeightedOperations returns all the operations from the module with their respective weights 42 func WeightedOperations( 43 appParams simtypes.AppParams, cdc codec.JSONCodec, ak authz.AccountKeeper, bk authz.BankKeeper, k keeper.Keeper, appCdc cdctypes.AnyUnpacker, 44 ) simulation.WeightedOperations { 45 var ( 46 weightMsgGrant int 47 weightRevoke int 48 weightExec int 49 ) 50 51 appParams.GetOrGenerate(cdc, OpWeightMsgGrant, &weightMsgGrant, nil, 52 func(_ *rand.Rand) { 53 weightMsgGrant = WeightGrant 54 }, 55 ) 56 57 appParams.GetOrGenerate(cdc, OpWeightRevoke, &weightRevoke, nil, 58 func(_ *rand.Rand) { 59 weightRevoke = WeightRevoke 60 }, 61 ) 62 63 appParams.GetOrGenerate(cdc, OpWeightExec, &weightExec, nil, 64 func(_ *rand.Rand) { 65 weightExec = WeightExec 66 }, 67 ) 68 69 return simulation.WeightedOperations{ 70 simulation.NewWeightedOperation( 71 weightMsgGrant, 72 SimulateMsgGrant(ak, bk, k), 73 ), 74 simulation.NewWeightedOperation( 75 weightRevoke, 76 SimulateMsgRevoke(ak, bk, k), 77 ), 78 simulation.NewWeightedOperation( 79 weightExec, 80 SimulateMsgExec(ak, bk, k, appCdc), 81 ), 82 } 83 } 84 85 // SimulateMsgGrant generates a MsgGrant with random values. 86 func SimulateMsgGrant(ak authz.AccountKeeper, bk authz.BankKeeper, _ keeper.Keeper) simtypes.Operation { 87 return func( 88 r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, 89 ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { 90 granter, _ := simtypes.RandomAcc(r, accs) 91 grantee, _ := simtypes.RandomAcc(r, accs) 92 93 if granter.Address.Equals(grantee.Address) { 94 return simtypes.NoOpMsg(authz.ModuleName, TypeMsgGrant, "granter and grantee are same"), nil, nil 95 } 96 97 granterAcc := ak.GetAccount(ctx, granter.Address) 98 spendableCoins := bk.SpendableCoins(ctx, granter.Address) 99 fees, err := simtypes.RandomFees(r, ctx, spendableCoins) 100 if err != nil { 101 return simtypes.NoOpMsg(authz.ModuleName, TypeMsgGrant, err.Error()), nil, err 102 } 103 104 spendLimit := spendableCoins.Sub(fees) 105 if spendLimit == nil { 106 return simtypes.NoOpMsg(authz.ModuleName, TypeMsgGrant, "spend limit is nil"), nil, nil 107 } 108 109 expiration := ctx.BlockTime().AddDate(1, 0, 0) 110 msg, err := authz.NewMsgGrant(granter.Address, grantee.Address, generateRandomAuthorization(r, spendLimit), expiration) 111 if err != nil { 112 return simtypes.NoOpMsg(authz.ModuleName, TypeMsgGrant, err.Error()), nil, err 113 } 114 txCfg := simappparams.MakeTestEncodingConfig().TxConfig 115 tx, err := helpers.GenSignedMockTx( 116 r, 117 txCfg, 118 []sdk.Msg{msg}, 119 fees, 120 helpers.DefaultGenTxGas, 121 chainID, 122 []uint64{granterAcc.GetAccountNumber()}, 123 []uint64{granterAcc.GetSequence()}, 124 granter.PrivKey, 125 ) 126 if err != nil { 127 return simtypes.NoOpMsg(authz.ModuleName, TypeMsgGrant, "unable to generate mock tx"), nil, err 128 } 129 130 _, _, err = app.Deliver(txCfg.TxEncoder(), tx) 131 if err != nil { 132 return simtypes.NoOpMsg(authz.ModuleName, sdk.MsgTypeURL(msg), "unable to deliver tx"), nil, err 133 } 134 return simtypes.NewOperationMsg(msg, true, "", nil), nil, err 135 } 136 } 137 138 func generateRandomAuthorization(r *rand.Rand, spendLimit sdk.Coins) authz.Authorization { 139 authorizations := make([]authz.Authorization, 2) 140 authorizations[0] = banktype.NewSendAuthorization(spendLimit) 141 authorizations[1] = authz.NewGenericAuthorization(sdk.MsgTypeURL(&banktype.MsgSend{})) 142 143 return authorizations[r.Intn(len(authorizations))] 144 } 145 146 // SimulateMsgRevoke generates a MsgRevoke with random values. 147 func SimulateMsgRevoke(ak authz.AccountKeeper, bk authz.BankKeeper, k keeper.Keeper) simtypes.Operation { 148 return func( 149 r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, 150 ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { 151 var granterAddr, granteeAddr sdk.AccAddress 152 var grant authz.Grant 153 hasGrant := false 154 155 k.IterateGrants(ctx, func(granter, grantee sdk.AccAddress, g authz.Grant) bool { 156 grant = g 157 granterAddr = granter 158 granteeAddr = grantee 159 hasGrant = true 160 return true 161 }) 162 163 if !hasGrant { 164 return simtypes.NoOpMsg(authz.ModuleName, TypeMsgRevoke, "no grants"), nil, nil 165 } 166 167 granterAcc, ok := simtypes.FindAccount(accs, granterAddr) 168 if !ok { 169 return simtypes.NoOpMsg(authz.ModuleName, TypeMsgRevoke, "account not found"), nil, sdkerrors.Wrapf(sdkerrors.ErrNotFound, "account not found") 170 } 171 172 spendableCoins := bk.SpendableCoins(ctx, granterAddr) 173 fees, err := simtypes.RandomFees(r, ctx, spendableCoins) 174 if err != nil { 175 return simtypes.NoOpMsg(authz.ModuleName, TypeMsgRevoke, "fee error"), nil, err 176 } 177 178 a := grant.GetAuthorization() 179 msg := authz.NewMsgRevoke(granterAddr, granteeAddr, a.MsgTypeURL()) 180 txCfg := simappparams.MakeTestEncodingConfig().TxConfig 181 account := ak.GetAccount(ctx, granterAddr) 182 tx, err := helpers.GenSignedMockTx( 183 r, 184 txCfg, 185 []sdk.Msg{&msg}, 186 fees, 187 helpers.DefaultGenTxGas, 188 chainID, 189 []uint64{account.GetAccountNumber()}, 190 []uint64{account.GetSequence()}, 191 granterAcc.PrivKey, 192 ) 193 if err != nil { 194 return simtypes.NoOpMsg(authz.ModuleName, TypeMsgRevoke, err.Error()), nil, err 195 } 196 197 _, _, err = app.Deliver(txCfg.TxEncoder(), tx) 198 if err != nil { 199 return simtypes.NoOpMsg(authz.ModuleName, TypeMsgRevoke, "unable to deliver tx"), nil, err 200 } 201 202 return simtypes.NewOperationMsg(&msg, true, "", nil), nil, nil 203 } 204 } 205 206 // SimulateMsgExec generates a MsgExec with random values. 207 func SimulateMsgExec(ak authz.AccountKeeper, bk authz.BankKeeper, k keeper.Keeper, cdc cdctypes.AnyUnpacker) simtypes.Operation { 208 return func( 209 r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, 210 ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { 211 hasGrant := false 212 var targetGrant authz.Grant 213 var granterAddr sdk.AccAddress 214 var granteeAddr sdk.AccAddress 215 k.IterateGrants(ctx, func(granter, grantee sdk.AccAddress, grant authz.Grant) bool { 216 targetGrant = grant 217 granterAddr = granter 218 granteeAddr = grantee 219 hasGrant = true 220 return true 221 }) 222 223 if !hasGrant { 224 return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, "no grant found"), nil, nil 225 } 226 227 if targetGrant.Expiration.Before(ctx.BlockHeader().Time) { 228 return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, "grant expired"), nil, nil 229 } 230 231 grantee, ok := simtypes.FindAccount(accs, granteeAddr) 232 if !ok { 233 return simtypes.NoOpMsg(authz.ModuleName, TypeMsgRevoke, "Account not found"), nil, sdkerrors.Wrapf(sdkerrors.ErrNotFound, "grantee account not found") 234 } 235 236 if _, ok := simtypes.FindAccount(accs, granterAddr); !ok { 237 return simtypes.NoOpMsg(authz.ModuleName, TypeMsgRevoke, "Account not found"), nil, sdkerrors.Wrapf(sdkerrors.ErrNotFound, "granter account not found") 238 } 239 240 granterspendableCoins := bk.SpendableCoins(ctx, granterAddr) 241 coins := simtypes.RandSubsetCoins(r, granterspendableCoins) 242 // if coins slice is empty, we can not create valid banktype.MsgSend 243 if len(coins) == 0 { 244 return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, "empty coins slice"), nil, nil 245 } 246 // Check send_enabled status of each sent coin denom 247 if err := bk.IsSendEnabledCoins(ctx, coins...); err != nil { 248 return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, err.Error()), nil, nil 249 } 250 251 msg := []sdk.Msg{banktype.NewMsgSend(granterAddr, granteeAddr, coins)} 252 authorization := targetGrant.GetAuthorization() 253 254 sendAuth, ok := authorization.(*banktype.SendAuthorization) 255 if !ok { 256 return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, "not a send authorization"), nil, nil 257 } 258 259 _, err := sendAuth.Accept(ctx, msg[0]) 260 if err != nil { 261 if sdkerrors.ErrInsufficientFunds.Is(err) { 262 return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, err.Error()), nil, nil 263 } 264 return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, err.Error()), nil, err 265 } 266 267 msgExec := authz.NewMsgExec(granteeAddr, msg) 268 granteeSpendableCoins := bk.SpendableCoins(ctx, granteeAddr) 269 fees, err := simtypes.RandomFees(r, ctx, granteeSpendableCoins) 270 if err != nil { 271 return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, "fee error"), nil, err 272 } 273 274 txCfg := simappparams.MakeTestEncodingConfig().TxConfig 275 granteeAcc := ak.GetAccount(ctx, granteeAddr) 276 tx, err := helpers.GenSignedMockTx( 277 r, 278 txCfg, 279 []sdk.Msg{&msgExec}, 280 fees, 281 helpers.DefaultGenTxGas, 282 chainID, 283 []uint64{granteeAcc.GetAccountNumber()}, 284 []uint64{granteeAcc.GetSequence()}, 285 grantee.PrivKey, 286 ) 287 if err != nil { 288 return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, err.Error()), nil, err 289 } 290 291 _, _, err = app.Deliver(txCfg.TxEncoder(), tx) 292 if err != nil { 293 return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, err.Error()), nil, err 294 } 295 296 err = msgExec.UnpackInterfaces(cdc) 297 if err != nil { 298 return simtypes.NoOpMsg(authz.ModuleName, TypeMsgExec, "unmarshal error"), nil, err 299 } 300 return simtypes.NewOperationMsg(&msgExec, true, "success", nil), nil, nil 301 } 302 }