package simulation import ( "io/ioutil" "math/rand" "github.com/cosmos/cosmos-sdk/baseapp" simappparams "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/simulation" "github.com/CosmWasm/wasmd/app/params" "github.com/CosmWasm/wasmd/x/wasm/types" ) // Simulation operation weights constants //nolint:gosec const ( OpWeightMsgStoreCode = "op_weight_msg_store_code" OpWeightMsgInstantiateContract = "op_weight_msg_instantiate_contract" OpReflectContractPath = "op_reflect_contract_path" ) // WasmKeeper is a subset of the wasm keeper used by simulations type WasmKeeper interface { GetParams(ctx sdk.Context) types.Params IterateCodeInfos(ctx sdk.Context, cb func(uint64, types.CodeInfo) bool) } // WeightedOperations returns all the operations from the module with their respective weights func WeightedOperations( simstate *module.SimulationState, ak types.AccountKeeper, bk simulation.BankKeeper, wasmKeeper WasmKeeper, ) simulation.WeightedOperations { var ( weightMsgStoreCode int weightMsgInstantiateContract int wasmContractPath string ) simstate.AppParams.GetOrGenerate(simstate.Cdc, OpWeightMsgStoreCode, &weightMsgStoreCode, nil, func(_ *rand.Rand) { weightMsgStoreCode = params.DefaultWeightMsgStoreCode }, ) simstate.AppParams.GetOrGenerate(simstate.Cdc, OpWeightMsgInstantiateContract, &weightMsgInstantiateContract, nil, func(_ *rand.Rand) { weightMsgInstantiateContract = params.DefaultWeightMsgInstantiateContract }, ) simstate.AppParams.GetOrGenerate(simstate.Cdc, OpReflectContractPath, &wasmContractPath, nil, func(_ *rand.Rand) { // simulations are run from the `app` folder wasmContractPath = "../x/wasm/keeper/testdata/reflect.wasm" }, ) wasmBz, err := ioutil.ReadFile(wasmContractPath) if err != nil { panic(err) } return simulation.WeightedOperations{ simulation.NewWeightedOperation( weightMsgStoreCode, SimulateMsgStoreCode(ak, bk, wasmKeeper, wasmBz), ), simulation.NewWeightedOperation( weightMsgInstantiateContract, SimulateMsgInstantiateContract(ak, bk, wasmKeeper), ), } } // SimulateMsgStoreCode generates a MsgStoreCode with random values func SimulateMsgStoreCode(ak types.AccountKeeper, bk simulation.BankKeeper, wasmKeeper WasmKeeper, wasmBz []byte) simtypes.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { if wasmKeeper.GetParams(ctx).CodeUploadAccess.Permission != types.AccessTypeEverybody { return simtypes.NoOpMsg(types.ModuleName, types.MsgStoreCode{}.Type(), "no chain permission"), nil, nil } config := &types.AccessConfig{ Permission: types.AccessTypeEverybody, } simAccount, _ := simtypes.RandomAcc(r, accs) msg := types.MsgStoreCode{ Sender: simAccount.Address.String(), WASMByteCode: wasmBz, InstantiatePermission: config, } txCtx := simulation.OperationInput{ R: r, App: app, TxGen: simappparams.MakeTestEncodingConfig().TxConfig, Cdc: nil, Msg: &msg, MsgType: msg.Type(), Context: ctx, SimAccount: simAccount, AccountKeeper: ak, Bankkeeper: bk, ModuleName: types.ModuleName, } return simulation.GenAndDeliverTxWithRandFees(txCtx) } } // SimulateMsgInstantiateContract generates a MsgInstantiateContract with random values func SimulateMsgInstantiateContract(ak types.AccountKeeper, bk simulation.BankKeeper, wasmKeeper WasmKeeper) simtypes.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { simAccount, _ := simtypes.RandomAcc(r, accs) var codeID uint64 wasmKeeper.IterateCodeInfos(ctx, func(u uint64, info types.CodeInfo) bool { if info.InstantiateConfig.Permission != types.AccessTypeEverybody { return false } codeID = u return true }) if codeID == 0 { return simtypes.NoOpMsg(types.ModuleName, types.MsgInstantiateContract{}.Type(), "no codes with permission available"), nil, nil } spendable := bk.SpendableCoins(ctx, simAccount.Address) msg := types.MsgInstantiateContract{ Sender: simAccount.Address.String(), Admin: simtypes.RandomAccounts(r, 1)[0].Address.String(), CodeID: codeID, Label: simtypes.RandStringOfLength(r, 10), Msg: []byte(`{}`), Funds: simtypes.RandSubsetCoins(r, spendable), } txCtx := simulation.OperationInput{ R: r, App: app, TxGen: simappparams.MakeTestEncodingConfig().TxConfig, Cdc: nil, Msg: &msg, MsgType: msg.Type(), Context: ctx, SimAccount: simAccount, AccountKeeper: ak, Bankkeeper: bk, ModuleName: types.ModuleName, } return simulation.GenAndDeliverTxWithRandFees(txCtx) } }