diff --git a/CHANGELOG.md b/CHANGELOG.md index 7148e122122b..79947cba3ce3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -172,12 +172,15 @@ generalized genesis accounts through the `GenesisAccount` interface. * (simulation) [\#4824](https://github.com/cosmos/cosmos-sdk/issues/4824) PrintAllInvariants flag will print all failed invariants * (simulation) [\#4490](https://github.com/cosmos/cosmos-sdk/issues/4490) add `InitialBlockHeight` flag to resume a simulation from a given block * Support exporting the simulation stats to a given JSON file -* (simulation) [\#4847](https://github.com/cosmos/cosmos-sdk/issues/4847), [\#4838](https://github.com/cosmos/cosmos-sdk/pull/4838) `SimApp` and simulation refactors +* (simulation) [\#4847](https://github.com/cosmos/cosmos-sdk/issues/4847), [\#4838](https://github.com/cosmos/cosmos-sdk/pull/4838) and [\#4869](https://github.com/cosmos/cosmos-sdk/pull/4869) `SimApp` and simulation refactors: * Implement `SimulationManager` for executing modules' simulation functionalities in a modularized way * Add `RegisterStoreDecoders` to the `SimulationManager` for decoding each module's types * Add `GenerateGenesisStates` to the `SimulationManager` to generate a randomized `GenState` for each module - * Add `RandomizedParams` to the `SimulationManager` that registers each modules' parameters `Content` to simulate - `ParamChangeProposal`s + * Add `RandomizedParams` to the `SimulationManager` that registers each modules' parameters in order to + simulate `ParamChangeProposal`s' `Content`s + * Add `WeightedOperations` to the `SimulationManager` that define simulation operations (modules' `Msg`s) with their + respective weights (i.e chance of being simulated). + * Add `ProposalContents` to the `SimulationManager` to register each module's governance proposal `Content`s. * (simulation) [\#4893](https://github.com/cosmos/cosmos-sdk/issues/4893) Change SimApp keepers to be public and add getter functions for keys and codec * (simulation) [\#4906](https://github.com/cosmos/cosmos-sdk/issues/4906) Add simulation `Config` struct that wraps simulation flags * (simulation) [\#4935](https://github.com/cosmos/cosmos-sdk/issues/4935) Update simulation to reflect a proper `ABCI` application without bypassing `BaseApp` semantics diff --git a/simapp/app.go b/simapp/app.go index 4ed1a244dda1..84a1197713c4 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -226,10 +226,10 @@ func NewSimApp( bank.NewAppModule(app.BankKeeper, app.AccountKeeper), crisis.NewAppModule(&app.CrisisKeeper), supply.NewAppModule(app.SupplyKeeper, app.AccountKeeper), - gov.NewAppModule(app.GovKeeper, app.SupplyKeeper), + gov.NewAppModule(app.GovKeeper, app.AccountKeeper, app.SupplyKeeper), mint.NewAppModule(app.MintKeeper), - distr.NewAppModule(app.DistrKeeper, app.SupplyKeeper), - slashing.NewAppModule(app.SlashingKeeper, app.StakingKeeper), + slashing.NewAppModule(app.SlashingKeeper, app.AccountKeeper, app.StakingKeeper), + distr.NewAppModule(app.DistrKeeper, app.AccountKeeper, app.SupplyKeeper, app.StakingKeeper), staking.NewAppModule(app.StakingKeeper, app.AccountKeeper, app.SupplyKeeper), upgrade.NewAppModule(app.UpgradeKeeper), evidence.NewAppModule(app.EvidenceKeeper), @@ -260,11 +260,12 @@ func NewSimApp( auth.NewAppModule(app.AccountKeeper), bank.NewAppModule(app.BankKeeper, app.AccountKeeper), supply.NewAppModule(app.SupplyKeeper, app.AccountKeeper), - gov.NewAppModule(app.GovKeeper, app.SupplyKeeper), + gov.NewAppModule(app.GovKeeper, app.AccountKeeper, app.SupplyKeeper), mint.NewAppModule(app.MintKeeper), - distr.NewAppModule(app.DistrKeeper, app.SupplyKeeper), staking.NewAppModule(app.StakingKeeper, app.AccountKeeper, app.SupplyKeeper), - slashing.NewAppModule(app.SlashingKeeper, app.StakingKeeper), + distr.NewAppModule(app.DistrKeeper, app.AccountKeeper, app.SupplyKeeper, app.StakingKeeper), + slashing.NewAppModule(app.SlashingKeeper, app.AccountKeeper, app.StakingKeeper), + params.NewAppModule(), // NOTE: only used for simulation to generate randomized param change proposals ) app.sm.RegisterStoreDecoders() diff --git a/simapp/params.go b/simapp/params.go index e0416761a8b3..7bb425b5f46f 100644 --- a/simapp/params.go +++ b/simapp/params.go @@ -2,23 +2,6 @@ package simapp // Simulation parameter constants const ( - StakePerAccount = "stake_per_account" - InitiallyBondedValidators = "initially_bonded_validators" - OpWeightDeductFee = "op_weight_deduct_fee" - OpWeightMsgSend = "op_weight_msg_send" - OpWeightMsgMultiSend = "op_weight_msg_multisend" - OpWeightMsgSetWithdrawAddress = "op_weight_msg_set_withdraw_address" - OpWeightMsgWithdrawDelegationReward = "op_weight_msg_withdraw_delegation_reward" - OpWeightMsgWithdrawValidatorCommission = "op_weight_msg_withdraw_validator_commission" - OpWeightSubmitTextProposal = "op_weight_submit_text_proposal" - OpWeightSubmitCommunitySpendProposal = "op_weight_submit_community_spend_proposal" - OpWeightSubmitParamChangeProposal = "op_weight_submit_param_change_proposal" - OpWeightMsgDeposit = "op_weight_msg_deposit" - OpWeightMsgVote = "op_weight_msg_vote" - OpWeightMsgCreateValidator = "op_weight_msg_create_validator" - OpWeightMsgEditValidator = "op_weight_msg_edit_validator" - OpWeightMsgDelegate = "op_weight_msg_delegate" - OpWeightMsgUndelegate = "op_weight_msg_undelegate" - OpWeightMsgBeginRedelegate = "op_weight_msg_begin_redelegate" - OpWeightMsgUnjail = "op_weight_msg_unjail" + StakePerAccount = "stake_per_account" + InitiallyBondedValidators = "initially_bonded_validators" ) diff --git a/simapp/params/doc.go b/simapp/params/doc.go new file mode 100644 index 000000000000..1c721342a9c9 --- /dev/null +++ b/simapp/params/doc.go @@ -0,0 +1,19 @@ +/* +Package params defines the simulation parameters in the simapp. + +It contains the default weights used for each transaction used on the module's +simulation. These weights define the chance for a transaction to be simulated at +any gived operation. + +You can repace the default values for the weights by providing a params.json +file with the weights defined for each of the transaction operations: + + { + "op_weight_msg_send": 60, + "op_weight_msg_delegate": 100, + } + +In the example above, the `MsgSend` has 60% chance to be simulated, while the +`MsgDelegate` will always be simulated. +*/ +package params diff --git a/simapp/params/weights.go b/simapp/params/weights.go new file mode 100644 index 000000000000..adff26b8a288 --- /dev/null +++ b/simapp/params/weights.go @@ -0,0 +1,22 @@ +package params + +// Default simulation operation weights for messages and gov proposals +const ( + DefaultWeightMsgSend int = 100 + DefaultWeightMsgMultiSend int = 10 + DefaultWeightMsgSetWithdrawAddress int = 50 + DefaultWeightMsgWithdrawDelegationReward int = 50 + DefaultWeightMsgWithdrawValidatorCommission int = 50 + DefaultWeightMsgDeposit int = 100 + DefaultWeightMsgVote int = 67 + DefaultWeightMsgUnjail int = 100 + DefaultWeightMsgCreateValidator int = 100 + DefaultWeightMsgEditValidator int = 5 + DefaultWeightMsgDelegate int = 100 + DefaultWeightMsgUndelegate int = 100 + DefaultWeightMsgBeginRedelegate int = 100 + + DefaultWeightCommunitySpendProposal int = 5 + DefaultWeightTextProposal int = 5 + DefaultWeightParamChangeProposal int = 5 +) diff --git a/simapp/sim_bench_test.go b/simapp/sim_bench_test.go index e9d5d7d87d2c..994e9803247a 100644 --- a/simapp/sim_bench_test.go +++ b/simapp/sim_bench_test.go @@ -36,7 +36,8 @@ func BenchmarkFullAppSimulation(b *testing.B) { // TODO: parameterize numbers, save for a later PR _, simParams, simErr := simulation.SimulateFromSeed( b, os.Stdout, app.BaseApp, AppStateFn(app.Codec(), app.sm), - testAndRunTxs(app, config), app.ModuleAccountAddrs(), config, + SimulationOperations(app, app.Codec(), config), + app.ModuleAccountAddrs(), config, ) // export state and params before the simulation error is checked @@ -86,7 +87,8 @@ func BenchmarkInvariants(b *testing.B) { // 2. Run parameterized simulation (w/o invariants) _, simParams, simErr := simulation.SimulateFromSeed( b, ioutil.Discard, app.BaseApp, AppStateFn(app.Codec(), app.sm), - testAndRunTxs(app, config), app.ModuleAccountAddrs(), config, + SimulationOperations(app, app.Codec(), config), + app.ModuleAccountAddrs(), config, ) // export state and params before the simulation error is checked diff --git a/simapp/sim_test.go b/simapp/sim_test.go index 17bcf9d57010..100e685836fc 100644 --- a/simapp/sim_test.go +++ b/simapp/sim_test.go @@ -18,19 +18,13 @@ import ( "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" - banksim "github.com/cosmos/cosmos-sdk/x/bank/simulation" distr "github.com/cosmos/cosmos-sdk/x/distribution" - distrsim "github.com/cosmos/cosmos-sdk/x/distribution/simulation" "github.com/cosmos/cosmos-sdk/x/gov" - govsim "github.com/cosmos/cosmos-sdk/x/gov/simulation" "github.com/cosmos/cosmos-sdk/x/mint" "github.com/cosmos/cosmos-sdk/x/params" - paramsim "github.com/cosmos/cosmos-sdk/x/params/simulation" "github.com/cosmos/cosmos-sdk/x/simulation" "github.com/cosmos/cosmos-sdk/x/slashing" - slashingsim "github.com/cosmos/cosmos-sdk/x/slashing/simulation" "github.com/cosmos/cosmos-sdk/x/staking" - stakingsim "github.com/cosmos/cosmos-sdk/x/staking/simulation" "github.com/cosmos/cosmos-sdk/x/supply" ) @@ -39,201 +33,6 @@ func init() { GetSimulatorFlags() } -func testAndRunTxs(app *SimApp, config simulation.Config) []simulation.WeightedOperation { - ap := make(simulation.AppParams) - - paramChanges := app.sm.GenerateParamChanges(config.Seed) - - if config.ParamsFile != "" { - bz, err := ioutil.ReadFile(config.ParamsFile) - if err != nil { - panic(err) - } - - app.cdc.MustUnmarshalJSON(bz, &ap) - } - - // nolint: govet - return []simulation.WeightedOperation{ - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgSend, &v, nil, - func(_ *rand.Rand) { - v = 100 - }) - return v - }(nil), - banksim.SimulateMsgSend(app.AccountKeeper, app.BankKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgMultiSend, &v, nil, - func(_ *rand.Rand) { - v = 40 - }) - return v - }(nil), - banksim.SimulateMsgMultiSend(app.AccountKeeper, app.BankKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgSetWithdrawAddress, &v, nil, - func(_ *rand.Rand) { - v = 50 - }) - return v - }(nil), - distrsim.SimulateMsgSetWithdrawAddress(app.AccountKeeper, app.DistrKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgWithdrawDelegationReward, &v, nil, - func(_ *rand.Rand) { - v = 50 - }) - return v - }(nil), - distrsim.SimulateMsgWithdrawDelegatorReward(app.AccountKeeper, app.DistrKeeper, app.StakingKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgWithdrawValidatorCommission, &v, nil, - func(_ *rand.Rand) { - v = 50 - }) - return v - }(nil), - distrsim.SimulateMsgWithdrawValidatorCommission(app.AccountKeeper, app.DistrKeeper, app.StakingKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightSubmitTextProposal, &v, nil, - func(_ *rand.Rand) { - v = 20 - }) - return v - }(nil), - govsim.SimulateSubmitProposal(app.AccountKeeper, app.GovKeeper, govsim.SimulateTextProposalContent), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightSubmitCommunitySpendProposal, &v, nil, - func(_ *rand.Rand) { - v = 20 - }) - return v - }(nil), - govsim.SimulateSubmitProposal(app.AccountKeeper, app.GovKeeper, distrsim.SimulateCommunityPoolSpendProposalContent(app.DistrKeeper)), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightSubmitParamChangeProposal, &v, nil, - func(_ *rand.Rand) { - v = 20 - }) - return v - }(nil), - govsim.SimulateSubmitProposal(app.AccountKeeper, app.GovKeeper, paramsim.SimulateParamChangeProposalContent(paramChanges)), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgDeposit, &v, nil, - func(_ *rand.Rand) { - v = 100 - }) - return v - }(nil), - govsim.SimulateMsgDeposit(app.AccountKeeper, app.GovKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgVote, &v, nil, - func(_ *rand.Rand) { - v = 100 - }) - return v - }(nil), - govsim.SimulateMsgVote(app.AccountKeeper, app.GovKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgCreateValidator, &v, nil, - func(_ *rand.Rand) { - v = 100 - }) - return v - }(nil), - stakingsim.SimulateMsgCreateValidator(app.AccountKeeper, app.StakingKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgEditValidator, &v, nil, - func(_ *rand.Rand) { - v = 20 - }) - return v - }(nil), - stakingsim.SimulateMsgEditValidator(app.AccountKeeper, app.StakingKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgDelegate, &v, nil, - func(_ *rand.Rand) { - v = 100 - }) - return v - }(nil), - stakingsim.SimulateMsgDelegate(app.AccountKeeper, app.StakingKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgUndelegate, &v, nil, - func(_ *rand.Rand) { - v = 100 - }) - return v - }(nil), - stakingsim.SimulateMsgUndelegate(app.AccountKeeper, app.StakingKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgBeginRedelegate, &v, nil, - func(_ *rand.Rand) { - v = 100 - }) - return v - }(nil), - stakingsim.SimulateMsgBeginRedelegate(app.AccountKeeper, app.StakingKeeper), - }, - { - func(_ *rand.Rand) int { - var v int - ap.GetOrGenerate(app.cdc, OpWeightMsgUnjail, &v, nil, - func(_ *rand.Rand) { - v = 100 - }) - return v - }(nil), - slashingsim.SimulateMsgUnjail(app.AccountKeeper, app.SlashingKeeper, app.StakingKeeper), - }, - } -} - // fauxMerkleModeOpt returns a BaseApp option to use a dbStoreAdapter instead of // an IAVLStore for faster simulation speed. func fauxMerkleModeOpt(bapp *baseapp.BaseApp) { @@ -276,7 +75,8 @@ func TestFullAppSimulation(t *testing.T) { // Run randomized simulation _, simParams, simErr := simulation.SimulateFromSeed( t, os.Stdout, app.BaseApp, AppStateFn(app.Codec(), app.sm), - testAndRunTxs(app, config), app.ModuleAccountAddrs(), config, + SimulationOperations(app, app.Codec(), config), + app.ModuleAccountAddrs(), config, ) // export state and params before the simulation error is checked @@ -331,7 +131,8 @@ func TestAppImportExport(t *testing.T) { // Run randomized simulation _, simParams, simErr := simulation.SimulateFromSeed( t, os.Stdout, app.BaseApp, AppStateFn(app.Codec(), app.sm), - testAndRunTxs(app, config), app.ModuleAccountAddrs(), config, + SimulationOperations(app, app.Codec(), config), + app.ModuleAccountAddrs(), config, ) // export state and simParams before the simulation error is checked @@ -417,7 +218,6 @@ func TestAppImportExport(t *testing.T) { fmt.Printf("compared %d key/value pairs between %s and %s\n", len(failedKVAs), storeKeyA, storeKeyB) require.Equal(t, len(failedKVAs), 0, GetSimulationLog(storeKeyA.Name(), app.sm.StoreDecoders, app.cdc, failedKVAs, failedKVBs)) } - } func TestAppSimulationAfterImport(t *testing.T) { @@ -449,7 +249,8 @@ func TestAppSimulationAfterImport(t *testing.T) { // Run randomized simulation stopEarly, simParams, simErr := simulation.SimulateFromSeed( t, os.Stdout, app.BaseApp, AppStateFn(app.Codec(), app.sm), - testAndRunTxs(app, config), app.ModuleAccountAddrs(), config, + SimulationOperations(app, app.Codec(), config), + app.ModuleAccountAddrs(), config, ) // export state and params before the simulation error is checked @@ -504,7 +305,8 @@ func TestAppSimulationAfterImport(t *testing.T) { // Run randomized simulation on imported app _, _, err = simulation.SimulateFromSeed( t, os.Stdout, newApp.BaseApp, AppStateFn(app.Codec(), app.sm), - testAndRunTxs(newApp, config), newApp.ModuleAccountAddrs(), config, + SimulationOperations(newApp, newApp.Codec(), config), + newApp.ModuleAccountAddrs(), config, ) require.NoError(t, err) @@ -550,7 +352,8 @@ func TestAppStateDeterminism(t *testing.T) { _, _, err := simulation.SimulateFromSeed( t, os.Stdout, app.BaseApp, AppStateFn(app.Codec(), app.sm), - testAndRunTxs(app, config), app.ModuleAccountAddrs(), config, + SimulationOperations(app, app.Codec(), config), + app.ModuleAccountAddrs(), config, ) require.NoError(t, err) diff --git a/simapp/state.go b/simapp/state.go index 679bce803b20..22a4e53a63f0 100644 --- a/simapp/state.go +++ b/simapp/state.go @@ -30,6 +30,7 @@ func AppStateFn(cdc *codec.Codec, simManager *module.SimulationManager) simulati genesisTimestamp = time.Unix(FlagGenesisTimeValue, 0) } + chainID = config.ChainID switch { case config.ParamsFile != "" && config.GenesisFile != "": panic("cannot provide both a genesis file and a params file") diff --git a/simapp/utils.go b/simapp/utils.go index 4f9ff37dc21b..959988d0b1c0 100644 --- a/simapp/utils.go +++ b/simapp/utils.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/x/simulation" ) @@ -84,6 +85,28 @@ func NewConfigFromFlags() simulation.Config { } } +// SimulationOperations retrieves the simulation params from the provided file path +// and returns all the modules weighted operations +func SimulationOperations(app *SimApp, cdc *codec.Codec, config simulation.Config) []simulation.WeightedOperation { + simState := module.SimulationState{ + AppParams: make(simulation.AppParams), + Cdc: cdc, + } + + if config.ParamsFile != "" { + bz, err := ioutil.ReadFile(config.ParamsFile) + if err != nil { + panic(err) + } + + app.cdc.MustUnmarshalJSON(bz, &simState.AppParams) + } + + simState.ParamChanges = app.sm.GenerateParamChanges(config.Seed) + simState.Contents = app.sm.GetProposalContents(simState) + return app.sm.WeightedOperations(simState) +} + //--------------------------------------------------------------------- // Simulation Utils diff --git a/types/module/simulation.go b/types/module/simulation.go index 1d359888646b..fab432c8a57e 100644 --- a/types/module/simulation.go +++ b/types/module/simulation.go @@ -2,6 +2,7 @@ package module import ( "encoding/json" + "math/rand" "time" @@ -13,14 +14,20 @@ import ( // AppModuleSimulation defines the standard functions that every module should expose // for the SDK blockchain simulator type AppModuleSimulation interface { - // register a func to decode the each module's defined types from their corresponding store key - RegisterStoreDecoder(sdk.StoreDecoderRegistry) - // randomized genesis states GenerateGenesisState(input *SimulationState) + // content functions used to simulate governance proposals + ProposalContents(simState SimulationState) []simulation.WeightedProposalContent + // randomized module parameters for param change proposals RandomizedParams(r *rand.Rand) []simulation.ParamChange + + // register a func to decode the each module's defined types from their corresponding store key + RegisterStoreDecoder(sdk.StoreDecoderRegistry) + + // simulation operations (i.e msgs) with their respective weight + WeightedOperations(simState SimulationState) []simulation.WeightedOperation } // SimulationManager defines a simulation manager that provides the high level utility @@ -40,6 +47,17 @@ func NewSimulationManager(modules ...AppModuleSimulation) *SimulationManager { } } +// GetProposalContents returns each module's proposal content generator function +// with their default operation weight and key. +func (sm *SimulationManager) GetProposalContents(simState SimulationState) []simulation.WeightedProposalContent { + var wContents []simulation.WeightedProposalContent + for _, module := range sm.Modules { + wContents = append(wContents, module.ProposalContents(simState)...) + } + + return wContents +} + // RegisterStoreDecoders registers each of the modules' store decoders into a map func (sm *SimulationManager) RegisterStoreDecoders() { for _, module := range sm.Modules { @@ -49,9 +67,9 @@ func (sm *SimulationManager) RegisterStoreDecoders() { // GenerateGenesisStates generates a randomized GenesisState for each of the // registered modules -func (sm *SimulationManager) GenerateGenesisStates(input *SimulationState) { +func (sm *SimulationManager) GenerateGenesisStates(simState *SimulationState) { for _, module := range sm.Modules { - module.GenerateGenesisState(input) + module.GenerateGenesisState(simState) } } @@ -67,16 +85,28 @@ func (sm *SimulationManager) GenerateParamChanges(seed int64) (paramChanges []si return } +// WeightedOperations returns all the modules' weighted operations of an application +func (sm *SimulationManager) WeightedOperations(simState SimulationState) []simulation.WeightedOperation { + var wOps []simulation.WeightedOperation + for _, module := range sm.Modules { + wOps = append(wOps, module.WeightedOperations(simState)...) + } + + return wOps +} + // SimulationState is the input parameters used on each of the module's randomized // GenesisState generator function type SimulationState struct { AppParams simulation.AppParams - Cdc *codec.Codec // application codec - Rand *rand.Rand // random number - GenState map[string]json.RawMessage // genesis state - Accounts []simulation.Account // simulation accounts - InitialStake int64 // initial coins per account - NumBonded int64 // number of initially bonded acconts - GenTimestamp time.Time // genesis timestamp - UnbondTime time.Duration // staking unbond time stored to use it as the slashing maximum evidence duration + Cdc *codec.Codec // application codec + Rand *rand.Rand // random number + GenState map[string]json.RawMessage // genesis state + Accounts []simulation.Account // simulation accounts + InitialStake int64 // initial coins per account + NumBonded int64 // number of initially bonded accounts + GenTimestamp time.Time // genesis timestamp + UnbondTime time.Duration // staking unbond time stored to use it as the slashing maximum evidence duration + ParamChanges []simulation.ParamChange // simulated parameter changes from modules + Contents []simulation.WeightedProposalContent // proposal content generator functions with their default weight and app sim key } diff --git a/x/auth/module.go b/x/auth/module.go index 676a54b61990..510f4304d7c5 100644 --- a/x/auth/module.go +++ b/x/auth/module.go @@ -22,7 +22,7 @@ import ( var ( _ module.AppModule = AppModule{} _ module.AppModuleBasic = AppModuleBasic{} - _ module.AppModuleSimulation = AppModuleSimulation{} + _ module.AppModuleSimulation = AppModule{} ) // AppModuleBasic defines the basic application module used by the auth module. @@ -71,30 +71,9 @@ func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { //____________________________________________________________________________ -// AppModuleSimulation defines the module simulation functions used by the auth module. -type AppModuleSimulation struct{} - -// RegisterStoreDecoder registers a decoder for auth module's types -func (AppModuleSimulation) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { - sdr[StoreKey] = simulation.DecodeStore -} - -// GenerateGenesisState creates a randomized GenState of the auth module -func (AppModuleSimulation) GenerateGenesisState(simState *module.SimulationState) { - simulation.RandomizedGenState(simState) -} - -// RandomizedParams creates randomized auth param changes for the simulator. -func (AppModuleSimulation) RandomizedParams(r *rand.Rand) []sim.ParamChange { - return simulation.ParamChanges(r) -} - -//____________________________________________________________________________ - // AppModule implements an application module for the auth module. type AppModule struct { AppModuleBasic - AppModuleSimulation accountKeeper AccountKeeper } @@ -102,9 +81,8 @@ type AppModule struct { // NewAppModule creates a new AppModule object func NewAppModule(accountKeeper AccountKeeper) AppModule { return AppModule{ - AppModuleBasic: AppModuleBasic{}, - AppModuleSimulation: AppModuleSimulation{}, - accountKeeper: accountKeeper, + AppModuleBasic: AppModuleBasic{}, + accountKeeper: accountKeeper, } } @@ -156,3 +134,32 @@ func (AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { return []abci.ValidatorUpdate{} } + +//____________________________________________________________________________ + +// AppModuleSimulation functions + +// GenerateGenesisState creates a randomized GenState of the auth module +func (AppModule) GenerateGenesisState(simState *module.SimulationState) { + simulation.RandomizedGenState(simState) +} + +// ProposalContents doesn't return any content functions for governance proposals. +func (AppModule) ProposalContents(_ module.SimulationState) []sim.WeightedProposalContent { + return nil +} + +// RandomizedParams creates randomized auth param changes for the simulator. +func (AppModule) RandomizedParams(r *rand.Rand) []sim.ParamChange { + return simulation.ParamChanges(r) +} + +// RegisterStoreDecoder registers a decoder for auth module's types +func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { + sdr[StoreKey] = simulation.DecodeStore +} + +// WeightedOperations doesn't return any auth module operation. +func (AppModule) WeightedOperations(_ module.SimulationState) []sim.WeightedOperation { + return nil +} diff --git a/x/bank/module.go b/x/bank/module.go index 2539f052cd3b..0430d18f1550 100644 --- a/x/bank/module.go +++ b/x/bank/module.go @@ -24,7 +24,7 @@ import ( var ( _ module.AppModule = AppModule{} _ module.AppModuleBasic = AppModuleBasic{} - _ module.AppModuleSimulation = AppModuleSimulation{} + _ module.AppModuleSimulation = AppModule{} ) // AppModuleBasic defines the basic application module used by the bank module. @@ -67,28 +67,9 @@ func (AppModuleBasic) GetQueryCmd(_ *codec.Codec) *cobra.Command { return nil } //____________________________________________________________________________ -// AppModuleSimulation defines the module simulation functions used by the bank module. -type AppModuleSimulation struct{} - -// RegisterStoreDecoder performs a no-op. -func (AppModuleSimulation) RegisterStoreDecoder(_ sdk.StoreDecoderRegistry) {} - -// GenerateGenesisState creates a randomized GenState of the bank module. -func (AppModuleSimulation) GenerateGenesisState(simState *module.SimulationState) { - simulation.RandomizedGenState(simState) -} - -// RandomizedParams creates randomized bank param changes for the simulator. -func (AppModuleSimulation) RandomizedParams(r *rand.Rand) []sim.ParamChange { - return simulation.ParamChanges(r) -} - -//____________________________________________________________________________ - // AppModule implements an application module for the bank module. type AppModule struct { AppModuleBasic - AppModuleSimulation keeper Keeper accountKeeper types.AccountKeeper @@ -97,10 +78,9 @@ type AppModule struct { // NewAppModule creates a new AppModule object func NewAppModule(keeper Keeper, accountKeeper types.AccountKeeper) AppModule { return AppModule{ - AppModuleBasic: AppModuleBasic{}, - AppModuleSimulation: AppModuleSimulation{}, - keeper: keeper, - accountKeeper: accountKeeper, + AppModuleBasic: AppModuleBasic{}, + keeper: keeper, + accountKeeper: accountKeeper, } } @@ -150,3 +130,32 @@ func (AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { return []abci.ValidatorUpdate{} } + +//____________________________________________________________________________ + +// AppModuleSimulation functions + +// GenerateGenesisState creates a randomized GenState of the bank module. +func (AppModule) GenerateGenesisState(simState *module.SimulationState) { + simulation.RandomizedGenState(simState) +} + +// ProposalContents doesn't return any content functions for governance proposals. +func (AppModule) ProposalContents(_ module.SimulationState) []sim.WeightedProposalContent { + return nil +} + +// RandomizedParams creates randomized bank param changes for the simulator. +func (AppModule) RandomizedParams(r *rand.Rand) []sim.ParamChange { + return simulation.ParamChanges(r) +} + +// RegisterStoreDecoder performs a no-op. +func (AppModule) RegisterStoreDecoder(_ sdk.StoreDecoderRegistry) {} + +// WeightedOperations returns the all the gov module operations with their respective weights. +func (am AppModule) WeightedOperations(simState module.SimulationState) []sim.WeightedOperation { + return simulation.WeightedOperations( + simState.AppParams, simState.Cdc, am.accountKeeper, am.keeper, + ) +} diff --git a/x/bank/simulation/operations.go b/x/bank/simulation/operations.go index 9d46d1fff946..9e89174e9433 100644 --- a/x/bank/simulation/operations.go +++ b/x/bank/simulation/operations.go @@ -7,13 +7,50 @@ import ( "github.com/tendermint/tendermint/crypto" "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/simapp/helpers" + simappparams "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/bank/internal/keeper" "github.com/cosmos/cosmos-sdk/x/bank/internal/types" "github.com/cosmos/cosmos-sdk/x/simulation" ) +// Simulation operation weights constants +const ( + OpWeightMsgSend = "op_weight_msg_send" + OpWeightMsgMultiSend = "op_weight_msg_multisend" +) + +// WeightedOperations returns all the operations from the module with their respective weights +func WeightedOperations(appParams simulation.AppParams, cdc *codec.Codec, ak types.AccountKeeper, + bk keeper.Keeper) simulation.WeightedOperations { + + var weightMsgSend, weightMsgMultiSend int + appParams.GetOrGenerate(cdc, OpWeightMsgSend, &weightMsgSend, nil, + func(_ *rand.Rand) { + weightMsgSend = simappparams.DefaultWeightMsgSend + }, + ) + + appParams.GetOrGenerate(cdc, OpWeightMsgMultiSend, &weightMsgMultiSend, nil, + func(_ *rand.Rand) { + weightMsgMultiSend = simappparams.DefaultWeightMsgMultiSend + }, + ) + + return simulation.WeightedOperations{ + simulation.NewWeightedOperation( + weightMsgSend, + SimulateMsgSend(ak, bk), + ), + simulation.NewWeightedOperation( + weightMsgMultiSend, + SimulateMsgMultiSend(ak, bk), + ), + } +} + // SimulateMsgSend tests and runs a single msg send where both // accounts already exist. // nolint: funlen @@ -51,12 +88,15 @@ func SimulateMsgSend(ak types.AccountKeeper, bk keeper.Keeper) simulation.Operat func sendMsgSend( r *rand.Rand, app *baseapp.BaseApp, ak types.AccountKeeper, msg types.MsgSend, ctx sdk.Context, chainID string, privkeys []crypto.PrivKey, -) (err error) { +) error { account := ak.GetAccount(ctx, msg.FromAddress) coins := account.SpendableCoins(ctx.BlockTime()) - var fees sdk.Coins + var ( + fees sdk.Coins + err error + ) coins, hasNeg := coins.SafeSub(msg.Amount) if !hasNeg { fees, err = simulation.RandomFees(r, ctx, coins) @@ -181,7 +221,7 @@ func SimulateMsgMultiSend(ak types.AccountKeeper, bk keeper.Keeper) simulation.O func sendMsgMultiSend( r *rand.Rand, app *baseapp.BaseApp, ak types.AccountKeeper, msg types.MsgMultiSend, ctx sdk.Context, chainID string, privkeys []crypto.PrivKey, -) (err error) { +) error { accountNumbers := make([]uint64, len(msg.Inputs)) sequenceNumbers := make([]uint64, len(msg.Inputs)) @@ -196,7 +236,10 @@ func sendMsgMultiSend( feePayer := ak.GetAccount(ctx, msg.Inputs[0].Address) coins := feePayer.SpendableCoins(ctx.BlockTime()) - var fees sdk.Coins + var ( + fees sdk.Coins + err error + ) coins, hasNeg := coins.SafeSub(msg.Inputs[0].Coins) if !hasNeg { fees, err = simulation.RandomFees(r, ctx, coins) diff --git a/x/distribution/module.go b/x/distribution/module.go index 2b42e0b68c51..c0452ebb3c6b 100644 --- a/x/distribution/module.go +++ b/x/distribution/module.go @@ -18,12 +18,13 @@ import ( "github.com/cosmos/cosmos-sdk/x/distribution/simulation" "github.com/cosmos/cosmos-sdk/x/distribution/types" sim "github.com/cosmos/cosmos-sdk/x/simulation" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" ) var ( _ module.AppModule = AppModule{} _ module.AppModuleBasic = AppModuleBasic{} - _ module.AppModuleSimulation = AppModuleSimulation{} + _ module.AppModuleSimulation = AppModule{} ) // AppModuleBasic defines the basic application module used by the distribution module. @@ -72,42 +73,25 @@ func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { //____________________________________________________________________________ -// AppModuleSimulation defines the module simulation functions used by the distribution module. -type AppModuleSimulation struct{} - -// RegisterStoreDecoder registers a decoder for distribution module's types -func (AppModuleSimulation) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { - sdr[StoreKey] = simulation.DecodeStore -} - -// GenerateGenesisState creates a randomized GenState of the distribution module. -func (AppModuleSimulation) GenerateGenesisState(simState *module.SimulationState) { - simulation.RandomizedGenState(simState) -} - -// RandomizedParams creates randomized distribution param changes for the simulator. -func (AppModuleSimulation) RandomizedParams(r *rand.Rand) []sim.ParamChange { - return simulation.ParamChanges(r) -} - -//____________________________________________________________________________ - // AppModule implements an application module for the distribution module. type AppModule struct { AppModuleBasic - AppModuleSimulation - keeper Keeper - supplyKeeper types.SupplyKeeper + keeper Keeper + accountKeeper types.AccountKeeper + stakingKeeper stakingkeeper.Keeper + supplyKeeper types.SupplyKeeper } // NewAppModule creates a new AppModule object -func NewAppModule(keeper Keeper, supplyKeeper types.SupplyKeeper) AppModule { +func NewAppModule(keeper Keeper, accountKeeper types.AccountKeeper, + supplyKeeper types.SupplyKeeper, stakingKeeper stakingkeeper.Keeper) AppModule { return AppModule{ - AppModuleBasic: AppModuleBasic{}, - AppModuleSimulation: AppModuleSimulation{}, - keeper: keeper, - supplyKeeper: supplyKeeper, + AppModuleBasic: AppModuleBasic{}, + keeper: keeper, + accountKeeper: accountKeeper, + supplyKeeper: supplyKeeper, + stakingKeeper: stakingKeeper, } } @@ -167,3 +151,34 @@ func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) { func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { return []abci.ValidatorUpdate{} } + +//____________________________________________________________________________ + +// AppModuleSimulation functions + +// GenerateGenesisState creates a randomized GenState of the distribution module. +func (AppModule) GenerateGenesisState(simState *module.SimulationState) { + simulation.RandomizedGenState(simState) +} + +// ProposalContents returns all the distribution content functions used to +// simulate governance proposals. +func (am AppModule) ProposalContents(_ module.SimulationState) []sim.WeightedProposalContent { + return simulation.ProposalContents(am.keeper) +} + +// RandomizedParams creates randomized distribution param changes for the simulator. +func (AppModule) RandomizedParams(r *rand.Rand) []sim.ParamChange { + return simulation.ParamChanges(r) +} + +// RegisterStoreDecoder registers a decoder for distribution module's types +func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { + sdr[StoreKey] = simulation.DecodeStore +} + +// WeightedOperations returns the all the gov module operations with their respective weights. +func (am AppModule) WeightedOperations(simState module.SimulationState) []sim.WeightedOperation { + return simulation.WeightedOperations(simState.AppParams, simState.Cdc, + am.accountKeeper, am.keeper, am.stakingKeeper) +} diff --git a/x/distribution/simulation/operations.go b/x/distribution/simulation/operations.go index c8bab36d496b..f3875e2560b0 100644 --- a/x/distribution/simulation/operations.go +++ b/x/distribution/simulation/operations.go @@ -6,23 +6,72 @@ import ( "math/rand" "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/simapp/helpers" + simappparams "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/distribution/keeper" "github.com/cosmos/cosmos-sdk/x/distribution/types" - govsim "github.com/cosmos/cosmos-sdk/x/gov/simulation" - govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/cosmos/cosmos-sdk/x/simulation" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" ) +// Simulation operation weights constants +const ( + OpWeightMsgSetWithdrawAddress = "op_weight_msg_set_withdraw_address" + OpWeightMsgWithdrawDelegationReward = "op_weight_msg_withdraw_delegation_reward" + OpWeightMsgWithdrawValidatorCommission = "op_weight_msg_withdraw_validator_commission" +) + +// WeightedOperations returns all the operations from the module with their respective weights +func WeightedOperations( + appParams simulation.AppParams, cdc *codec.Codec, ak types.AccountKeeper, + k keeper.Keeper, sk stakingkeeper.Keeper, +) simulation.WeightedOperations { + + var weightMsgSetWithdrawAddress int + appParams.GetOrGenerate(cdc, OpWeightMsgSetWithdrawAddress, &weightMsgSetWithdrawAddress, nil, + func(_ *rand.Rand) { + weightMsgSetWithdrawAddress = simappparams.DefaultWeightMsgSetWithdrawAddress + }, + ) + + var weightMsgWithdrawDelegationReward int + appParams.GetOrGenerate(cdc, OpWeightMsgWithdrawDelegationReward, &weightMsgWithdrawDelegationReward, nil, + func(_ *rand.Rand) { + weightMsgWithdrawDelegationReward = simappparams.DefaultWeightMsgWithdrawDelegationReward + }, + ) + + var weightMsgWithdrawValidatorCommission int + appParams.GetOrGenerate(cdc, OpWeightMsgWithdrawValidatorCommission, &weightMsgWithdrawValidatorCommission, nil, + func(_ *rand.Rand) { + weightMsgWithdrawValidatorCommission = simappparams.DefaultWeightMsgWithdrawValidatorCommission + }, + ) + + return simulation.WeightedOperations{ + simulation.NewWeightedOperation( + weightMsgSetWithdrawAddress, + SimulateMsgSetWithdrawAddress(ak, k), + ), + simulation.NewWeightedOperation( + weightMsgWithdrawDelegationReward, + SimulateMsgWithdrawDelegatorReward(ak, k, sk), + ), + simulation.NewWeightedOperation( + weightMsgWithdrawValidatorCommission, + SimulateMsgWithdrawValidatorCommission(ak, k, sk), + ), + } +} + // SimulateMsgSetWithdrawAddress generates a MsgSetWithdrawAddress with random values. // nolint: funlen func SimulateMsgSetWithdrawAddress(ak types.AccountKeeper, k keeper.Keeper) simulation.Operation { return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, ) (simulation.OperationMsg, []simulation.FutureOperation, error) { - if !k.GetWithdrawAddrEnabled(ctx) { return simulation.NoOpMsg(types.ModuleName), nil, nil } @@ -59,9 +108,9 @@ func SimulateMsgSetWithdrawAddress(ak types.AccountKeeper, k keeper.Keeper) simu // SimulateMsgWithdrawDelegatorReward generates a MsgWithdrawDelegatorReward with random values. // nolint: funlen func SimulateMsgWithdrawDelegatorReward(ak types.AccountKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation { - return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, + return func( + r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string, ) (simulation.OperationMsg, []simulation.FutureOperation, error) { - simAccount, _ := simulation.RandomAcc(r, accs) delegations := sk.GetAllDelegatorDelegations(ctx, simAccount.Address) if len(delegations) == 0 { @@ -148,29 +197,3 @@ func SimulateMsgWithdrawValidatorCommission(ak types.AccountKeeper, k keeper.Kee return simulation.NewOperationMsg(msg, true, ""), nil, nil } } - -// SimulateCommunityPoolSpendProposalContent generates random community-pool-spend proposal content -// nolint: funlen -func SimulateCommunityPoolSpendProposalContent(k keeper.Keeper) govsim.ContentSimulator { - return func(r *rand.Rand, ctx sdk.Context, accs []simulation.Account) govtypes.Content { - simAccount, _ := simulation.RandomAcc(r, accs) - - balance := k.GetFeePool(ctx).CommunityPool - if balance.Empty() { - return nil - } - - denomIndex := r.Intn(len(balance)) - amount, err := simulation.RandPositiveInt(r, balance[denomIndex].Amount.TruncateInt()) - if err != nil { - return nil - } - - return types.NewCommunityPoolSpendProposal( - simulation.RandStringOfLength(r, 10), - simulation.RandStringOfLength(r, 100), - simAccount.Address, - sdk.NewCoins(sdk.NewCoin(balance[denomIndex].Denom, amount)), - ) - } -} diff --git a/x/distribution/simulation/proposals.go b/x/distribution/simulation/proposals.go new file mode 100644 index 000000000000..cd6fcb1b7506 --- /dev/null +++ b/x/distribution/simulation/proposals.go @@ -0,0 +1,52 @@ +package simulation + +import ( + "math/rand" + + simappparams "github.com/cosmos/cosmos-sdk/simapp/params" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/distribution/keeper" + "github.com/cosmos/cosmos-sdk/x/distribution/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/cosmos-sdk/x/simulation" +) + +// OpWeightSubmitCommunitySpendProposal app params key for community spend proposal +const OpWeightSubmitCommunitySpendProposal = "op_weight_submit_community_spend_proposal" + +// ProposalContents defines the module weighted proposals' contents +func ProposalContents(k keeper.Keeper) []simulation.WeightedProposalContent { + return []simulation.WeightedProposalContent{ + { + AppParamsKey: OpWeightSubmitCommunitySpendProposal, + DefaultWeight: simappparams.DefaultWeightCommunitySpendProposal, + ContentSimulatorFn: SimulateCommunityPoolSpendProposalContent(k), + }, + } +} + +// SimulateCommunityPoolSpendProposalContent generates random community-pool-spend proposal content +// nolint: funlen +func SimulateCommunityPoolSpendProposalContent(k keeper.Keeper) simulation.ContentSimulatorFn { + return func(r *rand.Rand, ctx sdk.Context, accs []simulation.Account) govtypes.Content { + simAccount, _ := simulation.RandomAcc(r, accs) + + balance := k.GetFeePool(ctx).CommunityPool + if balance.Empty() { + return nil + } + + denomIndex := r.Intn(len(balance)) + amount, err := simulation.RandPositiveInt(r, balance[denomIndex].Amount.TruncateInt()) + if err != nil { + return nil + } + + return types.NewCommunityPoolSpendProposal( + simulation.RandStringOfLength(r, 10), + simulation.RandStringOfLength(r, 100), + simAccount.Address, + sdk.NewCoins(sdk.NewCoin(balance[denomIndex].Denom, amount)), + ) + } +} diff --git a/x/gov/module.go b/x/gov/module.go index 26b238f1e9df..1ef3a8c0f5cf 100644 --- a/x/gov/module.go +++ b/x/gov/module.go @@ -26,7 +26,7 @@ import ( var ( _ module.AppModule = AppModule{} _ module.AppModuleBasic = AppModuleBasic{} - _ module.AppModuleSimulation = AppModuleSimulation{} + _ module.AppModuleSimulation = AppModule{} ) // AppModuleBasic defines the basic application module used by the gov module. @@ -95,42 +95,22 @@ func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { //____________________________________________________________________________ -// AppModuleSimulation defines the module simulation functions used by the gov module. -type AppModuleSimulation struct{} - -// RegisterStoreDecoder registers a decoder for gov module's types -func (AppModuleSimulation) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { - sdr[StoreKey] = simulation.DecodeStore -} - -// GenerateGenesisState creates a randomized GenState of the gov module. -func (AppModuleSimulation) GenerateGenesisState(simState *module.SimulationState) { - simulation.RandomizedGenState(simState) -} - -// RandomizedParams creates randomized gov param changes for the simulator. -func (AppModuleSimulation) RandomizedParams(r *rand.Rand) []sim.ParamChange { - return simulation.ParamChanges(r) -} - -//____________________________________________________________________________ - // AppModule implements an application module for the gov module. type AppModule struct { AppModuleBasic - AppModuleSimulation - keeper Keeper - supplyKeeper types.SupplyKeeper + keeper Keeper + accountKeeper types.AccountKeeper + supplyKeeper types.SupplyKeeper } // NewAppModule creates a new AppModule object -func NewAppModule(keeper Keeper, supplyKeeper types.SupplyKeeper) AppModule { +func NewAppModule(keeper Keeper, accountKeeper types.AccountKeeper, supplyKeeper types.SupplyKeeper) AppModule { return AppModule{ - AppModuleBasic: AppModuleBasic{}, - AppModuleSimulation: AppModuleSimulation{}, - keeper: keeper, - supplyKeeper: supplyKeeper, + AppModuleBasic: AppModuleBasic{}, + keeper: keeper, + accountKeeper: accountKeeper, + supplyKeeper: supplyKeeper, } } @@ -189,3 +169,35 @@ func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.Val EndBlocker(ctx, am.keeper) return []abci.ValidatorUpdate{} } + +//____________________________________________________________________________ + +// AppModuleSimulation functions + +// GenerateGenesisState creates a randomized GenState of the gov module. +func (AppModule) GenerateGenesisState(simState *module.SimulationState) { + simulation.RandomizedGenState(simState) +} + +// ProposalContents returns all the gov content functions used to +// simulate governance proposals. +func (AppModule) ProposalContents(_ module.SimulationState) []sim.WeightedProposalContent { + return simulation.ProposalContents() +} + +// RandomizedParams creates randomized gov param changes for the simulator. +func (AppModule) RandomizedParams(r *rand.Rand) []sim.ParamChange { + return simulation.ParamChanges(r) +} + +// RegisterStoreDecoder registers a decoder for gov module's types +func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { + sdr[StoreKey] = simulation.DecodeStore +} + +// WeightedOperations returns the all the gov module operations with their respective weights. +func (am AppModule) WeightedOperations(simState module.SimulationState) []sim.WeightedOperation { + return simulation.WeightedOperations( + simState.AppParams, simState.Cdc, + am.accountKeeper, am.keeper, simState.Contents) +} diff --git a/x/gov/simulation/operations.go b/x/gov/simulation/operations.go index ddabe9c238b9..4d33d82bc86c 100644 --- a/x/gov/simulation/operations.go +++ b/x/gov/simulation/operations.go @@ -7,7 +7,9 @@ import ( "time" "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/simapp/helpers" + simappparams "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/gov/keeper" "github.com/cosmos/cosmos-sdk/x/gov/types" @@ -16,16 +18,72 @@ import ( var initialProposalID = uint64(100000000000000) -// ContentSimulator defines a function type alias for generating random proposal -// content. -type ContentSimulator func(r *rand.Rand, ctx sdk.Context, accs []simulation.Account) types.Content +// Simulation operation weights constants +const ( + OpWeightMsgDeposit = "op_weight_msg_deposit" + OpWeightMsgVote = "op_weight_msg_vote" +) + +// WeightedOperations returns all the operations from the module with their respective weights +func WeightedOperations(appParams simulation.AppParams, cdc *codec.Codec, ak types.AccountKeeper, + k keeper.Keeper, wContents []simulation.WeightedProposalContent) simulation.WeightedOperations { + + var ( + weightMsgDeposit int + weightMsgVote int + ) + + appParams.GetOrGenerate(cdc, OpWeightMsgDeposit, &weightMsgDeposit, nil, + func(_ *rand.Rand) { + weightMsgDeposit = simappparams.DefaultWeightMsgDeposit + }, + ) + + appParams.GetOrGenerate(cdc, OpWeightMsgVote, &weightMsgVote, nil, + func(_ *rand.Rand) { + weightMsgVote = simappparams.DefaultWeightMsgVote + }, + ) + + // generate the weighted operations for the proposal contents + var wProposalOps simulation.WeightedOperations + + for _, wContent := range wContents { + wContent := wContent // pin variable + var weight int + appParams.GetOrGenerate(cdc, wContent.AppParamsKey, &weight, nil, + func(_ *rand.Rand) { weight = wContent.DefaultWeight }) + + wProposalOps = append( + wProposalOps, + simulation.NewWeightedOperation( + weight, + SimulateSubmitProposal(ak, k, wContent.ContentSimulatorFn), + ), + ) + } + + wGovOps := simulation.WeightedOperations{ + simulation.NewWeightedOperation( + weightMsgDeposit, + SimulateMsgDeposit(ak, k), + ), + simulation.NewWeightedOperation( + weightMsgVote, + SimulateMsgVote(ak, k), + ), + } + + return append(wProposalOps, wGovOps...) +} // SimulateSubmitProposal simulates creating a msg Submit Proposal // voting on the proposal, and subsequently slashing the proposal. It is implemented using // future operations. // nolint: funlen -func SimulateSubmitProposal(ak types.AccountKeeper, k keeper.Keeper, - contentSim ContentSimulator) simulation.Operation { +func SimulateSubmitProposal( + ak types.AccountKeeper, k keeper.Keeper, contentSim simulation.ContentSimulatorFn, +) simulation.Operation { // The states are: // column 1: All validators vote // column 2: 90% vote @@ -127,14 +185,6 @@ func SimulateSubmitProposal(ak types.AccountKeeper, k keeper.Keeper, } } -// SimulateTextProposalContent returns random text proposal content. -func SimulateTextProposalContent(r *rand.Rand, _ sdk.Context, _ []simulation.Account) types.Content { - return types.NewTextProposal( - simulation.RandStringOfLength(r, 140), - simulation.RandStringOfLength(r, 5000), - ) -} - // SimulateMsgDeposit generates a MsgDeposit with random values. // nolint: funlen func SimulateMsgDeposit(ak types.AccountKeeper, k keeper.Keeper) simulation.Operation { diff --git a/x/gov/simulation/proposals.go b/x/gov/simulation/proposals.go new file mode 100644 index 000000000000..b3d73d15c349 --- /dev/null +++ b/x/gov/simulation/proposals.go @@ -0,0 +1,32 @@ +package simulation + +import ( + "math/rand" + + simappparams "github.com/cosmos/cosmos-sdk/simapp/params" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/cosmos-sdk/x/simulation" +) + +// OpWeightSubmitTextProposal app params key for text proposal +const OpWeightSubmitTextProposal = "op_weight_submit_text_proposal" + +// ProposalContents defines the module weighted proposals' contents +func ProposalContents() []simulation.WeightedProposalContent { + return []simulation.WeightedProposalContent{ + { + AppParamsKey: OpWeightSubmitTextProposal, + DefaultWeight: simappparams.DefaultWeightTextProposal, + ContentSimulatorFn: SimulateTextProposalContent, + }, + } +} + +// SimulateTextProposalContent returns a random text proposal content. +func SimulateTextProposalContent(r *rand.Rand, _ sdk.Context, _ []simulation.Account) types.Content { + return types.NewTextProposal( + simulation.RandStringOfLength(r, 140), + simulation.RandStringOfLength(r, 5000), + ) +} diff --git a/x/mint/module.go b/x/mint/module.go index 115150dc9eaa..f0e36e1693d7 100644 --- a/x/mint/module.go +++ b/x/mint/module.go @@ -22,7 +22,7 @@ import ( var ( _ module.AppModule = AppModule{} _ module.AppModuleBasic = AppModuleBasic{} - _ module.AppModuleSimulation = AppModuleSimulation{} + _ module.AppModuleSimulation = AppModule{} ) // AppModuleBasic defines the basic application module used by the mint module. @@ -69,30 +69,9 @@ func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { //____________________________________________________________________________ -// AppModuleSimulation defines the module simulation functions used by the mint module. -type AppModuleSimulation struct{} - -// RegisterStoreDecoder registers a decoder for mint module's types. -func (AppModuleSimulation) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { - sdr[StoreKey] = simulation.DecodeStore -} - -// GenerateGenesisState creates a randomized GenState of the mint module. -func (AppModuleSimulation) GenerateGenesisState(simState *module.SimulationState) { - simulation.RandomizedGenState(simState) -} - -// RandomizedParams creates randomized mint param changes for the simulator. -func (AppModuleSimulation) RandomizedParams(r *rand.Rand) []sim.ParamChange { - return simulation.ParamChanges(r) -} - -//____________________________________________________________________________ - // AppModule implements an application module for the mint module. type AppModule struct { AppModuleBasic - AppModuleSimulation keeper Keeper } @@ -100,9 +79,8 @@ type AppModule struct { // NewAppModule creates a new AppModule object func NewAppModule(keeper Keeper) AppModule { return AppModule{ - AppModuleBasic: AppModuleBasic{}, - AppModuleSimulation: AppModuleSimulation{}, - keeper: keeper, + AppModuleBasic: AppModuleBasic{}, + keeper: keeper, } } @@ -156,3 +134,32 @@ func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) { func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { return []abci.ValidatorUpdate{} } + +//____________________________________________________________________________ + +// AppModuleSimulation functions + +// GenerateGenesisState creates a randomized GenState of the mint module. +func (AppModule) GenerateGenesisState(simState *module.SimulationState) { + simulation.RandomizedGenState(simState) +} + +// ProposalContents doesn't return any content functions for governance proposals. +func (AppModule) ProposalContents(_ module.SimulationState) []sim.WeightedProposalContent { + return nil +} + +// RandomizedParams creates randomized mint param changes for the simulator. +func (AppModule) RandomizedParams(r *rand.Rand) []sim.ParamChange { + return simulation.ParamChanges(r) +} + +// RegisterStoreDecoder registers a decoder for mint module's types. +func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { + sdr[StoreKey] = simulation.DecodeStore +} + +// WeightedOperations doesn't return any mint module operation. +func (AppModule) WeightedOperations(_ module.SimulationState) []sim.WeightedOperation { + return nil +} diff --git a/x/params/module.go b/x/params/module.go index 38b93bd5f00c..5817b482b3b8 100644 --- a/x/params/module.go +++ b/x/params/module.go @@ -2,18 +2,23 @@ package params import ( "encoding/json" + "math/rand" "github.com/gorilla/mux" "github.com/spf13/cobra" "github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/x/params/simulation" "github.com/cosmos/cosmos-sdk/x/params/types" + sim "github.com/cosmos/cosmos-sdk/x/simulation" ) var ( - _ module.AppModuleBasic = AppModuleBasic{} + _ module.AppModuleBasic = AppModuleBasic{} + _ module.AppModuleSimulation = AppModule{} ) // AppModuleBasic defines the basic application module used by the params module. @@ -44,3 +49,44 @@ func (AppModuleBasic) GetTxCmd(_ *codec.Codec) *cobra.Command { return nil } // GetQueryCmd returns no root query command for the params module. func (AppModuleBasic) GetQueryCmd(_ *codec.Codec) *cobra.Command { return nil } + +//____________________________________________________________________________ + +// AppModule implements an application module for the distribution module. +type AppModule struct { + AppModuleBasic +} + +// NewAppModule creates a new AppModule object +func NewAppModule() AppModule { + return AppModule{ + AppModuleBasic: AppModuleBasic{}, + } +} + +//____________________________________________________________________________ + +// AppModuleSimulation functions + +// GenerateGenesisState performs a no-op. +func (AppModule) GenerateGenesisState(simState *module.SimulationState) { +} + +// ProposalContents returns all the params content functions used to +// simulate governance proposals. +func (am AppModule) ProposalContents(simState module.SimulationState) []sim.WeightedProposalContent { + return simulation.ProposalContents(simState.ParamChanges) +} + +// RandomizedParams creates randomized distribution param changes for the simulator. +func (AppModule) RandomizedParams(r *rand.Rand) []sim.ParamChange { + return nil +} + +// RegisterStoreDecoder doesn't register any type. +func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) {} + +// WeightedOperations returns the all the gov module operations with their respective weights. +func (am AppModule) WeightedOperations(_ module.SimulationState) []sim.WeightedOperation { + return nil +} diff --git a/x/params/simulation/operations.go b/x/params/simulation/operations.go index 0e2516c5fbe4..ab514e06fec0 100644 --- a/x/params/simulation/operations.go +++ b/x/params/simulation/operations.go @@ -4,16 +4,15 @@ import ( "math/rand" sdk "github.com/cosmos/cosmos-sdk/types" - govsim "github.com/cosmos/cosmos-sdk/x/gov/simulation" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - "github.com/cosmos/cosmos-sdk/x/params" + "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/cosmos/cosmos-sdk/x/simulation" ) // SimulateParamChangeProposalContent returns random parameter change content. // It will generate a ParameterChangeProposal object with anywhere between 1 and // the total amount of defined parameters changes, all of which have random valid values. -func SimulateParamChangeProposalContent(paramChangePool []simulation.ParamChange) govsim.ContentSimulator { +func SimulateParamChangeProposalContent(paramChangePool []simulation.ParamChange) simulation.ContentSimulatorFn { return func(r *rand.Rand, _ sdk.Context, _ []simulation.Account) govtypes.Content { lenParamChange := len(paramChangePool) @@ -22,7 +21,7 @@ func SimulateParamChangeProposalContent(paramChangePool []simulation.ParamChange } numChanges := simulation.RandIntBetween(r, 1, lenParamChange) - paramChanges := make([]params.ParamChange, numChanges) + paramChanges := make([]types.ParamChange, numChanges) // map from key to empty struct; used only for look-up of the keys of the // parameters that are already in the random set of changes. @@ -41,10 +40,10 @@ func SimulateParamChangeProposalContent(paramChangePool []simulation.ParamChange // add a new distinct parameter to the set of changes and register the key // to avoid further duplicates paramChangesKeys[spc.ComposedKey()] = struct{}{} - paramChanges[i] = params.NewParamChangeWithSubkey(spc.Subspace, spc.Key, spc.Subkey, spc.SimValue(r)) + paramChanges[i] = types.NewParamChangeWithSubkey(spc.Subspace, spc.Key, spc.Subkey, spc.SimValue(r)) } - return params.NewParameterChangeProposal( + return types.NewParameterChangeProposal( simulation.RandStringOfLength(r, 140), // title simulation.RandStringOfLength(r, 5000), // description paramChanges, // set of changes diff --git a/x/params/simulation/proposals.go b/x/params/simulation/proposals.go new file mode 100644 index 000000000000..ad1c37dd88b7 --- /dev/null +++ b/x/params/simulation/proposals.go @@ -0,0 +1,20 @@ +package simulation + +import ( + simappparams "github.com/cosmos/cosmos-sdk/simapp/params" + "github.com/cosmos/cosmos-sdk/x/simulation" +) + +// OpWeightSubmitParamChangeProposal app params key for param change proposal +const OpWeightSubmitParamChangeProposal = "op_weight_submit_param_change_proposal" + +// ProposalContents defines the module weighted proposals' contents +func ProposalContents(paramChanges []simulation.ParamChange) []simulation.WeightedProposalContent { + return []simulation.WeightedProposalContent{ + { + AppParamsKey: OpWeightSubmitParamChangeProposal, + DefaultWeight: simappparams.DefaultWeightParamChangeProposal, + ContentSimulatorFn: SimulateParamChangeProposalContent(paramChanges), + }, + } +} diff --git a/x/simulation/operation.go b/x/simulation/operation.go index d7eaf9cfe9b5..8565b42961d7 100644 --- a/x/simulation/operation.go +++ b/x/simulation/operation.go @@ -199,6 +199,14 @@ type WeightedOperation struct { Op Operation } +// NewWeightedOperation creates a new WeightedOperation instance +func NewWeightedOperation(weight int, op Operation) WeightedOperation { + return WeightedOperation{ + Weight: weight, + Op: op, + } +} + // WeightedOperations is the group of all weighted operations to simulate. type WeightedOperations []WeightedOperation diff --git a/x/simulation/params.go b/x/simulation/params.go index e2bbcfcca055..d3e2af44f15c 100644 --- a/x/simulation/params.go +++ b/x/simulation/params.go @@ -6,6 +6,8 @@ import ( "math/rand" "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" ) const ( @@ -45,7 +47,8 @@ type ParamSimulator func(r *rand.Rand) // GetOrGenerate attempts to get a given parameter by key from the AppParams // object. If it exists, it'll be decoded and returned. Otherwise, the provided -// ParamSimulator is used to generate a random value. +// ParamSimulator is used to generate a random value or default value (eg: in the +// case of operation weights where Rand is not used). func (sp AppParams) GetOrGenerate(cdc *codec.Codec, key string, ptr interface{}, r *rand.Rand, ps ParamSimulator) { if v, ok := sp[key]; ok && v != nil { cdc.MustUnmarshalJSON(v, ptr) @@ -55,6 +58,10 @@ func (sp AppParams) GetOrGenerate(cdc *codec.Codec, key string, ptr interface{}, ps(r) } +// ContentSimulatorFn defines a function type alias for generating random proposal +// content. +type ContentSimulatorFn func(r *rand.Rand, ctx sdk.Context, accs []Account) govtypes.Content + // Params define the parameters necessary for running the simulations type Params struct { PastEvidenceFraction float64 @@ -65,7 +72,7 @@ type Params struct { BlockSizeTransitionMatrix TransitionMatrix } -// RandomParams for simulation +// RandomParams returns random simulation parameters func RandomParams(r *rand.Rand) Params { return Params{ PastEvidenceFraction: r.Float64(), @@ -105,3 +112,14 @@ func NewSimParamChange(subspace, key, subkey string, simVal SimValFn) ParamChang func (spc ParamChange) ComposedKey() string { return fmt.Sprintf("%s/%s/%s", spc.Subspace, spc.Key, spc.Subkey) } + +//----------------------------------------------------------------------------- +// Proposal Contents + +// WeightedProposalContent defines a common struct for proposal contents defined by +// external modules (i.e outside gov) +type WeightedProposalContent struct { + AppParamsKey string // key used to retrieve the value of the weight from the simulation application params + DefaultWeight int // default weight + ContentSimulatorFn ContentSimulatorFn // content simulator function +} diff --git a/x/slashing/module.go b/x/slashing/module.go index 9a179b67d931..47d15cf89937 100644 --- a/x/slashing/module.go +++ b/x/slashing/module.go @@ -18,12 +18,13 @@ import ( "github.com/cosmos/cosmos-sdk/x/slashing/client/rest" "github.com/cosmos/cosmos-sdk/x/slashing/internal/types" "github.com/cosmos/cosmos-sdk/x/slashing/simulation" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" ) var ( _ module.AppModule = AppModule{} _ module.AppModuleBasic = AppModuleBasic{} - _ module.AppModuleSimulation = AppModuleSimulation{} + _ module.AppModuleSimulation = AppModule{} ) // AppModuleBasic defines the basic application module used by the slashing module. @@ -74,42 +75,22 @@ func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { //____________________________________________________________________________ -// AppModuleSimulation defines the module simulation functions used by the slashing module. -type AppModuleSimulation struct{} - -// RegisterStoreDecoder registers a decoder for slashing module's types -func (AppModuleSimulation) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { - sdr[StoreKey] = simulation.DecodeStore -} - -// GenerateGenesisState creates a randomized GenState of the slashing module. -func (AppModuleSimulation) GenerateGenesisState(simState *module.SimulationState) { - simulation.RandomizedGenState(simState) -} - -// RandomizedParams creates randomized slashing param changes for the simulator. -func (AppModuleSimulation) RandomizedParams(r *rand.Rand) []sim.ParamChange { - return simulation.ParamChanges(r) -} - -//____________________________________________________________________________ - // AppModule implements an application module for the slashing module. type AppModule struct { AppModuleBasic - AppModuleSimulation keeper Keeper - stakingKeeper types.StakingKeeper + accountKeeper types.AccountKeeper + stakingKeeper stakingkeeper.Keeper } // NewAppModule creates a new AppModule object -func NewAppModule(keeper Keeper, stakingKeeper types.StakingKeeper) AppModule { +func NewAppModule(keeper Keeper, accountKeeper types.AccountKeeper, stakingKeeper stakingkeeper.Keeper) AppModule { return AppModule{ - AppModuleBasic: AppModuleBasic{}, - AppModuleSimulation: AppModuleSimulation{}, - keeper: keeper, - stakingKeeper: stakingKeeper, + AppModuleBasic: AppModuleBasic{}, + keeper: keeper, + accountKeeper: accountKeeper, + stakingKeeper: stakingKeeper, } } @@ -167,3 +148,33 @@ func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) { func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { return []abci.ValidatorUpdate{} } + +//____________________________________________________________________________ + +// AppModuleSimulation functions + +// GenerateGenesisState creates a randomized GenState of the slashing module. +func (AppModule) GenerateGenesisState(simState *module.SimulationState) { + simulation.RandomizedGenState(simState) +} + +// ProposalContents doesn't return any content functions for governance proposals. +func (AppModule) ProposalContents(_ module.SimulationState) []sim.WeightedProposalContent { + return nil +} + +// RandomizedParams creates randomized slashing param changes for the simulator. +func (AppModule) RandomizedParams(r *rand.Rand) []sim.ParamChange { + return simulation.ParamChanges(r) +} + +// RegisterStoreDecoder registers a decoder for slashing module's types +func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { + sdr[StoreKey] = simulation.DecodeStore +} + +// WeightedOperations returns the all the slashing module operations with their respective weights. +func (am AppModule) WeightedOperations(simState module.SimulationState) []sim.WeightedOperation { + return simulation.WeightedOperations(simState.AppParams, simState.Cdc, + am.accountKeeper, am.keeper, am.stakingKeeper) +} diff --git a/x/slashing/simulation/operations.go b/x/slashing/simulation/operations.go index e7b4c6870ac2..992513c924d8 100644 --- a/x/slashing/simulation/operations.go +++ b/x/slashing/simulation/operations.go @@ -5,7 +5,9 @@ import ( "math/rand" "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/simapp/helpers" + simappparams "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/simulation" "github.com/cosmos/cosmos-sdk/x/slashing/internal/keeper" @@ -13,6 +15,32 @@ import ( stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" ) +// Simulation operation weights constants +const ( + OpWeightMsgUnjail = "op_weight_msg_unjail" +) + +// WeightedOperations returns all the operations from the module with their respective weights +func WeightedOperations( + appParams simulation.AppParams, cdc *codec.Codec, ak types.AccountKeeper, + k keeper.Keeper, sk stakingkeeper.Keeper, +) simulation.WeightedOperations { + + var weightMsgUnjail int + appParams.GetOrGenerate(cdc, OpWeightMsgUnjail, &weightMsgUnjail, nil, + func(_ *rand.Rand) { + weightMsgUnjail = simappparams.DefaultWeightMsgUnjail + }, + ) + + return simulation.WeightedOperations{ + simulation.NewWeightedOperation( + weightMsgUnjail, + SimulateMsgUnjail(ak, k, sk), + ), + } +} + // SimulateMsgUnjail generates a MsgUnjail with random values // nolint: funlen func SimulateMsgUnjail(ak types.AccountKeeper, k keeper.Keeper, sk stakingkeeper.Keeper) simulation.Operation { diff --git a/x/staking/module.go b/x/staking/module.go index 75833037d76b..45a06e67244a 100644 --- a/x/staking/module.go +++ b/x/staking/module.go @@ -27,7 +27,7 @@ import ( var ( _ module.AppModule = AppModule{} _ module.AppModuleBasic = AppModuleBasic{} - _ module.AppModuleSimulation = AppModuleSimulation{} + _ module.AppModuleSimulation = AppModule{} ) // AppModuleBasic defines the basic application module used by the staking module. @@ -99,30 +99,9 @@ func (AppModuleBasic) BuildCreateValidatorMsg(cliCtx context.CLIContext, //____________________________________________________________________________ -// AppModuleSimulation defines the module simulation functions used by the staking module. -type AppModuleSimulation struct{} - -// RegisterStoreDecoder registers a decoder for staking module's types -func (AppModuleSimulation) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { - sdr[StoreKey] = simulation.DecodeStore -} - -// GenerateGenesisState creates a randomized GenState of the staking module. -func (AppModuleSimulation) GenerateGenesisState(simState *module.SimulationState) { - simulation.RandomizedGenState(simState) -} - -// RandomizedParams creates randomized staking param changes for the simulator. -func (AppModuleSimulation) RandomizedParams(r *rand.Rand) []sim.ParamChange { - return simulation.ParamChanges(r) -} - -//____________________________________________________________________________ - // AppModule implements an application module for the staking module. type AppModule struct { AppModuleBasic - AppModuleSimulation keeper Keeper accountKeeper types.AccountKeeper @@ -133,11 +112,10 @@ type AppModule struct { func NewAppModule(keeper Keeper, accountKeeper types.AccountKeeper, supplyKeeper types.SupplyKeeper) AppModule { return AppModule{ - AppModuleBasic: AppModuleBasic{}, - AppModuleSimulation: AppModuleSimulation{}, - keeper: keeper, - accountKeeper: accountKeeper, - supplyKeeper: supplyKeeper, + AppModuleBasic: AppModuleBasic{}, + keeper: keeper, + accountKeeper: accountKeeper, + supplyKeeper: supplyKeeper, } } @@ -194,3 +172,33 @@ func (AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { return EndBlocker(ctx, am.keeper) } + +//____________________________________________________________________________ + +// AppModuleSimulation functions + +// GenerateGenesisState creates a randomized GenState of the staking module. +func (AppModule) GenerateGenesisState(simState *module.SimulationState) { + simulation.RandomizedGenState(simState) +} + +// ProposalContents doesn't return any content functions for governance proposals. +func (AppModule) ProposalContents(_ module.SimulationState) []sim.WeightedProposalContent { + return nil +} + +// RandomizedParams creates randomized staking param changes for the simulator. +func (AppModule) RandomizedParams(r *rand.Rand) []sim.ParamChange { + return simulation.ParamChanges(r) +} + +// RegisterStoreDecoder registers a decoder for staking module's types +func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { + sdr[StoreKey] = simulation.DecodeStore +} + +// WeightedOperations returns the all the staking module operations with their respective weights. +func (am AppModule) WeightedOperations(simState module.SimulationState) []sim.WeightedOperation { + return simulation.WeightedOperations(simState.AppParams, simState.Cdc, + am.accountKeeper, am.keeper) +} diff --git a/x/staking/simulation/operations.go b/x/staking/simulation/operations.go index 71513bb19bd3..d2b2cab87d04 100644 --- a/x/staking/simulation/operations.go +++ b/x/staking/simulation/operations.go @@ -6,13 +6,92 @@ import ( "math/rand" "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/simapp/helpers" + simappparams "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/simulation" "github.com/cosmos/cosmos-sdk/x/staking/keeper" "github.com/cosmos/cosmos-sdk/x/staking/types" ) +// Simulation operation weights constants +const ( + OpWeightMsgCreateValidator = "op_weight_msg_create_validator" + OpWeightMsgEditValidator = "op_weight_msg_edit_validator" + OpWeightMsgDelegate = "op_weight_msg_delegate" + OpWeightMsgUndelegate = "op_weight_msg_undelegate" + OpWeightMsgBeginRedelegate = "op_weight_msg_begin_redelegate" +) + +// WeightedOperations returns all the operations from the module with their respective weights +func WeightedOperations( + appParams simulation.AppParams, cdc *codec.Codec, ak types.AccountKeeper, + k keeper.Keeper, +) simulation.WeightedOperations { + + var ( + weightMsgCreateValidator int + weightMsgEditValidator int + weightMsgDelegate int + weightMsgUndelegate int + weightMsgBeginRedelegate int + ) + + appParams.GetOrGenerate(cdc, OpWeightMsgCreateValidator, &weightMsgCreateValidator, nil, + func(_ *rand.Rand) { + weightMsgCreateValidator = simappparams.DefaultWeightMsgCreateValidator + }, + ) + + appParams.GetOrGenerate(cdc, OpWeightMsgEditValidator, &weightMsgEditValidator, nil, + func(_ *rand.Rand) { + weightMsgEditValidator = simappparams.DefaultWeightMsgEditValidator + }, + ) + + appParams.GetOrGenerate(cdc, OpWeightMsgDelegate, &weightMsgDelegate, nil, + func(_ *rand.Rand) { + weightMsgDelegate = simappparams.DefaultWeightMsgDelegate + }, + ) + + appParams.GetOrGenerate(cdc, OpWeightMsgUndelegate, &weightMsgUndelegate, nil, + func(_ *rand.Rand) { + weightMsgUndelegate = simappparams.DefaultWeightMsgUndelegate + }, + ) + + appParams.GetOrGenerate(cdc, OpWeightMsgBeginRedelegate, &weightMsgBeginRedelegate, nil, + func(_ *rand.Rand) { + weightMsgBeginRedelegate = simappparams.DefaultWeightMsgBeginRedelegate + }, + ) + + return simulation.WeightedOperations{ + simulation.NewWeightedOperation( + weightMsgCreateValidator, + SimulateMsgCreateValidator(ak, k), + ), + simulation.NewWeightedOperation( + weightMsgEditValidator, + SimulateMsgEditValidator(ak, k), + ), + simulation.NewWeightedOperation( + weightMsgDelegate, + SimulateMsgDelegate(ak, k), + ), + simulation.NewWeightedOperation( + weightMsgUndelegate, + SimulateMsgUndelegate(ak, k), + ), + simulation.NewWeightedOperation( + weightMsgBeginRedelegate, + SimulateMsgBeginRedelegate(ak, k), + ), + } +} + // SimulateMsgCreateValidator generates a MsgCreateValidator with random values // nolint: funlen func SimulateMsgCreateValidator(ak types.AccountKeeper, k keeper.Keeper) simulation.Operation { diff --git a/x/supply/module.go b/x/supply/module.go index 6c14e8d892cd..307b77865b36 100644 --- a/x/supply/module.go +++ b/x/supply/module.go @@ -70,30 +70,9 @@ func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { //____________________________________________________________________________ -// AppModuleSimulation defines the module simulation functions used by the supply module. -type AppModuleSimulation struct{} - -// RegisterStoreDecoder registers a decoder for supply module's types -func (AppModuleSimulation) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { - sdr[StoreKey] = simulation.DecodeStore -} - -// GenerateGenesisState creates a randomized GenState of the supply module. -func (AppModuleSimulation) GenerateGenesisState(simState *module.SimulationState) { - simulation.RandomizedGenState(simState) -} - -// RandomizedParams doesn't create any randomized supply param changes for the simulator. -func (AppModuleSimulation) RandomizedParams(_ *rand.Rand) []sim.ParamChange { - return nil -} - -//____________________________________________________________________________ - // AppModule implements an application module for the supply module. type AppModule struct { AppModuleBasic - AppModuleSimulation keeper Keeper ak types.AccountKeeper @@ -102,10 +81,9 @@ type AppModule struct { // NewAppModule creates a new AppModule object func NewAppModule(keeper Keeper, ak types.AccountKeeper) AppModule { return AppModule{ - AppModuleBasic: AppModuleBasic{}, - AppModuleSimulation: AppModuleSimulation{}, - keeper: keeper, - ak: ak, + AppModuleBasic: AppModuleBasic{}, + keeper: keeper, + ak: ak, } } @@ -161,3 +139,32 @@ func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { return []abci.ValidatorUpdate{} } + +//____________________________________________________________________________ + +// AppModuleSimulation functions + +// GenerateGenesisState creates a randomized GenState of the supply module. +func (AppModule) GenerateGenesisState(simState *module.SimulationState) { + simulation.RandomizedGenState(simState) +} + +// ProposalContents doesn't return any content functions for governance proposals. +func (AppModule) ProposalContents(_ module.SimulationState) []sim.WeightedProposalContent { + return nil +} + +// RandomizedParams doesn't create any randomized supply param changes for the simulator. +func (AppModule) RandomizedParams(_ *rand.Rand) []sim.ParamChange { + return nil +} + +// RegisterStoreDecoder registers a decoder for supply module's types +func (AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) { + sdr[StoreKey] = simulation.DecodeStore +} + +// WeightedOperations doesn't return any operation for the nft module. +func (AppModule) WeightedOperations(_ module.SimulationState) []sim.WeightedOperation { + return nil +}