github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/wasm/simulation/operations.go (about)

     1  package simulation
     2  
     3  //
     4  //import (
     5  //	"encoding/json"
     6  //	"io/ioutil"
     7  //	"math/rand"
     8  //
     9  //	wasmvmtypes "github.com/CosmWasm/wasmvm/types"
    10  //	"github.com/cosmos/cosmos-sdk/baseapp"
    11  //	simappparams "github.com/cosmos/cosmos-sdk/simapp/params"
    12  //	sdk "github.com/cosmos/cosmos-sdk/types"
    13  //	sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
    14  //	"github.com/cosmos/cosmos-sdk/types/module"
    15  //	simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
    16  //	"github.com/cosmos/cosmos-sdk/x/simulation"
    17  //
    18  //	"github.com/CosmWasm/wasmd/app/params"
    19  //	wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper"
    20  //	"github.com/CosmWasm/wasmd/x/wasm/keeper/testdata"
    21  //	"github.com/CosmWasm/wasmd/x/wasm/types"
    22  //)
    23  //
    24  //// Simulation operation weights constants
    25  ////nolint:gosec
    26  //const (
    27  //	OpWeightMsgStoreCode           = "op_weight_msg_store_code"
    28  //	OpWeightMsgInstantiateContract = "op_weight_msg_instantiate_contract"
    29  //	OpWeightMsgExecuteContract     = "op_weight_msg_execute_contract"
    30  //	OpReflectContractPath          = "op_reflect_contract_path"
    31  //)
    32  //
    33  //// WasmKeeper is a subset of the wasm keeper used by simulations
    34  //type WasmKeeper interface {
    35  //	GetParams(ctx sdk.Context) types.Params
    36  //	IterateCodeInfos(ctx sdk.Context, cb func(uint64, types.CodeInfo) bool)
    37  //	IterateContractInfo(ctx sdk.Context, cb func(sdk.AccAddress, types.ContractInfo) bool)
    38  //	QuerySmart(ctx sdk.Context, contractAddr sdk.AccAddress, req []byte) ([]byte, error)
    39  //	PeekAutoIncrementID(ctx sdk.Context, lastIDKey []byte) uint64
    40  //}
    41  //type BankKeeper interface {
    42  //	simulation.BankKeeper
    43  //	IsSendEnabledCoin(ctx sdk.Context, coin sdk.Coin) bool
    44  //}
    45  //
    46  //// WeightedOperations returns all the operations from the module with their respective weights
    47  //func WeightedOperations(
    48  //	simstate *module.SimulationState,
    49  //	ak types.AccountKeeper,
    50  //	bk BankKeeper,
    51  //	wasmKeeper WasmKeeper,
    52  //) simulation.WeightedOperations {
    53  //	var (
    54  //		weightMsgStoreCode           int
    55  //		weightMsgInstantiateContract int
    56  //		weightMsgExecuteContract     int
    57  //		wasmContractPath             string
    58  //	)
    59  //
    60  //	simstate.AppParams.GetOrGenerate(simstate.Cdc, OpWeightMsgStoreCode, &weightMsgStoreCode, nil,
    61  //		func(_ *rand.Rand) {
    62  //			weightMsgStoreCode = params.DefaultWeightMsgStoreCode
    63  //		},
    64  //	)
    65  //
    66  //	simstate.AppParams.GetOrGenerate(simstate.Cdc, OpWeightMsgInstantiateContract, &weightMsgInstantiateContract, nil,
    67  //		func(_ *rand.Rand) {
    68  //			weightMsgInstantiateContract = params.DefaultWeightMsgInstantiateContract
    69  //		},
    70  //	)
    71  //	simstate.AppParams.GetOrGenerate(simstate.Cdc, OpWeightMsgExecuteContract, &weightMsgInstantiateContract, nil,
    72  //		func(_ *rand.Rand) {
    73  //			weightMsgExecuteContract = params.DefaultWeightMsgExecuteContract
    74  //		},
    75  //	)
    76  //	simstate.AppParams.GetOrGenerate(simstate.Cdc, OpReflectContractPath, &wasmContractPath, nil,
    77  //		func(_ *rand.Rand) {
    78  //			wasmContractPath = ""
    79  //		},
    80  //	)
    81  //
    82  //	var wasmBz []byte
    83  //	if wasmContractPath == "" {
    84  //		wasmBz = testdata.ReflectContractWasm()
    85  //	} else {
    86  //		var err error
    87  //		wasmBz, err = ioutil.ReadFile(wasmContractPath)
    88  //		if err != nil {
    89  //			panic(err)
    90  //		}
    91  //	}
    92  //
    93  //	return simulation.WeightedOperations{
    94  //		simulation.NewWeightedOperation(
    95  //			weightMsgStoreCode,
    96  //			SimulateMsgStoreCode(ak, bk, wasmKeeper, wasmBz, 5_000_000),
    97  //		),
    98  //		simulation.NewWeightedOperation(
    99  //			weightMsgInstantiateContract,
   100  //			SimulateMsgInstantiateContract(ak, bk, wasmKeeper, DefaultSimulationCodeIDSelector),
   101  //		),
   102  //		simulation.NewWeightedOperation(
   103  //			weightMsgExecuteContract,
   104  //			SimulateMsgExecuteContract(
   105  //				ak,
   106  //				bk,
   107  //				wasmKeeper,
   108  //				DefaultSimulationExecuteContractSelector,
   109  //				DefaultSimulationExecuteSenderSelector,
   110  //				DefaultSimulationExecutePayloader,
   111  //			),
   112  //		),
   113  //	}
   114  //}
   115  //
   116  //// SimulateMsgStoreCode generates a MsgStoreCode with random values
   117  //func SimulateMsgStoreCode(ak types.AccountKeeper, bk simulation.BankKeeper, wasmKeeper WasmKeeper, wasmBz []byte, gas uint64) simtypes.Operation {
   118  //	return func(
   119  //		r *rand.Rand,
   120  //		app *baseapp.BaseApp,
   121  //		ctx sdk.Context,
   122  //		accs []simtypes.Account,
   123  //		chainID string,
   124  //	) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
   125  //		if wasmKeeper.GetParams(ctx).CodeUploadAccess.Permission != types.AccessTypeEverybody {
   126  //			return simtypes.NoOpMsg(types.ModuleName, types.MsgStoreCode{}.Type(), "no chain permission"), nil, nil
   127  //		}
   128  //
   129  //		simAccount, _ := simtypes.RandomAcc(r, accs)
   130  //
   131  //		permission := wasmKeeper.GetParams(ctx).InstantiateDefaultPermission
   132  //		config := permission.With(simAccount.Address)
   133  //
   134  //		msg := types.MsgStoreCode{
   135  //			Sender:                simAccount.Address.String(),
   136  //			WASMByteCode:          wasmBz,
   137  //			InstantiatePermission: &config,
   138  //		}
   139  //
   140  //		txCtx := simulation.OperationInput{
   141  //			R:             r,
   142  //			App:           app,
   143  //			TxGen:         simappparams.MakeTestEncodingConfig().TxConfig,
   144  //			Cdc:           nil,
   145  //			Msg:           &msg,
   146  //			MsgType:       msg.Type(),
   147  //			Context:       ctx,
   148  //			SimAccount:    simAccount,
   149  //			AccountKeeper: ak,
   150  //			Bankkeeper:    bk,
   151  //			ModuleName:    types.ModuleName,
   152  //		}
   153  //
   154  //		return GenAndDeliverTxWithRandFees(txCtx, gas)
   155  //	}
   156  //}
   157  //
   158  //// CodeIDSelector returns code id to be used in simulations
   159  //type CodeIDSelector = func(ctx sdk.Context, wasmKeeper WasmKeeper) uint64
   160  //
   161  //// DefaultSimulationCodeIDSelector picks the first code id
   162  //func DefaultSimulationCodeIDSelector(ctx sdk.Context, wasmKeeper WasmKeeper) uint64 {
   163  //	var codeID uint64
   164  //	wasmKeeper.IterateCodeInfos(ctx, func(u uint64, info types.CodeInfo) bool {
   165  //		if info.InstantiateConfig.Permission != types.AccessTypeEverybody {
   166  //			return false
   167  //		}
   168  //		codeID = u
   169  //		return true
   170  //	})
   171  //	return codeID
   172  //}
   173  //
   174  //// SimulateMsgInstantiateContract generates a MsgInstantiateContract with random values
   175  //func SimulateMsgInstantiateContract(ak types.AccountKeeper, bk BankKeeper, wasmKeeper WasmKeeper, codeSelector CodeIDSelector) simtypes.Operation {
   176  //	return func(
   177  //		r *rand.Rand,
   178  //		app *baseapp.BaseApp,
   179  //		ctx sdk.Context,
   180  //		accs []simtypes.Account,
   181  //		chainID string,
   182  //	) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
   183  //		simAccount, _ := simtypes.RandomAcc(r, accs)
   184  //
   185  //		codeID := codeSelector(ctx, wasmKeeper)
   186  //		if codeID == 0 {
   187  //			return simtypes.NoOpMsg(types.ModuleName, types.MsgInstantiateContract{}.Type(), "no codes with permission available"), nil, nil
   188  //		}
   189  //		deposit := sdk.Coins{}
   190  //		spendableCoins := bk.SpendableCoins(ctx, simAccount.Address)
   191  //		for _, v := range spendableCoins {
   192  //			if bk.IsSendEnabledCoin(ctx, v) {
   193  //				deposit = deposit.Add(simtypes.RandSubsetCoins(r, sdk.NewCoins(v))...)
   194  //			}
   195  //		}
   196  //
   197  //		msg := types.MsgInstantiateContract{
   198  //			Sender: simAccount.Address.String(),
   199  //			Admin:  simtypes.RandomAccounts(r, 1)[0].Address.String(),
   200  //			CodeID: codeID,
   201  //			Label:  simtypes.RandStringOfLength(r, 10),
   202  //			Msg:    []byte(`{}`),
   203  //			Funds:  deposit,
   204  //		}
   205  //
   206  //		txCtx := simulation.OperationInput{
   207  //			R:               r,
   208  //			App:             app,
   209  //			TxGen:           simappparams.MakeTestEncodingConfig().TxConfig,
   210  //			Cdc:             nil,
   211  //			Msg:             &msg,
   212  //			MsgType:         msg.Type(),
   213  //			Context:         ctx,
   214  //			SimAccount:      simAccount,
   215  //			AccountKeeper:   ak,
   216  //			Bankkeeper:      bk,
   217  //			ModuleName:      types.ModuleName,
   218  //			CoinsSpentInMsg: deposit,
   219  //		}
   220  //
   221  //		return simulation.GenAndDeliverTxWithRandFees(txCtx)
   222  //	}
   223  //}
   224  //
   225  //// MsgExecuteContractSelector returns contract address to be used in simulations
   226  //type MsgExecuteContractSelector = func(ctx sdk.Context, wasmKeeper WasmKeeper) sdk.AccAddress
   227  //
   228  //// MsgExecutePayloader extension point to modify msg with custom payload
   229  //type MsgExecutePayloader func(msg *types.MsgExecuteContract) error
   230  //
   231  //// MsgExecuteSenderSelector extension point that returns the sender address
   232  //type MsgExecuteSenderSelector func(wasmKeeper WasmKeeper, ctx sdk.Context, contractAddr sdk.AccAddress, accs []simtypes.Account) (simtypes.Account, error)
   233  //
   234  //// SimulateMsgExecuteContract create a execute message a reflect contract instance
   235  //func SimulateMsgExecuteContract(
   236  //	ak types.AccountKeeper,
   237  //	bk BankKeeper,
   238  //	wasmKeeper WasmKeeper,
   239  //	contractSelector MsgExecuteContractSelector,
   240  //	senderSelector MsgExecuteSenderSelector,
   241  //	payloader MsgExecutePayloader,
   242  //) simtypes.Operation {
   243  //	return func(
   244  //		r *rand.Rand,
   245  //		app *baseapp.BaseApp,
   246  //		ctx sdk.Context,
   247  //		accs []simtypes.Account,
   248  //		chainID string,
   249  //	) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
   250  //		contractAddr := contractSelector(ctx, wasmKeeper)
   251  //		if contractAddr == nil {
   252  //			return simtypes.NoOpMsg(types.ModuleName, types.MsgExecuteContract{}.Type(), "no contract instance available"), nil, nil
   253  //		}
   254  //		simAccount, err := senderSelector(wasmKeeper, ctx, contractAddr, accs)
   255  //		if err != nil {
   256  //			return simtypes.NoOpMsg(types.ModuleName, types.MsgExecuteContract{}.Type(), "query contract owner"), nil, err
   257  //		}
   258  //
   259  //		deposit := sdk.Coins{}
   260  //		spendableCoins := bk.SpendableCoins(ctx, simAccount.Address)
   261  //		for _, v := range spendableCoins {
   262  //			if bk.IsSendEnabledCoin(ctx, v) {
   263  //				deposit = deposit.Add(simtypes.RandSubsetCoins(r, sdk.NewCoins(v))...)
   264  //			}
   265  //		}
   266  //		if deposit.IsZero() {
   267  //			return simtypes.NoOpMsg(types.ModuleName, types.MsgExecuteContract{}.Type(), "broke account"), nil, nil
   268  //		}
   269  //		msg := types.MsgExecuteContract{
   270  //			Sender:   simAccount.Address.String(),
   271  //			Contract: contractAddr.String(),
   272  //			Funds:    deposit,
   273  //		}
   274  //		if err := payloader(&msg); err != nil {
   275  //			return simtypes.NoOpMsg(types.ModuleName, types.MsgExecuteContract{}.Type(), "contract execute payload"), nil, err
   276  //		}
   277  //
   278  //		txCtx := simulation.OperationInput{
   279  //			R:               r,
   280  //			App:             app,
   281  //			TxGen:           simappparams.MakeTestEncodingConfig().TxConfig,
   282  //			Cdc:             nil,
   283  //			Msg:             &msg,
   284  //			MsgType:         msg.Type(),
   285  //			Context:         ctx,
   286  //			SimAccount:      simAccount,
   287  //			AccountKeeper:   ak,
   288  //			Bankkeeper:      bk,
   289  //			ModuleName:      types.ModuleName,
   290  //			CoinsSpentInMsg: deposit,
   291  //		}
   292  //		return simulation.GenAndDeliverTxWithRandFees(txCtx)
   293  //	}
   294  //}
   295  //
   296  //// DefaultSimulationExecuteContractSelector picks the first contract address
   297  //func DefaultSimulationExecuteContractSelector(ctx sdk.Context, wasmKeeper WasmKeeper) sdk.AccAddress {
   298  //	var r sdk.AccAddress
   299  //	wasmKeeper.IterateContractInfo(ctx, func(address sdk.AccAddress, info types.ContractInfo) bool {
   300  //		r = address
   301  //		return true
   302  //	})
   303  //	return r
   304  //}
   305  //
   306  //// DefaultSimulationExecuteSenderSelector queries reflect contract for owner address and selects accounts
   307  //func DefaultSimulationExecuteSenderSelector(wasmKeeper WasmKeeper, ctx sdk.Context, contractAddr sdk.AccAddress, accs []simtypes.Account) (simtypes.Account, error) {
   308  //	var none simtypes.Account
   309  //	bz, err := json.Marshal(testdata.ReflectQueryMsg{Owner: &struct{}{}})
   310  //	if err != nil {
   311  //		return none, sdkerrors.Wrap(err, "build smart query")
   312  //	}
   313  //	got, err := wasmKeeper.QuerySmart(ctx, contractAddr, bz)
   314  //	if err != nil {
   315  //		return none, sdkerrors.Wrap(err, "exec smart query")
   316  //	}
   317  //	var ownerRes testdata.OwnerResponse
   318  //	if err := json.Unmarshal(got, &ownerRes); err != nil || ownerRes.Owner == "" {
   319  //		return none, sdkerrors.Wrap(err, "parse smart query response")
   320  //	}
   321  //	ownerAddr, err := sdk.AccAddressFromBech32(ownerRes.Owner)
   322  //	if err != nil {
   323  //		return none, sdkerrors.Wrap(err, "parse contract owner address")
   324  //	}
   325  //	simAccount, ok := simtypes.FindAccount(accs, ownerAddr)
   326  //	if !ok {
   327  //		return none, sdkerrors.Wrap(err, "unknown contract owner address")
   328  //	}
   329  //	return simAccount, nil
   330  //}
   331  //
   332  //// DefaultSimulationExecutePayloader implements a bank msg to send the
   333  //// tokens from contract account back to original sender
   334  //func DefaultSimulationExecutePayloader(msg *types.MsgExecuteContract) error {
   335  //	reflectSend := testdata.ReflectHandleMsg{
   336  //		Reflect: &testdata.ReflectPayload{
   337  //			Msgs: []wasmvmtypes.CosmosMsg{{
   338  //				Bank: &wasmvmtypes.BankMsg{
   339  //					Send: &wasmvmtypes.SendMsg{
   340  //						ToAddress: msg.Sender, //
   341  //						Amount:    wasmkeeper.ConvertSdkCoinsToWasmCoins(msg.Funds),
   342  //					},
   343  //				},
   344  //			}},
   345  //		},
   346  //	}
   347  //	reflectSendBz, err := json.Marshal(reflectSend)
   348  //	if err != nil {
   349  //		return err
   350  //	}
   351  //	msg.Msg = reflectSendBz
   352  //	return nil
   353  //}