diff --git a/CHANGELOG.md b/CHANGELOG.md index 48a0d9bb192a..479145c22569 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -168,10 +168,11 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking Changes +* (simulation) [#14728](https://github.com/cosmos/cosmos-sdk/pull/14728) Rename the `ParamChanges` field to `LegacyParamChange` and `Contents` to `LegacyProposalContents` in `simulation.SimulationState`. Additionally it adds a `ProposalMsgs` field to `simulation.SimulationState`. * (x/upgrade) [14764](https://github.com/cosmos/cosmos-sdk/pull/14764) The `x/upgrade` module is extracted to have a separate go.mod file which allows it to be a standalone module. * (x/gov) [#14782](https://github.com/cosmos/cosmos-sdk/pull/14782) Move the `metadata` argument in `govv1.NewProposal` alongside `title` and `summary`. * (store) [#14746](https://github.com/cosmos/cosmos-sdk/pull/14746) Extract Store in its own go.mod and rename the package to `cosmossdk.io/store`. -* (x/simulation) [#14751](https://github.com/cosmos/cosmos-sdk/pull/14751) Remove the `MsgType` field from `simulation.OperationInput` struct. +* (simulation) [#14751](https://github.com/cosmos/cosmos-sdk/pull/14751) Remove the `MsgType` field from `simulation.OperationInput` struct. * (crypto/keyring) [#13734](https://github.com/cosmos/cosmos-sdk/pull/13834) The keyring's `Sign` method now takes a new `signMode` argument. It is only used if the signing key is a Ledger hardware device. You can set it to 0 in all other cases. * (x/evidence) [14724](https://github.com/cosmos/cosmos-sdk/pull/14724) Extract Evidence in its own go.mod and rename the package to `cosmossdk.io/x/evidence`. * (x/nft) [#14725](https://github.com/cosmos/cosmos-sdk/pull/14725) Extract NFT in its own go.mod and rename the package to `cosmossdk.io/x/nft`. diff --git a/UPGRADING.md b/UPGRADING.md index 99971856bc00..b8d5d116ae84 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -101,6 +101,10 @@ All the upgrade imports are now renamed to use `cosmossdk.io/x/upgrade` instead Remove `RandomizedParams` from `AppModuleSimulation` interface. Previously, it used to generate random parameter changes during simulations, however, it does so through ParamChangeProposal which is now legacy. Since all modules were migrated, we can now safely remove this from `AppModuleSimulation` interface. +Moreover, to support the `MsgUpdateParams` governance proposals for each modules, `AppModuleSimulation` now defines a `AppModule.ProposalMsgs` method in addition to `AppModule.ProposalContents`. That method defines the messages that can be used to submit a proposal and that should be tested in simulation. + +When a module has no proposal messages or proposal content to be tested by simulation, the `AppModule.ProposalMsgs` and `AppModule.ProposalContents` methods can be deleted. + ### gRPC A new gRPC service, `proto/cosmos/base/node/v1beta1/query.proto`, has been introduced diff --git a/testutil/sims/simulation_helpers.go b/testutil/sims/simulation_helpers.go index dc4e7f3405d8..059c9aada434 100644 --- a/testutil/sims/simulation_helpers.go +++ b/testutil/sims/simulation_helpers.go @@ -68,7 +68,8 @@ func SimulationOperations(app runtime.AppI, cdc codec.JSONCodec, config simtypes } } - simState.Contents = app.SimulationManager().GetProposalContents(simState) + simState.LegacyProposalContents = app.SimulationManager().GetProposalContents(simState) //nolint:staticcheck + simState.ProposalMsgs = app.SimulationManager().GetProposalMsgs(simState) return app.SimulationManager().WeightedOperations(simState) } diff --git a/types/module/simulation.go b/types/module/simulation.go index d742a6639498..036ef3a9f755 100644 --- a/types/module/simulation.go +++ b/types/module/simulation.go @@ -17,9 +17,6 @@ type AppModuleSimulation interface { // randomized genesis states GenerateGenesisState(input *SimulationState) - // content functions used to simulate governance proposals - ProposalContents(simState SimulationState) []simulation.WeightedProposalContent - // register a func to decode the each module's defined types from their corresponding store key RegisterStoreDecoder(simulation.StoreDecoderRegistry) @@ -27,6 +24,18 @@ type AppModuleSimulation interface { WeightedOperations(simState SimulationState) []simulation.WeightedOperation } +// HasProposalMsgs defines the messages that can be used to simulate governance (v1) proposals +type HasProposalMsgs interface { + // msg functions used to simulate governance proposals + ProposalMsgs(simState SimulationState) []simulation.WeightedProposalMsg +} + +// HasProposalContents defines the contents that can be used to simulate legacy governance (v1beta1) proposals +type HasProposalContents interface { + // content functions used to simulate governance proposals + ProposalContents(simState SimulationState) []simulation.WeightedProposalContent //nolint:staticcheck +} + // SimulationManager defines a simulation manager that provides the high level utility // for managing and executing simulation functionalities for a group of modules type SimulationManager struct { @@ -76,12 +85,28 @@ func NewSimulationManagerFromAppModules(modules map[string]interface{}, override return NewSimulationManager(simModules...) } +// Deprecated: Use GetProposalMsgs instead. // GetProposalContents returns each module's proposal content generator function // with their default operation weight and key. func (sm *SimulationManager) GetProposalContents(simState SimulationState) []simulation.WeightedProposalContent { wContents := make([]simulation.WeightedProposalContent, 0, len(sm.Modules)) for _, module := range sm.Modules { - wContents = append(wContents, module.ProposalContents(simState)...) + if module, ok := module.(HasProposalContents); ok { + wContents = append(wContents, module.ProposalContents(simState)...) + } + } + + return wContents +} + +// GetProposalMsgs returns each module's proposal msg generator function +// with their default operation weight and key. +func (sm *SimulationManager) GetProposalMsgs(simState SimulationState) []simulation.WeightedProposalMsg { + wContents := make([]simulation.WeightedProposalMsg, 0, len(sm.Modules)) + for _, module := range sm.Modules { + if module, ok := module.(HasProposalMsgs); ok { + wContents = append(wContents, module.ProposalMsgs(simState)...) + } } return wContents @@ -115,16 +140,18 @@ func (sm *SimulationManager) WeightedOperations(simState SimulationState) []simu // SimulationState is the input parameters used on each of the module's randomized // GenesisState generator function type SimulationState struct { - AppParams simulation.AppParams - Cdc codec.JSONCodec // application codec - Rand *rand.Rand // random number - GenState map[string]json.RawMessage // genesis state - Accounts []simulation.Account // simulation accounts - InitialStake sdkmath.Int // initial coins per account - NumBonded int64 // number of initially bonded accounts - BondDenom string // denom to be used as default - 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 + AppParams simulation.AppParams + Cdc codec.JSONCodec // application codec + Rand *rand.Rand // random number + GenState map[string]json.RawMessage // genesis state + Accounts []simulation.Account // simulation accounts + InitialStake sdkmath.Int // initial coins per account + NumBonded int64 // number of initially bonded accounts + BondDenom string // denom to be used as default + GenTimestamp time.Time // genesis timestamp + UnbondTime time.Duration // staking unbond time stored to use it as the slashing maximum evidence duration + LegacyParamChange []simulation.LegacyParamChange // simulated parameter changes from modules + //nolint:staticcheck + LegacyProposalContents []simulation.WeightedProposalContent // proposal content generator functions with their default weight and app sim key + ProposalMsgs []simulation.WeightedProposalMsg // proposal msg generator functions with their default weight and app sim key } diff --git a/types/simulation/types.go b/types/simulation/types.go index eeb9c15553f0..34d29d04e323 100644 --- a/types/simulation/types.go +++ b/types/simulation/types.go @@ -12,14 +12,17 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" ) +// Deprecated: Use WeightedProposalMsg instead. type WeightedProposalContent interface { 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 } +// Deprecated: Use MsgSimulatorFn instead. type ContentSimulatorFn func(r *rand.Rand, ctx sdk.Context, accs []Account) Content +// Deprecated: Use MsgSimulatorFn instead. type Content interface { GetTitle() string GetDescription() string @@ -29,9 +32,17 @@ type Content interface { String() string } +type WeightedProposalMsg interface { + AppParamsKey() string // key used to retrieve the value of the weight from the simulation application params + DefaultWeight() int // default weight + MsgSimulatorFn() MsgSimulatorFn // msg simulator function +} + +type MsgSimulatorFn func(r *rand.Rand, ctx sdk.Context, accs []Account) sdk.Msg + type SimValFn func(r *rand.Rand) string -type ParamChange interface { +type LegacyParamChange interface { Subspace() string Key() string SimValue() SimValFn diff --git a/x/auth/module.go b/x/auth/module.go index dd74be10b421..b913b79cb885 100644 --- a/x/auth/module.go +++ b/x/auth/module.go @@ -179,9 +179,9 @@ func (am AppModule) GenerateGenesisState(simState *module.SimulationState) { simulation.RandomizedGenState(simState, am.randGenAccountsFn) } -// ProposalContents doesn't return any content functions for governance proposals. -func (AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent { - return nil +// ProposalMsgs returns msgs used for governance proposals for simulations. +func (AppModule) ProposalMsgs(simState module.SimulationState) []simtypes.WeightedProposalMsg { + return simulation.ProposalMsgs() } // RegisterStoreDecoder registers a decoder for auth module's types diff --git a/x/auth/simulation/params.go b/x/auth/simulation/params.go deleted file mode 100644 index 310e2a49ae16..000000000000 --- a/x/auth/simulation/params.go +++ /dev/null @@ -1,38 +0,0 @@ -package simulation - -import ( - "fmt" - "math/rand" - - simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/cosmos/cosmos-sdk/x/auth/types" - "github.com/cosmos/cosmos-sdk/x/simulation" -) - -const ( - keyMaxMemoCharacters = "MaxMemoCharacters" - keyTxSigLimit = "TxSigLimit" - keyTxSizeCostPerByte = "TxSizeCostPerByte" -) - -// ParamChanges defines the parameters that can be modified by param change proposals -// on the simulation -func ParamChanges(r *rand.Rand) []simtypes.ParamChange { - return []simtypes.ParamChange{ - simulation.NewSimParamChange(types.ModuleName, keyMaxMemoCharacters, - func(r *rand.Rand) string { - return fmt.Sprintf("\"%d\"", GenMaxMemoChars(r)) - }, - ), - simulation.NewSimParamChange(types.ModuleName, keyTxSigLimit, - func(r *rand.Rand) string { - return fmt.Sprintf("\"%d\"", GenTxSigLimit(r)) - }, - ), - simulation.NewSimParamChange(types.ModuleName, keyTxSizeCostPerByte, - func(r *rand.Rand) string { - return fmt.Sprintf("\"%d\"", GenTxSizeCostPerByte(r)) - }, - ), - } -} diff --git a/x/auth/simulation/params_test.go b/x/auth/simulation/params_test.go deleted file mode 100644 index b8fb384a80f6..000000000000 --- a/x/auth/simulation/params_test.go +++ /dev/null @@ -1,37 +0,0 @@ -package simulation_test - -import ( - "math/rand" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/x/auth/simulation" -) - -func TestParamChanges(t *testing.T) { - s := rand.NewSource(1) - r := rand.New(s) - - expected := []struct { - composedKey string - key string - simValue string - subspace string - }{ - {"auth/MaxMemoCharacters", "MaxMemoCharacters", "\"181\"", "auth"}, - {"auth/TxSigLimit", "TxSigLimit", "\"7\"", "auth"}, - {"auth/TxSizeCostPerByte", "TxSizeCostPerByte", "\"12\"", "auth"}, - } - - paramChanges := simulation.ParamChanges(r) - - require.Len(t, paramChanges, 3) - - for i, p := range paramChanges { - require.Equal(t, expected[i].composedKey, p.ComposedKey()) - require.Equal(t, expected[i].key, p.Key()) - require.Equal(t, expected[i].simValue, p.SimValue()(r)) - require.Equal(t, expected[i].subspace, p.Subspace()) - } -} diff --git a/x/auth/simulation/proposals.go b/x/auth/simulation/proposals.go new file mode 100644 index 000000000000..87746569c22f --- /dev/null +++ b/x/auth/simulation/proposals.go @@ -0,0 +1,47 @@ +package simulation + +import ( + "math/rand" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/simulation" +) + +// Simulation operation weights constants +const ( + DefaultWeightMsgUpdateParams int = 100 + + OpWeightMsgUpdateParams = "op_weight_msg_update_params" //nolint:gosec +) + +// ProposalMsgs defines the module weighted proposals' contents +func ProposalMsgs() []simtypes.WeightedProposalMsg { + return []simtypes.WeightedProposalMsg{ + simulation.NewWeightedProposalMsg( + OpWeightMsgUpdateParams, + DefaultWeightMsgUpdateParams, + SimulateMsgUpdateParams, + ), + } +} + +// SimulateMsgUpdateParams returns a random MsgUpdateParams +func SimulateMsgUpdateParams(r *rand.Rand, _ sdk.Context, _ []simtypes.Account) sdk.Msg { + // use the default gov module account address as authority + var authority sdk.AccAddress = address.Module("gov") + + params := types.DefaultParams() + params.MaxMemoCharacters = uint64(simtypes.RandIntBetween(r, 1, 1000)) + params.TxSigLimit = uint64(simtypes.RandIntBetween(r, 1, 1000)) + params.TxSizeCostPerByte = uint64(simtypes.RandIntBetween(r, 1, 1000)) + params.SigVerifyCostED25519 = uint64(simtypes.RandIntBetween(r, 1, 1000)) + params.SigVerifyCostSecp256k1 = uint64(simtypes.RandIntBetween(r, 1, 1000)) + + return &types.MsgUpdateParams{ + Authority: authority.String(), + Params: params, + } +} diff --git a/x/auth/simulation/proposals_test.go b/x/auth/simulation/proposals_test.go new file mode 100644 index 000000000000..285985cad31d --- /dev/null +++ b/x/auth/simulation/proposals_test.go @@ -0,0 +1,45 @@ +package simulation_test + +import ( + "math/rand" + "testing" + + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + "gotest.tools/v3/assert" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/auth/simulation" + "github.com/cosmos/cosmos-sdk/x/auth/types" +) + +func TestProposalMsgs(t *testing.T) { + // initialize parameters + s := rand.NewSource(1) + r := rand.New(s) + + ctx := sdk.NewContext(nil, tmproto.Header{}, true, nil) + accounts := simtypes.RandomAccounts(r, 3) + + // execute ProposalMsgs function + weightedProposalMsgs := simulation.ProposalMsgs() + assert.Assert(t, len(weightedProposalMsgs) == 1) + + w0 := weightedProposalMsgs[0] + + // tests w0 interface: + assert.Equal(t, simulation.OpWeightMsgUpdateParams, w0.AppParamsKey()) + assert.Equal(t, simulation.DefaultWeightMsgUpdateParams, w0.DefaultWeight()) + + msg := w0.MsgSimulatorFn()(r, ctx, accounts) + msgUpdateParams, ok := msg.(*types.MsgUpdateParams) + assert.Assert(t, ok) + + assert.Equal(t, sdk.AccAddress(address.Module("gov")).String(), msgUpdateParams.Authority) + assert.Equal(t, uint64(999), msgUpdateParams.Params.MaxMemoCharacters) + assert.Equal(t, uint64(905), msgUpdateParams.Params.TxSigLimit) + assert.Equal(t, uint64(151), msgUpdateParams.Params.TxSizeCostPerByte) + assert.Equal(t, uint64(213), msgUpdateParams.Params.SigVerifyCostED25519) + assert.Equal(t, uint64(539), msgUpdateParams.Params.SigVerifyCostSecp256k1) +} diff --git a/x/authz/module/module.go b/x/authz/module/module.go index ce3f00daeecd..5934aae60414 100644 --- a/x/authz/module/module.go +++ b/x/authz/module/module.go @@ -207,12 +207,6 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) { simulation.RandomizedGenState(simState) } -// ProposalContents returns all the authz content functions used to -// simulate governance proposals. -func (am AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent { - return nil -} - // RegisterStoreDecoder registers a decoder for authz module's types func (am AppModule) RegisterStoreDecoder(sdr simtypes.StoreDecoderRegistry) { sdr[keeper.StoreKey] = simulation.NewDecodeStore(am.cdc) diff --git a/x/authz/msgs.go b/x/authz/msgs.go index f96163b7f334..792120d6de71 100644 --- a/x/authz/msgs.go +++ b/x/authz/msgs.go @@ -3,6 +3,7 @@ package authz import ( "time" + "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" authzcodec "github.com/cosmos/cosmos-sdk/x/authz/codec" "github.com/cosmos/gogoproto/proto" @@ -10,7 +11,6 @@ import ( cdctypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx" ) var ( diff --git a/x/authz/simulation/operations.go b/x/authz/simulation/operations.go index 39172a1e5ec8..33fe08dea025 100644 --- a/x/authz/simulation/operations.go +++ b/x/authz/simulation/operations.go @@ -26,12 +26,10 @@ var ( ) // Simulation operation weights constants -// -//nolint:gosec // these are not hardcoded credentials. const ( - OpWeightMsgGrant = "op_weight_msg_grant" - OpWeightRevoke = "op_weight_msg_revoke" - OpWeightExec = "op_weight_msg_execute" + OpWeightMsgGrant = "op_weight_msg_grant" //nolint:gosec + OpWeightRevoke = "op_weight_msg_revoke" //nolint:gosec + OpWeightExec = "op_weight_msg_execute" //nolint:gosec ) // authz operations weights diff --git a/x/bank/module.go b/x/bank/module.go index 52654cc2c718..ad1bb0eaa661 100644 --- a/x/bank/module.go +++ b/x/bank/module.go @@ -183,9 +183,9 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) { simulation.RandomizedGenState(simState) } -// ProposalContents doesn't return any content functions for governance proposals. -func (AppModule) ProposalContents(_ module.SimulationState) []simtypes.WeightedProposalContent { - return nil +// ProposalMsgs returns msgs used for governance proposals for simulations. +func (AppModule) ProposalMsgs(simState module.SimulationState) []simtypes.WeightedProposalMsg { + return simulation.ProposalMsgs() } // RegisterStoreDecoder registers a decoder for supply module's types diff --git a/x/bank/simulation/operations.go b/x/bank/simulation/operations.go index 25aa67759269..3f7a1b024d91 100644 --- a/x/bank/simulation/operations.go +++ b/x/bank/simulation/operations.go @@ -17,13 +17,11 @@ import ( ) // Simulation operation weights constants -// -//nolint:gosec // these are not hardcoded credentials. const ( - OpWeightMsgSend = "op_weight_msg_send" - OpWeightMsgMultiSend = "op_weight_msg_multisend" - DefaultWeightMsgSend = 100 // from simappparams.DefaultWeightMsgSend - DefaultWeightMsgMultiSend = 10 // from simappparams.DefaultWeightMsgMultiSend + OpWeightMsgSend = "op_weight_msg_send" //nolint:gosec + OpWeightMsgMultiSend = "op_weight_msg_multisend" //nolint:gosec + DefaultWeightMsgSend = 100 // from simappparams.DefaultWeightMsgSend + DefaultWeightMsgMultiSend = 10 // from simappparams.DefaultWeightMsgMultiSend ) // WeightedOperations returns all the operations from the module with their respective weights diff --git a/x/bank/simulation/params.go b/x/bank/simulation/params.go deleted file mode 100644 index ab83624c035b..000000000000 --- a/x/bank/simulation/params.go +++ /dev/null @@ -1,23 +0,0 @@ -package simulation - -import ( - "fmt" - "math/rand" - - "github.com/cosmos/cosmos-sdk/x/simulation" - - simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/cosmos/cosmos-sdk/x/bank/types" -) - -// ParamChanges defines the parameters that can be modified by param change proposals -// on the simulation -func ParamChanges(r *rand.Rand) []simtypes.ParamChange { - return []simtypes.ParamChange{ - simulation.NewSimParamChange(types.ModuleName, string(types.KeyDefaultSendEnabled), - func(r *rand.Rand) string { - return fmt.Sprintf("%v", RandomGenesisDefaultSendEnabledParam(r)) - }, - ), - } -} diff --git a/x/bank/simulation/params_test.go b/x/bank/simulation/params_test.go deleted file mode 100644 index df6604367a1d..000000000000 --- a/x/bank/simulation/params_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package simulation_test - -import ( - "math/rand" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/x/bank/simulation" -) - -func TestParamChanges(t *testing.T) { - s := rand.NewSource(1) - r := rand.New(s) - - expected := []struct { - composedKey string - key string - simValue string - subspace string - }{ - {"bank/DefaultSendEnabled", "DefaultSendEnabled", "true", "bank"}, - } - - paramChanges := simulation.ParamChanges(r) - - require.Len(t, paramChanges, len(expected)) - - for i, p := range paramChanges { - require.Equal(t, expected[i].composedKey, p.ComposedKey()) - require.Equal(t, expected[i].key, p.Key()) - require.Equal(t, expected[i].simValue, p.SimValue()(r)) - require.Equal(t, expected[i].subspace, p.Subspace()) - } -} diff --git a/x/bank/simulation/proposals.go b/x/bank/simulation/proposals.go new file mode 100644 index 000000000000..5a63b8632cea --- /dev/null +++ b/x/bank/simulation/proposals.go @@ -0,0 +1,43 @@ +package simulation + +import ( + "math/rand" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/simulation" +) + +// Simulation operation weights constants +const ( + DefaultWeightMsgUpdateParams int = 100 + + OpWeightMsgUpdateParams = "op_weight_msg_update_params" //nolint:gosec +) + +// ProposalMsgs defines the module weighted proposals' contents +func ProposalMsgs() []simtypes.WeightedProposalMsg { + return []simtypes.WeightedProposalMsg{ + simulation.NewWeightedProposalMsg( + OpWeightMsgUpdateParams, + DefaultWeightMsgUpdateParams, + SimulateMsgUpdateParams, + ), + } +} + +// SimulateMsgUpdateParams returns a random MsgUpdateParams +func SimulateMsgUpdateParams(r *rand.Rand, _ sdk.Context, _ []simtypes.Account) sdk.Msg { + // use the default gov module account address as authority + var authority sdk.AccAddress = address.Module("gov") + + params := types.DefaultParams() + params.DefaultSendEnabled = r.Intn(2) == 0 + + return &types.MsgUpdateParams{ + Authority: authority.String(), + Params: params, + } +} diff --git a/x/bank/simulation/proposals_test.go b/x/bank/simulation/proposals_test.go new file mode 100644 index 000000000000..8fa38af01056 --- /dev/null +++ b/x/bank/simulation/proposals_test.go @@ -0,0 +1,44 @@ +package simulation_test + +import ( + "fmt" + "math/rand" + "testing" + + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + "gotest.tools/v3/assert" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/bank/simulation" + "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +func TestProposalMsgs(t *testing.T) { + // initialize parameters + s := rand.NewSource(1) + r := rand.New(s) + + ctx := sdk.NewContext(nil, tmproto.Header{}, true, nil) + accounts := simtypes.RandomAccounts(r, 3) + + // execute ProposalMsgs function + weightedProposalMsgs := simulation.ProposalMsgs() + assert.Assert(t, len(weightedProposalMsgs) == 1) + + w0 := weightedProposalMsgs[0] + + // tests w0 interface: + assert.Equal(t, simulation.OpWeightMsgUpdateParams, w0.AppParamsKey()) + assert.Equal(t, simulation.DefaultWeightMsgUpdateParams, w0.DefaultWeight()) + + msg := w0.MsgSimulatorFn()(r, ctx, accounts) + msgUpdateParams, ok := msg.(*types.MsgUpdateParams) + assert.Assert(t, ok) + + fmt.Println(msgUpdateParams) + assert.Equal(t, sdk.AccAddress(address.Module("gov")).String(), msgUpdateParams.Authority) + assert.Assert(t, len(msgUpdateParams.Params.SendEnabled) == 0) //nolint:staticcheck + assert.Equal(t, true, msgUpdateParams.Params.DefaultSendEnabled) +} diff --git a/x/capability/module.go b/x/capability/module.go index 000f832bee43..a704da4f4651 100644 --- a/x/capability/module.go +++ b/x/capability/module.go @@ -163,11 +163,6 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) { simulation.RandomizedGenState(simState) } -// ProposalContents performs a no-op -func (am AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent { - return nil -} - // RegisterStoreDecoder registers a decoder for capability module's types func (am AppModule) RegisterStoreDecoder(sdr simtypes.StoreDecoderRegistry) { sdr[types.StoreKey] = simulation.NewDecodeStore(am.cdc) diff --git a/x/distribution/module.go b/x/distribution/module.go index a263c2205f49..0181ceb69522 100644 --- a/x/distribution/module.go +++ b/x/distribution/module.go @@ -185,10 +185,9 @@ 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(simState module.SimulationState) []simtypes.WeightedProposalContent { - return nil +// ProposalMsgs returns msgs used for governance proposals for simulations. +func (AppModule) ProposalMsgs(simState module.SimulationState) []simtypes.WeightedProposalMsg { + return simulation.ProposalMsgs() } // RegisterStoreDecoder registers a decoder for distribution module's types diff --git a/x/distribution/simulation/operations.go b/x/distribution/simulation/operations.go index 7f9e61d1d03d..40165a31798a 100644 --- a/x/distribution/simulation/operations.go +++ b/x/distribution/simulation/operations.go @@ -18,13 +18,11 @@ import ( ) // Simulation operation weights constants -// -//nolint:gosec // these are not hardcoded credentials. const ( - OpWeightMsgSetWithdrawAddress = "op_weight_msg_set_withdraw_address" - OpWeightMsgWithdrawDelegationReward = "op_weight_msg_withdraw_delegation_reward" - OpWeightMsgWithdrawValidatorCommission = "op_weight_msg_withdraw_validator_commission" - OpWeightMsgFundCommunityPool = "op_weight_msg_fund_community_pool" + OpWeightMsgSetWithdrawAddress = "op_weight_msg_set_withdraw_address" //nolint:gosec + OpWeightMsgWithdrawDelegationReward = "op_weight_msg_withdraw_delegation_reward" //nolint:gosec + OpWeightMsgWithdrawValidatorCommission = "op_weight_msg_withdraw_validator_commission" //nolint:gosec + OpWeightMsgFundCommunityPool = "op_weight_msg_fund_community_pool" //nolint:gosec DefaultWeightMsgSetWithdrawAddress int = 50 DefaultWeightMsgWithdrawDelegationReward int = 50 diff --git a/x/distribution/simulation/params.go b/x/distribution/simulation/params.go deleted file mode 100644 index d4ca51822767..000000000000 --- a/x/distribution/simulation/params.go +++ /dev/null @@ -1,27 +0,0 @@ -package simulation - -import ( - "fmt" - "math/rand" - - "github.com/cosmos/cosmos-sdk/x/simulation" - - simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/cosmos/cosmos-sdk/x/distribution/types" -) - -const ( - keyCommunityTax = "communitytax" -) - -// ParamChanges defines the parameters that can be modified by param change proposals -// on the simulation -func ParamChanges(r *rand.Rand) []simtypes.ParamChange { - return []simtypes.ParamChange{ - simulation.NewSimParamChange(types.ModuleName, keyCommunityTax, - func(r *rand.Rand) string { - return fmt.Sprintf("\"%s\"", GenCommunityTax(r)) - }, - ), - } -} diff --git a/x/distribution/simulation/params_test.go b/x/distribution/simulation/params_test.go deleted file mode 100644 index 0d1818a40510..000000000000 --- a/x/distribution/simulation/params_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package simulation_test - -import ( - "math/rand" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/x/distribution/simulation" -) - -func TestParamChanges(t *testing.T) { - s := rand.NewSource(1) - r := rand.New(s) - - expected := []struct { - composedKey string - key string - simValue string - subspace string - }{ - {"distribution/communitytax", "communitytax", "\"0.120000000000000000\"", "distribution"}, - } - - paramChanges := simulation.ParamChanges(r) - - require.Len(t, paramChanges, 1) - - for i, p := range paramChanges { - require.Equal(t, expected[i].composedKey, p.ComposedKey()) - require.Equal(t, expected[i].key, p.Key()) - require.Equal(t, expected[i].simValue, p.SimValue()(r)) - require.Equal(t, expected[i].subspace, p.Subspace()) - } -} diff --git a/x/distribution/simulation/proposals.go b/x/distribution/simulation/proposals.go new file mode 100644 index 000000000000..6330691afc26 --- /dev/null +++ b/x/distribution/simulation/proposals.go @@ -0,0 +1,44 @@ +package simulation + +import ( + "math/rand" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/distribution/types" + "github.com/cosmos/cosmos-sdk/x/simulation" +) + +// Simulation operation weights constants +const ( + DefaultWeightMsgUpdateParams int = 50 + + OpWeightMsgUpdateParams = "op_weight_msg_update_params" //nolint:gosec +) + +// ProposalMsgs defines the module weighted proposals' contents +func ProposalMsgs() []simtypes.WeightedProposalMsg { + return []simtypes.WeightedProposalMsg{ + simulation.NewWeightedProposalMsg( + OpWeightMsgUpdateParams, + DefaultWeightMsgUpdateParams, + SimulateMsgUpdateParams, + ), + } +} + +// SimulateMsgUpdateParams returns a random MsgUpdateParams +func SimulateMsgUpdateParams(r *rand.Rand, _ sdk.Context, _ []simtypes.Account) sdk.Msg { + // use the default gov module account address as authority + var authority sdk.AccAddress = address.Module("gov") + + params := types.DefaultParams() + params.CommunityTax = simtypes.RandomDecAmount(r, sdk.NewDec(1)) + params.WithdrawAddrEnabled = r.Intn(2) == 0 + + return &types.MsgUpdateParams{ + Authority: authority.String(), + Params: params, + } +} diff --git a/x/distribution/simulation/proposals_test.go b/x/distribution/simulation/proposals_test.go new file mode 100644 index 000000000000..77d7d570716e --- /dev/null +++ b/x/distribution/simulation/proposals_test.go @@ -0,0 +1,42 @@ +package simulation_test + +import ( + "math/rand" + "testing" + + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + "gotest.tools/v3/assert" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/distribution/simulation" + "github.com/cosmos/cosmos-sdk/x/distribution/types" +) + +func TestProposalMsgs(t *testing.T) { + // initialize parameters + s := rand.NewSource(1) + r := rand.New(s) + + ctx := sdk.NewContext(nil, tmproto.Header{}, true, nil) + accounts := simtypes.RandomAccounts(r, 3) + + // execute ProposalMsgs function + weightedProposalMsgs := simulation.ProposalMsgs() + assert.Assert(t, len(weightedProposalMsgs) == 1) + + w0 := weightedProposalMsgs[0] + + // tests w0 interface: + assert.Equal(t, simulation.OpWeightMsgUpdateParams, w0.AppParamsKey()) + assert.Equal(t, simulation.DefaultWeightMsgUpdateParams, w0.DefaultWeight()) + + msg := w0.MsgSimulatorFn()(r, ctx, accounts) + msgUpdateParams, ok := msg.(*types.MsgUpdateParams) + assert.Assert(t, ok) + + assert.Equal(t, sdk.AccAddress(address.Module("gov")).String(), msgUpdateParams.Authority) + assert.DeepEqual(t, sdk.NewDec(0), msgUpdateParams.Params.CommunityTax) + assert.Equal(t, true, msgUpdateParams.Params.WithdrawAddrEnabled) +} diff --git a/x/evidence/module.go b/x/evidence/module.go index 7f00e6be6ed2..65e964f015ab 100644 --- a/x/evidence/module.go +++ b/x/evidence/module.go @@ -177,12 +177,6 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) { simulation.RandomizedGenState(simState) } -// ProposalContents returns all the evidence content functions used to -// simulate governance proposals. -func (am AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent { - return nil -} - // RegisterStoreDecoder registers a decoder for evidence module's types func (am AppModule) RegisterStoreDecoder(sdr simtypes.StoreDecoderRegistry) { sdr[types.StoreKey] = simulation.NewDecodeStore(am.keeper) diff --git a/x/feegrant/module/module.go b/x/feegrant/module/module.go index b8e994315be9..1fb8b3138205 100644 --- a/x/feegrant/module/module.go +++ b/x/feegrant/module/module.go @@ -208,12 +208,6 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) { simulation.RandomizedGenState(simState) } -// ProposalContents returns all the feegrant content functions used to -// simulate governance proposals. -func (AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent { - return nil -} - // RegisterStoreDecoder registers a decoder for feegrant module's types func (am AppModule) RegisterStoreDecoder(sdr simtypes.StoreDecoderRegistry) { sdr[feegrant.StoreKey] = simulation.NewDecodeStore(am.cdc) diff --git a/x/gov/module.go b/x/gov/module.go index f7869c0a0bf8..dedb7e6ebd65 100644 --- a/x/gov/module.go +++ b/x/gov/module.go @@ -334,10 +334,15 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) { // ProposalContents returns all the gov content functions used to // simulate governance proposals. -func (AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent { +func (AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent { //nolint:staticcheck return simulation.ProposalContents() } +// ProposalMsgs returns all the gov msgs used to simulate governance proposals. +func (AppModule) ProposalMsgs(simState module.SimulationState) []simtypes.WeightedProposalMsg { + return simulation.ProposalMsgs() +} + // RegisterStoreDecoder registers a decoder for gov module's types func (am AppModule) RegisterStoreDecoder(sdr simtypes.StoreDecoderRegistry) { sdr[govtypes.StoreKey] = simulation.NewDecodeStore(am.cdc) @@ -347,6 +352,7 @@ func (am AppModule) RegisterStoreDecoder(sdr simtypes.StoreDecoderRegistry) { func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation { return simulation.WeightedOperations( simState.AppParams, simState.Cdc, - am.accountKeeper, am.bankKeeper, am.keeper, simState.Contents, + am.accountKeeper, am.bankKeeper, am.keeper, + simState.ProposalMsgs, simState.LegacyProposalContents, ) } diff --git a/x/gov/simulation/operations.go b/x/gov/simulation/operations.go index 7fb0059bb168..1256fed08ebb 100644 --- a/x/gov/simulation/operations.go +++ b/x/gov/simulation/operations.go @@ -26,6 +26,7 @@ var ( TypeMsgVoteWeighted = sdk.MsgTypeURL(&v1.MsgVoteWeighted{}) TypeMsgSubmitProposal = sdk.MsgTypeURL(&v1.MsgSubmitProposal{}) TypeMsgCancelProposal = sdk.MsgTypeURL(&v1.MsgCancelProposal{}) + TypeMsgUpdateParams = sdk.MsgTypeURL(&v1.MsgUpdateParams{}) ) // Simulation operation weights constants @@ -45,7 +46,7 @@ const ( ) // WeightedOperations returns all the operations from the module with their respective weights -func WeightedOperations(appParams simtypes.AppParams, cdc codec.JSONCodec, ak types.AccountKeeper, bk types.BankKeeper, k *keeper.Keeper, wContents []simtypes.WeightedProposalContent) simulation.WeightedOperations { +func WeightedOperations(appParams simtypes.AppParams, cdc codec.JSONCodec, ak types.AccountKeeper, bk types.BankKeeper, k *keeper.Keeper, wMsgs []simtypes.WeightedProposalMsg, wContents []simtypes.WeightedProposalContent) simulation.WeightedOperations { //nolint:staticcheck var ( weightMsgDeposit int weightMsgVote int @@ -77,20 +78,36 @@ func WeightedOperations(appParams simtypes.AppParams, cdc codec.JSONCodec, ak ty }, ) - // generate the weighted operations for the proposal contents + // generate the weighted operations for the proposal msgs var wProposalOps simulation.WeightedOperations + for _, wMsg := range wMsgs { + wMsg := wMsg // pin variable + var weight int + appParams.GetOrGenerate(cdc, wMsg.AppParamsKey(), &weight, nil, + func(_ *rand.Rand) { weight = wMsg.DefaultWeight() }) + + wProposalOps = append( + wProposalOps, + simulation.NewWeightedOperation( + weight, + SimulateMsgSubmitProposal(ak, bk, k, wMsg.MsgSimulatorFn()), + ), + ) + } + // generate the weighted operations for the proposal contents + var wLegacyProposalOps 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, + wLegacyProposalOps = append( + wLegacyProposalOps, simulation.NewWeightedOperation( weight, - SimulateMsgSubmitProposal(ak, bk, k, wContent.ContentSimulatorFn()), + SimulateMsgSubmitLegacyProposal(ak, bk, k, wContent.ContentSimulatorFn()), ), ) } @@ -114,34 +131,43 @@ func WeightedOperations(appParams simtypes.AppParams, cdc codec.JSONCodec, ak ty ), } - return append(wProposalOps, wGovOps...) + return append(wGovOps, append(wProposalOps, wLegacyProposalOps...)...) } // SimulateMsgSubmitProposal simulates creating a msg Submit Proposal // voting on the proposal, and subsequently slashing the proposal. It is implemented using // future operations. -func SimulateMsgSubmitProposal(ak types.AccountKeeper, bk types.BankKeeper, k *keeper.Keeper, contentSim simtypes.ContentSimulatorFn) simtypes.Operation { - // The states are: - // column 1: All validators vote - // column 2: 90% vote - // column 3: 75% vote - // column 4: 40% vote - // column 5: 15% vote - // column 6: noone votes - // All columns sum to 100 for simplicity, values chosen by @valardragon semi-arbitrarily, - // feel free to change. - numVotesTransitionMatrix, _ := simulation.CreateTransitionMatrix([][]int{ - {20, 10, 0, 0, 0, 0}, - {55, 50, 20, 10, 0, 0}, - {25, 25, 30, 25, 30, 15}, - {0, 15, 30, 25, 30, 30}, - {0, 0, 20, 30, 30, 30}, - {0, 0, 0, 10, 10, 25}, - }) +func SimulateMsgSubmitProposal(ak types.AccountKeeper, bk types.BankKeeper, k *keeper.Keeper, msgSim simtypes.MsgSimulatorFn) simtypes.Operation { + return func( + r *rand.Rand, + app *baseapp.BaseApp, + ctx sdk.Context, + accs []simtypes.Account, + chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + simAccount, _ := simtypes.RandomAcc(r, accs) + deposit, skip, err := randomDeposit(r, ctx, ak, bk, k, simAccount.Address, true) + switch { + case skip: + return simtypes.NoOpMsg(types.ModuleName, TypeMsgSubmitProposal, "skip deposit"), nil, nil + case err != nil: + return simtypes.NoOpMsg(types.ModuleName, TypeMsgSubmitProposal, "unable to generate deposit"), nil, err + } - statePercentageArray := []float64{1, .9, .75, .4, .15, 0} - curNumVotesState := 1 + msgs := []sdk.Msg{} + proposalMsg := msgSim(r, ctx, accs) + if proposalMsg != nil { + msgs = append(msgs, proposalMsg) + } + + return simulateMsgSubmitProposal(ak, bk, k, msgs, simAccount, deposit)(r, app, ctx, accs, chainID) + } +} +// SimulateMsgSubmitLegacyProposal simulates creating a msg Submit Proposal +// voting on the proposal, and subsequently slashing the proposal. It is implemented using +// future operations. +func SimulateMsgSubmitLegacyProposal(ak types.AccountKeeper, bk types.BankKeeper, k *keeper.Keeper, contentSim simtypes.ContentSimulatorFn) simtypes.Operation { //nolint:staticcheck return func( r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string, @@ -167,7 +193,54 @@ func SimulateMsgSubmitProposal(ak types.AccountKeeper, bk types.BankKeeper, k *k return simtypes.NoOpMsg(types.ModuleName, TypeMsgSubmitProposal, "error converting legacy content into proposal message"), nil, err } - msg, err := v1.NewMsgSubmitProposal([]sdk.Msg{contentMsg}, deposit, simAccount.Address.String(), "", "Title of proposal", "Short description of proposal") + return simulateMsgSubmitProposal(ak, bk, k, []sdk.Msg{contentMsg}, simAccount, deposit)(r, app, ctx, accs, chainID) + } +} + +func simulateMsgSubmitProposal( + ak types.AccountKeeper, + bk types.BankKeeper, + k *keeper.Keeper, + proposalMsgs []sdk.Msg, + simAccount simtypes.Account, + deposit sdk.Coins, +) simtypes.Operation { + // The states are: + // column 1: All validators vote + // column 2: 90% vote + // column 3: 75% vote + // column 4: 40% vote + // column 5: 15% vote + // column 6: noone votes + // All columns sum to 100 for simplicity, values chosen by @valardragon semi-arbitrarily, + // feel free to change. + numVotesTransitionMatrix, _ := simulation.CreateTransitionMatrix([][]int{ + {20, 10, 0, 0, 0, 0}, + {55, 50, 20, 10, 0, 0}, + {25, 25, 30, 25, 30, 15}, + {0, 15, 30, 25, 30, 30}, + {0, 0, 20, 30, 30, 30}, + {0, 0, 0, 10, 10, 25}, + }) + + statePercentageArray := []float64{1, .9, .75, .4, .15, 0} + curNumVotesState := 1 + + return func( + r *rand.Rand, + app *baseapp.BaseApp, + ctx sdk.Context, + accs []simtypes.Account, + chainID string, + ) (simtypes.OperationMsg, []simtypes.FutureOperation, error) { + msg, err := v1.NewMsgSubmitProposal( + proposalMsgs, + deposit, + simAccount.Address.String(), + simtypes.RandStringOfLength(r, 100), + simtypes.RandStringOfLength(r, 100), + simtypes.RandStringOfLength(r, 100), + ) if err != nil { return simtypes.NoOpMsg(types.ModuleName, sdk.MsgTypeURL(msg), "unable to generate a submit proposal msg"), nil, err } diff --git a/x/gov/simulation/operations_test.go b/x/gov/simulation/operations_test.go index facc01f7b503..7d34ad040efe 100644 --- a/x/gov/simulation/operations_test.go +++ b/x/gov/simulation/operations_test.go @@ -6,11 +6,11 @@ import ( "testing" "time" + storetypes "cosmossdk.io/store/types" "github.com/stretchr/testify/require" abci "github.com/tendermint/tendermint/abci/types" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/runtime" "github.com/cosmos/cosmos-sdk/testutil/configurator" simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" @@ -36,20 +36,31 @@ import ( stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" ) -type MockWeightedProposalContent struct { +var ( + _ simtypes.WeightedProposalMsg = MockWeightedProposals{} + _ simtypes.WeightedProposalContent = MockWeightedProposals{} //nolint:staticcheck +) + +type MockWeightedProposals struct { n int } -func (m MockWeightedProposalContent) AppParamsKey() string { +func (m MockWeightedProposals) AppParamsKey() string { return fmt.Sprintf("AppParamsKey-%d", m.n) } -func (m MockWeightedProposalContent) DefaultWeight() int { +func (m MockWeightedProposals) DefaultWeight() int { return m.n } -func (m MockWeightedProposalContent) ContentSimulatorFn() simtypes.ContentSimulatorFn { - return func(r *rand.Rand, _ sdk.Context, _ []simtypes.Account) simtypes.Content { +func (m MockWeightedProposals) MsgSimulatorFn() simtypes.MsgSimulatorFn { + return func(r *rand.Rand, _ sdk.Context, _ []simtypes.Account) sdk.Msg { + return nil + } +} + +func (m MockWeightedProposals) ContentSimulatorFn() simtypes.ContentSimulatorFn { //nolint:staticcheck + return func(r *rand.Rand, _ sdk.Context, _ []simtypes.Account) simtypes.Content { //nolint:staticcheck return v1beta1.NewTextProposal( fmt.Sprintf("title-%d: %s", m.n, simtypes.RandStringOfLength(r, 100)), fmt.Sprintf("description-%d: %s", m.n, simtypes.RandStringOfLength(r, 4000)), @@ -57,13 +68,18 @@ func (m MockWeightedProposalContent) ContentSimulatorFn() simtypes.ContentSimula } } -// make sure the MockWeightedProposalContent satisfied the WeightedProposalContent interface -var _ simtypes.WeightedProposalContent = MockWeightedProposalContent{} +func mockWeightedProposalMsg(n int) []simtypes.WeightedProposalMsg { + wpc := make([]simtypes.WeightedProposalMsg, n) + for i := 0; i < n; i++ { + wpc[i] = MockWeightedProposals{i} + } + return wpc +} -func mockWeightedProposalContent(n int) []simtypes.WeightedProposalContent { - wpc := make([]simtypes.WeightedProposalContent, n) +func mockWeightedLegacyProposalContent(n int) []simtypes.WeightedProposalContent { //nolint:staticcheck + wpc := make([]simtypes.WeightedProposalContent, n) //nolint:staticcheck for i := 0; i < n; i++ { - wpc[i] = MockWeightedProposalContent{i} + wpc[i] = MockWeightedProposals{i} } return wpc } @@ -73,12 +89,10 @@ func TestWeightedOperations(t *testing.T) { suite, ctx := createTestSuite(t, false) app := suite.App ctx.WithChainID("test-chain") - - cdc := suite.cdc appParams := make(simtypes.AppParams) - weightesOps := simulation.WeightedOperations(appParams, cdc, suite.AccountKeeper, - suite.BankKeeper, suite.GovKeeper, mockWeightedProposalContent(3), + weightesOps := simulation.WeightedOperations(appParams, govcodec.ModuleCdc, suite.AccountKeeper, + suite.BankKeeper, suite.GovKeeper, mockWeightedProposalMsg(3), mockWeightedLegacyProposalContent(1), ) // setup 3 accounts @@ -91,18 +105,19 @@ func TestWeightedOperations(t *testing.T) { opMsgRoute string opMsgName string }{ - {0, types.ModuleName, simulation.TypeMsgSubmitProposal}, - {1, types.ModuleName, simulation.TypeMsgSubmitProposal}, - {2, types.ModuleName, simulation.TypeMsgSubmitProposal}, {simulation.DefaultWeightMsgDeposit, types.ModuleName, simulation.TypeMsgDeposit}, {simulation.DefaultWeightMsgVote, types.ModuleName, simulation.TypeMsgVote}, {simulation.DefaultWeightMsgVoteWeighted, types.ModuleName, simulation.TypeMsgVoteWeighted}, {simulation.DefaultWeightMsgCancelProposal, types.ModuleName, simulation.TypeMsgCancelProposal}, + {0, types.ModuleName, simulation.TypeMsgSubmitProposal}, + {1, types.ModuleName, simulation.TypeMsgSubmitProposal}, + {2, types.ModuleName, simulation.TypeMsgSubmitProposal}, + {0, types.ModuleName, simulation.TypeMsgSubmitProposal}, } for i, w := range weightesOps { - operationMsg, _, _ := w.Op()(r, app.BaseApp, ctx, accs, ctx.ChainID()) - // require.NoError(t, err) // TODO check if it should be NoError + operationMsg, _, err := w.Op()(r, app.BaseApp, ctx.WithBlockGasMeter(storetypes.NewInfiniteGasMeter()), accs, ctx.ChainID()) + require.NoError(t, err) // the following checks are very much dependent from the ordering of the output given // by WeightedOperations. if the ordering in WeightedOperations changes some tests @@ -128,7 +143,37 @@ func TestSimulateMsgSubmitProposal(t *testing.T) { app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: app.LastBlockHeight() + 1, AppHash: app.LastCommitID().Hash}}) // execute operation - op := simulation.SimulateMsgSubmitProposal(suite.AccountKeeper, suite.BankKeeper, suite.GovKeeper, MockWeightedProposalContent{3}.ContentSimulatorFn()) + op := simulation.SimulateMsgSubmitProposal(suite.AccountKeeper, suite.BankKeeper, suite.GovKeeper, MockWeightedProposals{3}.MsgSimulatorFn()) + operationMsg, _, err := op(r, app.BaseApp, ctx, accounts, "") + require.NoError(t, err) + + var msg v1.MsgSubmitProposal + err = govcodec.ModuleCdc.UnmarshalJSON(operationMsg.Msg, &msg) + require.NoError(t, err) + + require.True(t, operationMsg.OK) + require.Equal(t, "cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r", msg.Proposer) + require.NotEqual(t, len(msg.InitialDeposit), 0) + require.Equal(t, "560969stake", msg.InitialDeposit[0].String()) + require.Equal(t, simulation.TypeMsgSubmitProposal, sdk.MsgTypeURL(&msg)) +} + +// TestSimulateMsgSubmitProposal tests the normal scenario of a valid message of type TypeMsgSubmitProposal. +// Abnormal scenarios, where errors occur, are not tested here. +func TestSimulateMsgSubmitLegacyProposal(t *testing.T) { + suite, ctx := createTestSuite(t, false) + app := suite.App + + // setup 3 accounts + s := rand.NewSource(1) + r := rand.New(s) + accounts := getTestingAccounts(t, r, suite.AccountKeeper, suite.BankKeeper, suite.StakingKeeper, ctx, 3) + + // begin a new block + app.BeginBlock(abci.RequestBeginBlock{Header: tmproto.Header{Height: app.LastBlockHeight() + 1, AppHash: app.LastCommitID().Hash}}) + + // execute operation + op := simulation.SimulateMsgSubmitLegacyProposal(suite.AccountKeeper, suite.BankKeeper, suite.GovKeeper, MockWeightedProposals{3}.ContentSimulatorFn()) operationMsg, _, err := op(r, app.BaseApp, ctx, accounts, "") require.NoError(t, err) @@ -323,7 +368,6 @@ func TestSimulateMsgVoteWeighted(t *testing.T) { } type suite struct { - cdc codec.Codec AccountKeeper authkeeper.AccountKeeper BankKeeper bankkeeper.Keeper GovKeeper *keeper.Keeper @@ -345,7 +389,7 @@ func createTestSuite(t *testing.T, isCheckTx bool) (suite, sdk.Context) { configurator.ConsensusModule(), configurator.DistributionModule(), configurator.GovModule(), - ), &res.AccountKeeper, &res.BankKeeper, &res.GovKeeper, &res.StakingKeeper, &res.DistributionKeeper, &res.cdc) + ), &res.AccountKeeper, &res.BankKeeper, &res.GovKeeper, &res.StakingKeeper, &res.DistributionKeeper) require.NoError(t, err) ctx := app.BaseApp.NewContext(isCheckTx, tmproto.Header{}) diff --git a/x/gov/simulation/params.go b/x/gov/simulation/params.go deleted file mode 100644 index 138ca15fb0bf..000000000000 --- a/x/gov/simulation/params.go +++ /dev/null @@ -1,67 +0,0 @@ -package simulation - -import ( - "encoding/json" - "fmt" - "math/rand" - - sdk "github.com/cosmos/cosmos-sdk/types" - simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/cosmos/cosmos-sdk/x/gov/types" - "github.com/cosmos/cosmos-sdk/x/simulation" -) - -const ( - keyVotingParams = "votingparams" - keyDepositParams = "depositparams" - keyTallyParams = "tallyparams" - subkeyQuorum = "quorum" - subkeyThreshold = "threshold" - subkeyVeto = "veto" -) - -// ParamChanges defines the parameters that can be modified by param change proposals -// on the simulation -func ParamChanges(r *rand.Rand) []simtypes.ParamChange { - return []simtypes.ParamChange{ - simulation.NewSimParamChange(types.ModuleName, keyVotingParams, - func(r *rand.Rand) string { - return fmt.Sprintf(`{"voting_period": "%d"}`, GenVotingParamsVotingPeriod(r)) - }, - ), - simulation.NewSimParamChange(types.ModuleName, keyDepositParams, - func(r *rand.Rand) string { - return fmt.Sprintf(`{"max_deposit_period": "%d"}`, GenDepositParamsDepositPeriod(r)) - }, - ), - simulation.NewSimParamChange(types.ModuleName, keyTallyParams, - func(r *rand.Rand) string { - changes := []struct { - key string - value sdk.Dec - }{ - {subkeyQuorum, GenTallyParamsQuorum(r)}, - {subkeyThreshold, GenTallyParamsThreshold(r)}, - {subkeyVeto, GenTallyParamsVeto(r)}, - } - - pc := make(map[string]string) - numChanges := simtypes.RandIntBetween(r, 1, len(changes)) - for i := 0; i < numChanges; i++ { - c := changes[r.Intn(len(changes))] - - _, ok := pc[c.key] - for ok { - c := changes[r.Intn(len(changes))] - _, ok = pc[c.key] - } - - pc[c.key] = c.value.String() - } - - bz, _ := json.Marshal(pc) - return string(bz) - }, - ), - } -} diff --git a/x/gov/simulation/params_test.go b/x/gov/simulation/params_test.go deleted file mode 100644 index de528d14d9d5..000000000000 --- a/x/gov/simulation/params_test.go +++ /dev/null @@ -1,37 +0,0 @@ -package simulation_test - -import ( - "math/rand" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/x/gov/simulation" -) - -func TestParamChanges(t *testing.T) { - s := rand.NewSource(1) - r := rand.New(s) - - expected := []struct { - composedKey string - key string - simValue string - subspace string - }{ - {"gov/votingparams", "votingparams", "{\"voting_period\": \"82639000000000\"}", "gov"}, - {"gov/depositparams", "depositparams", "{\"max_deposit_period\": \"47332000000000\"}", "gov"}, - {"gov/tallyparams", "tallyparams", "{\"threshold\":\"0.509000000000000000\"}", "gov"}, - } - - paramChanges := simulation.ParamChanges(r) - require.Len(t, paramChanges, 3) - - for i, p := range paramChanges { - - require.Equal(t, expected[i].composedKey, p.ComposedKey()) - require.Equal(t, expected[i].key, p.Key()) - require.Equal(t, expected[i].simValue, p.SimValue()(r)) - require.Equal(t, expected[i].subspace, p.Subspace()) - } -} diff --git a/x/gov/simulation/proposals.go b/x/gov/simulation/proposals.go index 9a7bfdf21256..4afda5b0e498 100644 --- a/x/gov/simulation/proposals.go +++ b/x/gov/simulation/proposals.go @@ -12,19 +12,40 @@ import ( // OpWeightSubmitTextProposal app params key for text proposal const OpWeightSubmitTextProposal = "op_weight_submit_text_proposal" +// ProposalMsgs defines the module weighted proposals' contents +func ProposalMsgs() []simtypes.WeightedProposalMsg { + return []simtypes.WeightedProposalMsg{ + simulation.NewWeightedProposalMsg( + OpWeightSubmitTextProposal, + DefaultWeightTextProposal, + SimulateTextProposal, + ), + } +} + +// SimulateTextProposal returns a random text proposal content. +// A text proposal is a proposal that contains no msgs. +func SimulateTextProposal(r *rand.Rand, _ sdk.Context, _ []simtypes.Account) sdk.Msg { + return nil +} + // ProposalContents defines the module weighted proposals' contents +// +//nolint:staticcheck func ProposalContents() []simtypes.WeightedProposalContent { return []simtypes.WeightedProposalContent{ simulation.NewWeightedProposalContent( OpWeightMsgDeposit, DefaultWeightTextProposal, - SimulateTextProposalContent, + SimulateLegacyTextProposalContent, ), } } // SimulateTextProposalContent returns a random text proposal content. -func SimulateTextProposalContent(r *rand.Rand, _ sdk.Context, _ []simtypes.Account) simtypes.Content { +// +//nolint:staticcheck +func SimulateLegacyTextProposalContent(r *rand.Rand, _ sdk.Context, _ []simtypes.Account) simtypes.Content { return v1beta1.NewTextProposal( simtypes.RandStringOfLength(r, 140), simtypes.RandStringOfLength(r, 5000), diff --git a/x/gov/simulation/proposals_test.go b/x/gov/simulation/proposals_test.go index f3c4b61ff626..a90c72008121 100644 --- a/x/gov/simulation/proposals_test.go +++ b/x/gov/simulation/proposals_test.go @@ -4,14 +4,36 @@ import ( "math/rand" "testing" - "github.com/stretchr/testify/require" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + "gotest.tools/v3/assert" sdk "github.com/cosmos/cosmos-sdk/types" simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/gov/simulation" ) +func TestProposalMsgs(t *testing.T) { + // initialize parameters + s := rand.NewSource(1) + r := rand.New(s) + + ctx := sdk.NewContext(nil, tmproto.Header{}, true, nil) + accounts := simtypes.RandomAccounts(r, 3) + + // execute ProposalMsgs function + weightedProposalMsgs := simulation.ProposalMsgs() + assert.Assert(t, len(weightedProposalMsgs) == 1) + + w0 := weightedProposalMsgs[0] + + // tests w0 interface: + assert.Equal(t, simulation.OpWeightSubmitTextProposal, w0.AppParamsKey()) + assert.Equal(t, simulation.DefaultWeightTextProposal, w0.DefaultWeight()) + + msg := w0.MsgSimulatorFn()(r, ctx, accounts) + assert.Assert(t, msg == nil) +} + func TestProposalContents(t *testing.T) { // initialize parameters s := rand.NewSource(1) @@ -22,18 +44,18 @@ func TestProposalContents(t *testing.T) { // execute ProposalContents function weightedProposalContent := simulation.ProposalContents() - require.Len(t, weightedProposalContent, 1) + assert.Assert(t, len(weightedProposalContent) == 1) w0 := weightedProposalContent[0] // tests w0 interface: - require.Equal(t, simulation.OpWeightMsgDeposit, w0.AppParamsKey()) - require.Equal(t, simulation.DefaultWeightTextProposal, w0.DefaultWeight()) + assert.Equal(t, simulation.OpWeightMsgDeposit, w0.AppParamsKey()) + assert.Equal(t, simulation.DefaultWeightTextProposal, w0.DefaultWeight()) content := w0.ContentSimulatorFn()(r, ctx, accounts) - require.Equal(t, "NxImpptHBIFDQfnxaTiOBJUgNzvqHbVcVJYlIFWFlzFqqRTTyFzDUMntPzyRamUFqeJAEaSHIuUHZoTWDjWXsYxYvwXwXZEsjRQKgKMselyUqWXMbHzRNDHnMzhWSirUgVggjiBxtWDfhzPDgrorEoNmDEiDdBldYegphCBTYWrmFFXNjxhtygsGBFHTejaKjMsqNdikEzDalEyWRHfJhKqifCKsedVuuJbQMbmRVuIPDluAWGpngjgBjOxuRFwSadayHNIhVVmNWBbfaTOldclxTTLUMvaBnLfwjHTtsKetEIvgrxLijhKJNablmvqpWIWsmhWQAYNLycREypoASHnyKWrxpoNLBJuyCGysZJgXbQAAmSIbGxMFXuwMVGZgBiZWfPWorAfjBeekCFvljHAtVZaTOsRxbPIioNxLTnWUTzGTvaNhplQQPmMADRRDuUIsiBpnGqPheKmLnopieVseFdTSAvOCacxaqFWFuXzsrVZzlGfeRpClwKuGEBujaPrzSLjVIOMvLlWxuznEOXlxbZroBRVEvEfBBAHOECribZNrYiFnzQqQmBnLksmFNAadusWAGltuqYNntgOlgOGwSdDjWdLboWyAWIcCfmpGJTfbljKPriLehwObuszICkaXNUkmeddeeRulbZBXJVLgteiKIfofGdNBregwUPlINQECatDSNXSIuefyMxxoKfcmjHEwbVtFiXtEnLJkLHUghmzFiymrgBChucZgOQUpGGVQEpRtIQjIBxYhtZPgUORdxXNWUMErWrUeriqYJPcgIDgLMWAyuuQnsHncCtjvHmvFbzYErxeunQllYDUVlXaRBveRUKeXwEGJFTSAqZtaBSDGDtzlADCnGjuTmYMJlapRsWfugmjwKEuoXJVpZvlcHeFvVvRRktRVGwzLfKezPEMABZtbLExQIjynSoahmkmoTHefdzFoBHMcQHFkKVHhpNtudPqJrYuQswzFuFHbSmpNltFnYJpvMrAYHFrNouZaanEUGHvbHIUUFTCtZrcpRHwgjblxlDNJWzHdBNpAXKJPHWQdrGYcAHSctgVlqwqHoLfHsXUdStwfefwzqLuKEhmMyYLdbZrcPgYqjNHxPexsruwEGStAneKbWkQDDIlCWBLSiAASNhZqNFlPtfqPJoxKsgMdzjWqLWdqKQuJqWPMvwPQWZUtVMOTMYKJbfdlZsjdsomuScvDmbDkgRualsxDvRJuCAmPOXitIbcyWsKGSdrEunFAOdmXnsuyFVgJqEjbklvmwrUlsxjRSfKZxGcpayDdgoFcnVSutxjRgOSFzPwidAjubMncNweqpbxhXGchpZUxuFDOtpnhNUycJICRYqsPhPSCjPTWZFLkstHWJxvdPEAyEIxXgLwbNOjrgzmaujiBABBIXvcXpLrbcEWNNQsbjvgJFgJkflpRohHUutvnaUqoopuKjTDaemDeSdqbnOzcfJpcTuAQtZoiLZOoAIlboFDAeGmSNwkvObPRvRWQgWkGkxwtPauYgdkmypLjbqhlHJIQTntgWjXwZdOyYEdQRRLfMSdnxqppqUofqLbLQDUjwKVKfZJUJQPsWIPwIVaSTrmKskoAhvmZyJgeRpkaTfGgrJzAigcxtfshmiDCFkuiluqtMOkidknnTBtumyJYlIsWLnCQclqdVmikUoMOPdPWwYbJxXyqUVicNxFxyqJTenNblyyKSdlCbiXxUiYUiMwXZASYfvMDPFgxniSjWaZTjHkqlJvtBsXqwPpyVxnJVGFWhfSxgOcduoxkiopJvFjMmFabrGYeVtTXLhxVUEiGwYUvndjFGzDVntUvibiyZhfMQdMhgsiuysLMiePBNXifRLMsSmXPkwlPloUbJveCvUlaalhZHuvdkCnkSHbMbmOnrfEGPwQiACiPlnihiaOdbjPqPiTXaHDoJXjSlZmltGqNHHNrcKdlFSCdmVOuvDcBLdSklyGJmcLTbSFtALdGlPkqqecJrpLCXNPWefoTJNgEJlyMEPneVaxxduAAEqQpHWZodWyRkDAxzyMnFMcjSVqeRXLqsNyNtQBbuRvunZflWSbbvXXdkyLikYqutQhLPONXbvhcQZJPSWnOulqQaXmbfFxAkqfYeseSHOQidHwbcsOaMnSrrmGjjRmEMQNuknupMxJiIeVjmgZvbmjPIQTEhQFULQLBMPrxcFPvBinaOPYWGvYGRKxLZdwamfRQQFngcdSlvwjfaPbURasIsGJVHtcEAxnIIrhSriiXLOlbEBLXFElXJFGxHJczRBIxAuPKtBisjKBwfzZFagdNmjdwIRvwzLkFKWRTDPxJCmpzHUcrPiiXXHnOIlqNVoGSXZewdnCRhuxeYGPVTfrNTQNOxZmxInOazUYNTNDgzsxlgiVEHPKMfbesvPHUqpNkUqbzeuzfdrsuLDpKHMUbBMKczKKWOdYoIXoPYtEjfOnlQLoGnbQUCuERdEFaptwnsHzTJDsuZkKtzMpFaZobynZdzNydEeJJHDYaQcwUxcqvwfWwNUsCiLvkZQiSfzAHftYgAmVsXgtmcYgTqJIawstRYJrZdSxlfRiqTufgEQVambeZZmaAyRQbcmdjVUZZCgqDrSeltJGXPMgZnGDZqISrGDOClxXCxMjmKqEPwKHoOfOeyGmqWqihqjINXLqnyTesZePQRqaWDQNqpLgNrAUKulklmckTijUltQKuWQDwpLmDyxLppPVMwsmBIpOwQttYFMjgJQZLYFPmxWFLIeZihkRNnkzoypBICIxgEuYsVWGIGRbbxqVasYnstWomJnHwmtOhAFSpttRYYzBmyEtZXiCthvKvWszTXDbiJbGXMcrYpKAgvUVFtdKUfvdMfhAryctklUCEdjetjuGNfJjajZtvzdYaqInKtFPPLYmRaXPdQzxdSQfmZDEVHlHGEGNSPRFJuIfKLLfUmnHxHnRjmzQPNlqrXgifUdzAGKVabYqvcDeYoTYgPsBUqehrBhmQUgTvDnsdpuhUoxskDdppTsYMcnDIPSwKIqhXDCIxOuXrywahvVavvHkPuaenjLmEbMgrkrQLHEAwrhHkPRNvonNQKqprqOFVZKAtpRSpvQUxMoXCMZLSSbnLEFsjVfANdQNQVwTmGxqVjVqRuxREAhuaDrFgEZpYKhwWPEKBevBfsOIcaZKyykQafzmGPLRAKDtTcJxJVgiiuUkmyMYuDUNEUhBEdoBLJnamtLmMJQgmLiUELIhLpiEvpOXOvXCPUeldLFqkKOwfacqIaRcnnZvERKRMCKUkMABbDHytQqQblrvoxOZkwzosQfDKGtIdfcXRJNqlBNwOCWoQBcEWyqrMlYZIAXYJmLfnjoJepgSFvrgajaBAIksoyeHqgqbGvpAstMIGmIhRYGGNPRIfOQKsGoKgxtsidhTaAePRCBFqZgPDWCIkqOJezGVkjfYUCZTlInbxBXwUAVRsxHTQtJFnnpmMvXDYCVlEmnZBKhmmxQOIQzxFWpJQkQoSAYzTEiDWEOsVLNrbfzeHFRyeYATakQQWmFDLPbVMCJcWjFGJjfqCoVzlbNNEsqxdSmNPjTjHYOkuEMFLkXYGaoJlraLqayMeCsTjWNRDPBywBJLAPVkGQqTwApVVwYAetlwSbzsdHWsTwSIcctkyKDuRWYDQikRqsKTMJchrliONJeaZIzwPQrNbTwxsGdwuduvibtYndRwpdsvyCktRHFalvUuEKMqXbItfGcNGWsGzubdPMYayOUOINjpcFBeESdwpdlTYmrPsLsVDhpTzoMegKrytNVZkfJRPuDCUXxSlSthOohmsuxmIZUedzxKmowKOdXTMcEtdpHaPWgIsIjrViKrQOCONlSuazmLuCUjLltOGXeNgJKedTVrrVCpWYWHyVrdXpKgNaMJVjbXxnVMSChdWKuZdqpisvrkBJPoURDYxWOtpjzZoOpWzyUuYNhCzRoHsMjmmWDcXzQiHIyjwdhPNwiPqFxeUfMVFQGImhykFgMIlQEoZCaRoqSBXTSWAeDumdbsOGtATwEdZlLfoBKiTvodQBGOEcuATWXfiinSjPmJKcWgQrTVYVrwlyMWhxqNbCMpIQNoSMGTiWfPTCezUjYcdWppnsYJihLQCqbNLRGgqrwHuIvsazapTpoPZIyZyeeSueJuTIhpHMEJfJpScshJubJGfkusuVBgfTWQoywSSliQQSfbvaHKiLnyjdSbpMkdBgXepoSsHnCQaYuHQqZsoEOmJCiuQUpJkmfyfbIShzlZpHFmLCsbknEAkKXKfRTRnuwdBeuOGgFbJLbDksHVapaRayWzwoYBEpmrlAxrUxYMUekKbpjPNfjUCjhbdMAnJmYQVZBQZkFVweHDAlaqJjRqoQPoOMLhyvYCzqEuQsAFoxWrzRnTVjStPadhsESlERnKhpEPsfDxNvxqcOyIulaCkmPdambLHvGhTZzysvqFauEgkFRItPfvisehFmoBhQqmkfbHVsgfHXDPJVyhwPllQpuYLRYvGodxKjkarnSNgsXoKEMlaSKxKdcVgvOkuLcfLFfdtXGTclqfPOfeoVLbqcjcXCUEBgAGplrkgsmIEhWRZLlGPGCwKWRaCKMkBHTAcypUrYjWwCLtOPVygMwMANGoQwFnCqFrUGMCRZUGJKTZIGPyldsifauoMnJPLTcDHmilcmahlqOELaAUYDBuzsVywnDQfwRLGIWozYaOAilMBcObErwgTDNGWnwQMUgFFSKtPDMEoEQCTKVREqrXZSGLqwTMcxHfWotDllNkIJPMbXzjDVjPOOjCFuIvTyhXKLyhUScOXvYthRXpPfKwMhptXaxIxgqBoUqzrWbaoLTVpQoottZyPFfNOoMioXHRuFwMRYUiKvcWPkrayyTLOCFJlAyslDameIuqVAuxErqFPEWIScKpBORIuZqoXlZuTvAjEdlEWDODFRregDTqGNoFBIHxvimmIZwLfFyKUfEWAnNBdtdzDmTPXtpHRGdIbuucfTjOygZsTxPjf", content.GetDescription()) - require.Equal(t, "XhSUkMhPjMaxKlMIJMOXcnQfyzeOcbWwNbeHVIkPZBSpYuLyYggwexjxusrBqDOTtGTOWeLrQKjLxzIivHSlcxgdXhhuTSkuxKGLwQvuyNhYFmBZHeAerqyNEUzXPFGkqEGqiQWIXnku", content.GetTitle()) - require.Equal(t, "gov", content.ProposalRoute()) - require.Equal(t, "Text", content.ProposalType()) + assert.Equal(t, "NxImpptHBIFDQfnxaTiOBJUgNzvqHbVcVJYlIFWFlzFqqRTTyFzDUMntPzyRamUFqeJAEaSHIuUHZoTWDjWXsYxYvwXwXZEsjRQKgKMselyUqWXMbHzRNDHnMzhWSirUgVggjiBxtWDfhzPDgrorEoNmDEiDdBldYegphCBTYWrmFFXNjxhtygsGBFHTejaKjMsqNdikEzDalEyWRHfJhKqifCKsedVuuJbQMbmRVuIPDluAWGpngjgBjOxuRFwSadayHNIhVVmNWBbfaTOldclxTTLUMvaBnLfwjHTtsKetEIvgrxLijhKJNablmvqpWIWsmhWQAYNLycREypoASHnyKWrxpoNLBJuyCGysZJgXbQAAmSIbGxMFXuwMVGZgBiZWfPWorAfjBeekCFvljHAtVZaTOsRxbPIioNxLTnWUTzGTvaNhplQQPmMADRRDuUIsiBpnGqPheKmLnopieVseFdTSAvOCacxaqFWFuXzsrVZzlGfeRpClwKuGEBujaPrzSLjVIOMvLlWxuznEOXlxbZroBRVEvEfBBAHOECribZNrYiFnzQqQmBnLksmFNAadusWAGltuqYNntgOlgOGwSdDjWdLboWyAWIcCfmpGJTfbljKPriLehwObuszICkaXNUkmeddeeRulbZBXJVLgteiKIfofGdNBregwUPlINQECatDSNXSIuefyMxxoKfcmjHEwbVtFiXtEnLJkLHUghmzFiymrgBChucZgOQUpGGVQEpRtIQjIBxYhtZPgUORdxXNWUMErWrUeriqYJPcgIDgLMWAyuuQnsHncCtjvHmvFbzYErxeunQllYDUVlXaRBveRUKeXwEGJFTSAqZtaBSDGDtzlADCnGjuTmYMJlapRsWfugmjwKEuoXJVpZvlcHeFvVvRRktRVGwzLfKezPEMABZtbLExQIjynSoahmkmoTHefdzFoBHMcQHFkKVHhpNtudPqJrYuQswzFuFHbSmpNltFnYJpvMrAYHFrNouZaanEUGHvbHIUUFTCtZrcpRHwgjblxlDNJWzHdBNpAXKJPHWQdrGYcAHSctgVlqwqHoLfHsXUdStwfefwzqLuKEhmMyYLdbZrcPgYqjNHxPexsruwEGStAneKbWkQDDIlCWBLSiAASNhZqNFlPtfqPJoxKsgMdzjWqLWdqKQuJqWPMvwPQWZUtVMOTMYKJbfdlZsjdsomuScvDmbDkgRualsxDvRJuCAmPOXitIbcyWsKGSdrEunFAOdmXnsuyFVgJqEjbklvmwrUlsxjRSfKZxGcpayDdgoFcnVSutxjRgOSFzPwidAjubMncNweqpbxhXGchpZUxuFDOtpnhNUycJICRYqsPhPSCjPTWZFLkstHWJxvdPEAyEIxXgLwbNOjrgzmaujiBABBIXvcXpLrbcEWNNQsbjvgJFgJkflpRohHUutvnaUqoopuKjTDaemDeSdqbnOzcfJpcTuAQtZoiLZOoAIlboFDAeGmSNwkvObPRvRWQgWkGkxwtPauYgdkmypLjbqhlHJIQTntgWjXwZdOyYEdQRRLfMSdnxqppqUofqLbLQDUjwKVKfZJUJQPsWIPwIVaSTrmKskoAhvmZyJgeRpkaTfGgrJzAigcxtfshmiDCFkuiluqtMOkidknnTBtumyJYlIsWLnCQclqdVmikUoMOPdPWwYbJxXyqUVicNxFxyqJTenNblyyKSdlCbiXxUiYUiMwXZASYfvMDPFgxniSjWaZTjHkqlJvtBsXqwPpyVxnJVGFWhfSxgOcduoxkiopJvFjMmFabrGYeVtTXLhxVUEiGwYUvndjFGzDVntUvibiyZhfMQdMhgsiuysLMiePBNXifRLMsSmXPkwlPloUbJveCvUlaalhZHuvdkCnkSHbMbmOnrfEGPwQiACiPlnihiaOdbjPqPiTXaHDoJXjSlZmltGqNHHNrcKdlFSCdmVOuvDcBLdSklyGJmcLTbSFtALdGlPkqqecJrpLCXNPWefoTJNgEJlyMEPneVaxxduAAEqQpHWZodWyRkDAxzyMnFMcjSVqeRXLqsNyNtQBbuRvunZflWSbbvXXdkyLikYqutQhLPONXbvhcQZJPSWnOulqQaXmbfFxAkqfYeseSHOQidHwbcsOaMnSrrmGjjRmEMQNuknupMxJiIeVjmgZvbmjPIQTEhQFULQLBMPrxcFPvBinaOPYWGvYGRKxLZdwamfRQQFngcdSlvwjfaPbURasIsGJVHtcEAxnIIrhSriiXLOlbEBLXFElXJFGxHJczRBIxAuPKtBisjKBwfzZFagdNmjdwIRvwzLkFKWRTDPxJCmpzHUcrPiiXXHnOIlqNVoGSXZewdnCRhuxeYGPVTfrNTQNOxZmxInOazUYNTNDgzsxlgiVEHPKMfbesvPHUqpNkUqbzeuzfdrsuLDpKHMUbBMKczKKWOdYoIXoPYtEjfOnlQLoGnbQUCuERdEFaptwnsHzTJDsuZkKtzMpFaZobynZdzNydEeJJHDYaQcwUxcqvwfWwNUsCiLvkZQiSfzAHftYgAmVsXgtmcYgTqJIawstRYJrZdSxlfRiqTufgEQVambeZZmaAyRQbcmdjVUZZCgqDrSeltJGXPMgZnGDZqISrGDOClxXCxMjmKqEPwKHoOfOeyGmqWqihqjINXLqnyTesZePQRqaWDQNqpLgNrAUKulklmckTijUltQKuWQDwpLmDyxLppPVMwsmBIpOwQttYFMjgJQZLYFPmxWFLIeZihkRNnkzoypBICIxgEuYsVWGIGRbbxqVasYnstWomJnHwmtOhAFSpttRYYzBmyEtZXiCthvKvWszTXDbiJbGXMcrYpKAgvUVFtdKUfvdMfhAryctklUCEdjetjuGNfJjajZtvzdYaqInKtFPPLYmRaXPdQzxdSQfmZDEVHlHGEGNSPRFJuIfKLLfUmnHxHnRjmzQPNlqrXgifUdzAGKVabYqvcDeYoTYgPsBUqehrBhmQUgTvDnsdpuhUoxskDdppTsYMcnDIPSwKIqhXDCIxOuXrywahvVavvHkPuaenjLmEbMgrkrQLHEAwrhHkPRNvonNQKqprqOFVZKAtpRSpvQUxMoXCMZLSSbnLEFsjVfANdQNQVwTmGxqVjVqRuxREAhuaDrFgEZpYKhwWPEKBevBfsOIcaZKyykQafzmGPLRAKDtTcJxJVgiiuUkmyMYuDUNEUhBEdoBLJnamtLmMJQgmLiUELIhLpiEvpOXOvXCPUeldLFqkKOwfacqIaRcnnZvERKRMCKUkMABbDHytQqQblrvoxOZkwzosQfDKGtIdfcXRJNqlBNwOCWoQBcEWyqrMlYZIAXYJmLfnjoJepgSFvrgajaBAIksoyeHqgqbGvpAstMIGmIhRYGGNPRIfOQKsGoKgxtsidhTaAePRCBFqZgPDWCIkqOJezGVkjfYUCZTlInbxBXwUAVRsxHTQtJFnnpmMvXDYCVlEmnZBKhmmxQOIQzxFWpJQkQoSAYzTEiDWEOsVLNrbfzeHFRyeYATakQQWmFDLPbVMCJcWjFGJjfqCoVzlbNNEsqxdSmNPjTjHYOkuEMFLkXYGaoJlraLqayMeCsTjWNRDPBywBJLAPVkGQqTwApVVwYAetlwSbzsdHWsTwSIcctkyKDuRWYDQikRqsKTMJchrliONJeaZIzwPQrNbTwxsGdwuduvibtYndRwpdsvyCktRHFalvUuEKMqXbItfGcNGWsGzubdPMYayOUOINjpcFBeESdwpdlTYmrPsLsVDhpTzoMegKrytNVZkfJRPuDCUXxSlSthOohmsuxmIZUedzxKmowKOdXTMcEtdpHaPWgIsIjrViKrQOCONlSuazmLuCUjLltOGXeNgJKedTVrrVCpWYWHyVrdXpKgNaMJVjbXxnVMSChdWKuZdqpisvrkBJPoURDYxWOtpjzZoOpWzyUuYNhCzRoHsMjmmWDcXzQiHIyjwdhPNwiPqFxeUfMVFQGImhykFgMIlQEoZCaRoqSBXTSWAeDumdbsOGtATwEdZlLfoBKiTvodQBGOEcuATWXfiinSjPmJKcWgQrTVYVrwlyMWhxqNbCMpIQNoSMGTiWfPTCezUjYcdWppnsYJihLQCqbNLRGgqrwHuIvsazapTpoPZIyZyeeSueJuTIhpHMEJfJpScshJubJGfkusuVBgfTWQoywSSliQQSfbvaHKiLnyjdSbpMkdBgXepoSsHnCQaYuHQqZsoEOmJCiuQUpJkmfyfbIShzlZpHFmLCsbknEAkKXKfRTRnuwdBeuOGgFbJLbDksHVapaRayWzwoYBEpmrlAxrUxYMUekKbpjPNfjUCjhbdMAnJmYQVZBQZkFVweHDAlaqJjRqoQPoOMLhyvYCzqEuQsAFoxWrzRnTVjStPadhsESlERnKhpEPsfDxNvxqcOyIulaCkmPdambLHvGhTZzysvqFauEgkFRItPfvisehFmoBhQqmkfbHVsgfHXDPJVyhwPllQpuYLRYvGodxKjkarnSNgsXoKEMlaSKxKdcVgvOkuLcfLFfdtXGTclqfPOfeoVLbqcjcXCUEBgAGplrkgsmIEhWRZLlGPGCwKWRaCKMkBHTAcypUrYjWwCLtOPVygMwMANGoQwFnCqFrUGMCRZUGJKTZIGPyldsifauoMnJPLTcDHmilcmahlqOELaAUYDBuzsVywnDQfwRLGIWozYaOAilMBcObErwgTDNGWnwQMUgFFSKtPDMEoEQCTKVREqrXZSGLqwTMcxHfWotDllNkIJPMbXzjDVjPOOjCFuIvTyhXKLyhUScOXvYthRXpPfKwMhptXaxIxgqBoUqzrWbaoLTVpQoottZyPFfNOoMioXHRuFwMRYUiKvcWPkrayyTLOCFJlAyslDameIuqVAuxErqFPEWIScKpBORIuZqoXlZuTvAjEdlEWDODFRregDTqGNoFBIHxvimmIZwLfFyKUfEWAnNBdtdzDmTPXtpHRGdIbuucfTjOygZsTxPjf", content.GetDescription()) + assert.Equal(t, "XhSUkMhPjMaxKlMIJMOXcnQfyzeOcbWwNbeHVIkPZBSpYuLyYggwexjxusrBqDOTtGTOWeLrQKjLxzIivHSlcxgdXhhuTSkuxKGLwQvuyNhYFmBZHeAerqyNEUzXPFGkqEGqiQWIXnku", content.GetTitle()) + assert.Equal(t, "gov", content.ProposalRoute()) + assert.Equal(t, "Text", content.ProposalType()) } diff --git a/x/group/module/module.go b/x/group/module/module.go index 1313f72277ce..6595ae71876b 100644 --- a/x/group/module/module.go +++ b/x/group/module/module.go @@ -173,12 +173,6 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) { simulation.RandomizedGenState(simState) } -// ProposalContents returns all the group content functions used to -// simulate governance proposals. -func (am AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent { - return nil -} - // RegisterStoreDecoder registers a decoder for group module's types func (am AppModule) RegisterStoreDecoder(sdr simtypes.StoreDecoderRegistry) { sdr[group.StoreKey] = simulation.NewDecodeStore(am.cdc) diff --git a/x/mint/module.go b/x/mint/module.go index ae35916feab7..6fe567b3386f 100644 --- a/x/mint/module.go +++ b/x/mint/module.go @@ -191,9 +191,9 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) { simulation.RandomizedGenState(simState) } -// ProposalContents doesn't return any content functions for governance proposals. -func (AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent { - return nil +// ProposalMsgs returns msgs used for governance proposals for simulations. +func (AppModule) ProposalMsgs(simState module.SimulationState) []simtypes.WeightedProposalMsg { + return simulation.ProposalMsgs() } // RegisterStoreDecoder registers a decoder for mint module's types. diff --git a/x/mint/simulation/params.go b/x/mint/simulation/params.go deleted file mode 100644 index 34927567e185..000000000000 --- a/x/mint/simulation/params.go +++ /dev/null @@ -1,45 +0,0 @@ -package simulation - -import ( - "fmt" - "math/rand" - - "github.com/cosmos/cosmos-sdk/x/simulation" - - simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/cosmos/cosmos-sdk/x/mint/types" -) - -const ( - keyInflationRateChange = "InflationRateChange" - keyInflationMax = "InflationMax" - keyInflationMin = "InflationMin" - keyGoalBonded = "GoalBonded" -) - -// ParamChanges defines the parameters that can be modified by param change proposals -// on the simulation -func ParamChanges(r *rand.Rand) []simtypes.ParamChange { - return []simtypes.ParamChange{ - simulation.NewSimParamChange(types.ModuleName, keyInflationRateChange, - func(r *rand.Rand) string { - return fmt.Sprintf("\"%s\"", GenInflationRateChange(r)) - }, - ), - simulation.NewSimParamChange(types.ModuleName, keyInflationMax, - func(r *rand.Rand) string { - return fmt.Sprintf("\"%s\"", GenInflationMax(r)) - }, - ), - simulation.NewSimParamChange(types.ModuleName, keyInflationMin, - func(r *rand.Rand) string { - return fmt.Sprintf("\"%s\"", GenInflationMin(r)) - }, - ), - simulation.NewSimParamChange(types.ModuleName, keyGoalBonded, - func(r *rand.Rand) string { - return fmt.Sprintf("\"%s\"", GenGoalBonded(r)) - }, - ), - } -} diff --git a/x/mint/simulation/params_test.go b/x/mint/simulation/params_test.go deleted file mode 100644 index 3334fbd51a97..000000000000 --- a/x/mint/simulation/params_test.go +++ /dev/null @@ -1,37 +0,0 @@ -package simulation_test - -import ( - "math/rand" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/x/mint/simulation" -) - -func TestParamChangest(t *testing.T) { - s := rand.NewSource(1) - r := rand.New(s) - - expected := []struct { - composedKey string - key string - simValue string - subspace string - }{ - {"mint/InflationRateChange", "InflationRateChange", "\"0.230000000000000000\"", "mint"}, - {"mint/InflationMax", "InflationMax", "\"0.200000000000000000\"", "mint"}, - {"mint/InflationMin", "InflationMin", "\"0.070000000000000000\"", "mint"}, - {"mint/GoalBonded", "GoalBonded", "\"0.670000000000000000\"", "mint"}, - } - - paramChanges := simulation.ParamChanges(r) - require.Len(t, paramChanges, 4) - - for i, p := range paramChanges { - require.Equal(t, expected[i].composedKey, p.ComposedKey()) - require.Equal(t, expected[i].key, p.Key()) - require.Equal(t, expected[i].simValue, p.SimValue()(r)) - require.Equal(t, expected[i].subspace, p.Subspace()) - } -} diff --git a/x/mint/simulation/proposals.go b/x/mint/simulation/proposals.go new file mode 100644 index 000000000000..129658adcf22 --- /dev/null +++ b/x/mint/simulation/proposals.go @@ -0,0 +1,48 @@ +package simulation + +import ( + "math/rand" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/mint/types" + "github.com/cosmos/cosmos-sdk/x/simulation" +) + +// Simulation operation weights constants +const ( + DefaultWeightMsgUpdateParams int = 100 + + OpWeightMsgUpdateParams = "op_weight_msg_update_params" //nolint:gosec +) + +// ProposalMsgs defines the module weighted proposals' contents +func ProposalMsgs() []simtypes.WeightedProposalMsg { + return []simtypes.WeightedProposalMsg{ + simulation.NewWeightedProposalMsg( + OpWeightMsgUpdateParams, + DefaultWeightMsgUpdateParams, + SimulateMsgUpdateParams, + ), + } +} + +// SimulateMsgUpdateParams returns a random MsgUpdateParams +func SimulateMsgUpdateParams(r *rand.Rand, _ sdk.Context, _ []simtypes.Account) sdk.Msg { + // use the default gov module account address as authority + var authority sdk.AccAddress = address.Module("gov") + + params := types.DefaultParams() + params.BlocksPerYear = uint64(simtypes.RandIntBetween(r, 1, 1000000)) + params.GoalBonded = sdk.NewDecWithPrec(int64(simtypes.RandIntBetween(r, 1, 100)), 2) + params.InflationMin = sdk.NewDecWithPrec(int64(simtypes.RandIntBetween(r, 1, 50)), 2) + params.InflationMax = sdk.NewDecWithPrec(int64(simtypes.RandIntBetween(r, 50, 100)), 2) + params.InflationRateChange = sdk.NewDecWithPrec(int64(simtypes.RandIntBetween(r, 1, 100)), 2) + params.MintDenom = simtypes.RandStringOfLength(r, 10) + + return &types.MsgUpdateParams{ + Authority: authority.String(), + Params: params, + } +} diff --git a/x/mint/simulation/proposals_test.go b/x/mint/simulation/proposals_test.go new file mode 100644 index 000000000000..eb14b31ad5b9 --- /dev/null +++ b/x/mint/simulation/proposals_test.go @@ -0,0 +1,46 @@ +package simulation_test + +import ( + "math/rand" + "testing" + + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + "gotest.tools/v3/assert" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/mint/simulation" + "github.com/cosmos/cosmos-sdk/x/mint/types" +) + +func TestProposalMsgs(t *testing.T) { + // initialize parameters + s := rand.NewSource(1) + r := rand.New(s) + + ctx := sdk.NewContext(nil, tmproto.Header{}, true, nil) + accounts := simtypes.RandomAccounts(r, 3) + + // execute ProposalMsgs function + weightedProposalMsgs := simulation.ProposalMsgs() + assert.Assert(t, len(weightedProposalMsgs) == 1) + + w0 := weightedProposalMsgs[0] + + // tests w0 interface: + assert.Equal(t, simulation.OpWeightMsgUpdateParams, w0.AppParamsKey()) + assert.Equal(t, simulation.DefaultWeightMsgUpdateParams, w0.DefaultWeight()) + + msg := w0.MsgSimulatorFn()(r, ctx, accounts) + msgUpdateParams, ok := msg.(*types.MsgUpdateParams) + assert.Assert(t, ok) + + assert.Equal(t, sdk.AccAddress(address.Module("gov")).String(), msgUpdateParams.Authority) + assert.Equal(t, uint64(122877), msgUpdateParams.Params.BlocksPerYear) + assert.DeepEqual(t, sdk.NewDecWithPrec(95, 2), msgUpdateParams.Params.GoalBonded) + assert.DeepEqual(t, sdk.NewDecWithPrec(94, 2), msgUpdateParams.Params.InflationMax) + assert.DeepEqual(t, sdk.NewDecWithPrec(23, 2), msgUpdateParams.Params.InflationMin) + assert.DeepEqual(t, sdk.NewDecWithPrec(89, 2), msgUpdateParams.Params.InflationRateChange) + assert.Equal(t, "XhhuTSkuxK", msgUpdateParams.Params.MintDenom) +} diff --git a/x/nft/simulation/operations.go b/x/nft/simulation/operations.go index 68159a672e3a..7667d7067388 100644 --- a/x/nft/simulation/operations.go +++ b/x/nft/simulation/operations.go @@ -16,13 +16,10 @@ import ( "cosmossdk.io/x/nft/keeper" ) -//nolint:gosec // these are not hardcoded credentials. const ( // OpWeightMsgSend Simulation operation weights constants - OpWeightMsgSend = "op_weight_msg_send" -) + OpWeightMsgSend = "op_weight_msg_send" //nolint:gosec -const ( // WeightSend nft operations weights WeightSend = 100 ) diff --git a/x/params/module.go b/x/params/module.go index 4a6e61e3688d..400aeb09b5bd 100644 --- a/x/params/module.go +++ b/x/params/module.go @@ -114,12 +114,6 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { proposal.RegisterQueryServer(cfg.QueryServer(), am.keeper) } -// ProposalContents returns all the params content functions used to -// simulate governance proposals. -func (am AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent { - return nil -} - // RegisterStoreDecoder doesn't register any type. func (AppModule) RegisterStoreDecoder(sdr simtypes.StoreDecoderRegistry) {} diff --git a/x/params/simulation/operations.go b/x/params/simulation/operations.go index 6e7619b7032b..fe6a5069e6b7 100644 --- a/x/params/simulation/operations.go +++ b/x/params/simulation/operations.go @@ -19,7 +19,7 @@ func min(a int, b int) int { // 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) simulation.ContentSimulatorFn { +func SimulateParamChangeProposalContent(paramChangePool []simulation.LegacyParamChange) simulation.ContentSimulatorFn { //nolint:staticcheck numProposals := 0 // Bound the maximum number of simultaneous parameter changes maxSimultaneousParamChanges := min(len(paramChangePool), 1000) @@ -27,7 +27,7 @@ func SimulateParamChangeProposalContent(paramChangePool []simulation.ParamChange panic("param changes array is empty") } - return func(r *rand.Rand, _ sdk.Context, _ []simulation.Account) simulation.Content { + return func(r *rand.Rand, _ sdk.Context, _ []simulation.Account) simulation.Content { //nolint:staticcheck numChanges := simulation.RandIntBetween(r, 1, maxSimultaneousParamChanges) paramChanges := make([]proposal.ParamChange, numChanges) diff --git a/x/params/simulation/operations_test.go b/x/params/simulation/operations_test.go index 5ed1ba8a50fc..5e4f4e93e193 100644 --- a/x/params/simulation/operations_test.go +++ b/x/params/simulation/operations_test.go @@ -37,7 +37,7 @@ func (pc MockParamChange) SimValue() simtypes.SimValFn { } // make sure that the MockParamChange satisfied the ParamChange interface -var _ simtypes.ParamChange = MockParamChange{} +var _ simtypes.LegacyParamChange = MockParamChange{} func TestSimulateParamChangeProposalContent(t *testing.T) { s := rand.NewSource(1) @@ -45,7 +45,7 @@ func TestSimulateParamChangeProposalContent(t *testing.T) { ctx := sdk.NewContext(nil, tmproto.Header{}, true, nil) accounts := simtypes.RandomAccounts(r, 3) - paramChangePool := []simtypes.ParamChange{MockParamChange{1}, MockParamChange{2}, MockParamChange{3}} + paramChangePool := []simtypes.LegacyParamChange{MockParamChange{1}, MockParamChange{2}, MockParamChange{3}} // execute operation op := simulation.SimulateParamChangeProposalContent(paramChangePool) diff --git a/x/params/simulation/proposals.go b/x/params/simulation/proposals.go index 551f940754be..30b8f8434794 100644 --- a/x/params/simulation/proposals.go +++ b/x/params/simulation/proposals.go @@ -12,7 +12,9 @@ const ( ) // ProposalContents defines the module weighted proposals' contents -func ProposalContents(paramChanges []simtypes.ParamChange) []simtypes.WeightedProposalContent { +// +//nolint:staticcheck +func ProposalContents(paramChanges []simtypes.LegacyParamChange) []simtypes.WeightedProposalContent { return []simtypes.WeightedProposalContent{ simulation.NewWeightedProposalContent( OpWeightSubmitParamChangeProposal, diff --git a/x/params/simulation/proposals_test.go b/x/params/simulation/proposals_test.go index 1ae2b413259d..e09202a6fe31 100644 --- a/x/params/simulation/proposals_test.go +++ b/x/params/simulation/proposals_test.go @@ -21,7 +21,7 @@ func TestProposalContents(t *testing.T) { ctx := sdk.NewContext(nil, tmproto.Header{}, true, nil) accounts := simtypes.RandomAccounts(r, 3) - paramChangePool := []simtypes.ParamChange{MockParamChange{1}, MockParamChange{2}, MockParamChange{3}} + paramChangePool := []simtypes.LegacyParamChange{MockParamChange{1}, MockParamChange{2}, MockParamChange{3}} // execute ProposalContents function weightedProposalContent := simulation.ProposalContents(paramChangePool) diff --git a/x/simulation/params.go b/x/simulation/params.go index acc7d9b6d8f7..4ef3d2201a6b 100644 --- a/x/simulation/params.go +++ b/x/simulation/params.go @@ -86,52 +86,78 @@ func RandomParams(r *rand.Rand) Params { } } -// Param change proposals +// Legacy param change proposals -// ParamChange defines the object used for simulating parameter change proposals -type ParamChange struct { +// LegacyParamChange defines the object used for simulating parameter change proposals +type LegacyParamChange struct { subspace string key string simValue simulation.SimValFn } -func (spc ParamChange) Subspace() string { +func (spc LegacyParamChange) Subspace() string { return spc.subspace } -func (spc ParamChange) Key() string { +func (spc LegacyParamChange) Key() string { return spc.key } -func (spc ParamChange) SimValue() simulation.SimValFn { +func (spc LegacyParamChange) SimValue() simulation.SimValFn { return spc.simValue } -// NewSimParamChange creates a new ParamChange instance -func NewSimParamChange(subspace, key string, simVal simulation.SimValFn) simulation.ParamChange { - return ParamChange{ +// ComposedKey creates a new composed key for the legacy param change proposal +func (spc LegacyParamChange) ComposedKey() string { + return spc.Subspace() + "/" + spc.Key() +} + +// NewSimLegacyParamChange creates a new LegacyParamChange instance +func NewSimLegacyParamChange(subspace, key string, simVal simulation.SimValFn) simulation.LegacyParamChange { + return LegacyParamChange{ subspace: subspace, key: key, simValue: simVal, } } -// ComposedKey creates a new composed key for the param change proposal -func (spc ParamChange) ComposedKey() string { - return spc.Subspace() + "/" + spc.Key() +// Proposal Msgs + +// WeightedProposalMsg defines a common struct for proposal msgs defined by external modules (i.e outside gov) +type WeightedProposalMsg struct { + appParamsKey string // key used to retrieve the value of the weight from the simulation application params + defaultWeight int // default weight + msgSimulatorFn simulation.MsgSimulatorFn // msg simulator function +} + +func NewWeightedProposalMsg(appParamsKey string, defaultWeight int, msgSimulatorFn simulation.MsgSimulatorFn) simulation.WeightedProposalMsg { + return &WeightedProposalMsg{appParamsKey: appParamsKey, defaultWeight: defaultWeight, msgSimulatorFn: msgSimulatorFn} +} + +func (w WeightedProposalMsg) AppParamsKey() string { + return w.appParamsKey +} + +func (w WeightedProposalMsg) DefaultWeight() int { + return w.defaultWeight +} + +func (w WeightedProposalMsg) MsgSimulatorFn() simulation.MsgSimulatorFn { + return w.msgSimulatorFn } -// Proposal Contents +// Legacy Proposal Content -// WeightedProposalContent defines a common struct for proposal contents defined by -// external modules (i.e outside gov) +// WeightedProposalContent defines a common struct for proposal content defined by external modules (i.e outside gov) +// +//nolint:staticcheck type WeightedProposalContent struct { appParamsKey string // key used to retrieve the value of the weight from the simulation application params defaultWeight int // default weight contentSimulatorFn simulation.ContentSimulatorFn // content simulator function } -func NewWeightedProposalContent(appParamsKey string, defaultWeight int, contentSimulatorFn simulation.ContentSimulatorFn) simulation.WeightedProposalContent { +func NewWeightedProposalContent(appParamsKey string, defaultWeight int, contentSimulatorFn simulation.ContentSimulatorFn) simulation.WeightedProposalContent { //nolint:staticcheck return &WeightedProposalContent{appParamsKey: appParamsKey, defaultWeight: defaultWeight, contentSimulatorFn: contentSimulatorFn} } @@ -143,11 +169,11 @@ func (w WeightedProposalContent) DefaultWeight() int { return w.defaultWeight } -func (w WeightedProposalContent) ContentSimulatorFn() simulation.ContentSimulatorFn { +func (w WeightedProposalContent) ContentSimulatorFn() simulation.ContentSimulatorFn { //nolint:staticcheck return w.contentSimulatorFn } -// Param change proposals +// Consensus Params // randomConsensusParams returns random simulation consensus parameters, it extracts the Evidence from the Staking genesis state. func randomConsensusParams(r *rand.Rand, appState json.RawMessage, cdc codec.JSONCodec) *tmproto.ConsensusParams { diff --git a/x/simulation/params_test.go b/x/simulation/params_test.go index 90eb4f22a0a4..23f0bb129f45 100644 --- a/x/simulation/params_test.go +++ b/x/simulation/params_test.go @@ -12,13 +12,13 @@ import ( simtypes "github.com/cosmos/cosmos-sdk/types/simulation" ) -func TestParamChange(t *testing.T) { +func TestLegacyParamChange(t *testing.T) { subspace, key := "theSubspace", "key" f := func(r *rand.Rand) string { return "theResult" } - pChange := NewSimParamChange(subspace, key, f) + pChange := NewSimLegacyParamChange(subspace, key, f) require.Equal(t, subspace, pChange.Subspace()) require.Equal(t, key, pChange.Key()) @@ -30,7 +30,7 @@ func TestNewWeightedProposalContent(t *testing.T) { key := "theKey" weight := 1 content := &testContent{} - f := func(r *rand.Rand, ctx sdk.Context, accs []simtypes.Account) simtypes.Content { + f := func(r *rand.Rand, ctx sdk.Context, accs []simtypes.Account) simtypes.Content { //nolint:staticcheck return content } diff --git a/x/slashing/module.go b/x/slashing/module.go index 0f1fb1b92dbe..442a90d45c9f 100644 --- a/x/slashing/module.go +++ b/x/slashing/module.go @@ -182,9 +182,9 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) { simulation.RandomizedGenState(simState) } -// ProposalContents doesn't return any content functions for governance proposals. -func (AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent { - return nil +// ProposalMsgs returns msgs used for governance proposals for simulations. +func (AppModule) ProposalMsgs(simState module.SimulationState) []simtypes.WeightedProposalMsg { + return simulation.ProposalMsgs() } // RegisterStoreDecoder registers a decoder for slashing module's types diff --git a/x/slashing/simulation/operations.go b/x/slashing/simulation/operations.go index 3abf711d82cf..41649e2793d1 100644 --- a/x/slashing/simulation/operations.go +++ b/x/slashing/simulation/operations.go @@ -18,10 +18,9 @@ import ( ) // Simulation operation weights constants -// -//nolint:gosec // these are not hardcoded credentials. const ( - OpWeightMsgUnjail = "op_weight_msg_unjail" + OpWeightMsgUnjail = "op_weight_msg_unjail" //nolint:gosec + DefaultWeightMsgUnjail = 100 ) @@ -31,6 +30,7 @@ func WeightedOperations( bk types.BankKeeper, k keeper.Keeper, sk types.StakingKeeper, ) simulation.WeightedOperations { interfaceRegistry := codectypes.NewInterfaceRegistry() + var weightMsgUnjail int appParams.GetOrGenerate(cdc, OpWeightMsgUnjail, &weightMsgUnjail, nil, func(_ *rand.Rand) { diff --git a/x/slashing/simulation/params.go b/x/slashing/simulation/params.go deleted file mode 100644 index 20d7f682589a..000000000000 --- a/x/slashing/simulation/params.go +++ /dev/null @@ -1,38 +0,0 @@ -package simulation - -import ( - "fmt" - "math/rand" - - simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/cosmos/cosmos-sdk/x/simulation" - "github.com/cosmos/cosmos-sdk/x/slashing/types" -) - -const ( - keySignedBlocksWindow = "SignedBlocksWindow" - keyMinSignedPerWindow = "MinSignedPerWindow" - keySlashFractionDowntime = "SlashFractionDowntime" -) - -// ParamChanges defines the parameters that can be modified by param change proposals -// on the simulation -func ParamChanges(r *rand.Rand) []simtypes.ParamChange { - return []simtypes.ParamChange{ - simulation.NewSimParamChange(types.ModuleName, keySignedBlocksWindow, - func(r *rand.Rand) string { - return fmt.Sprintf("\"%d\"", GenSignedBlocksWindow(r)) - }, - ), - simulation.NewSimParamChange(types.ModuleName, keyMinSignedPerWindow, - func(r *rand.Rand) string { - return fmt.Sprintf("\"%s\"", GenMinSignedPerWindow(r)) - }, - ), - simulation.NewSimParamChange(types.ModuleName, keySlashFractionDowntime, - func(r *rand.Rand) string { - return fmt.Sprintf("\"%s\"", GenSlashFractionDowntime(r)) - }, - ), - } -} diff --git a/x/slashing/simulation/params_test.go b/x/slashing/simulation/params_test.go deleted file mode 100644 index 2f1933c60ad2..000000000000 --- a/x/slashing/simulation/params_test.go +++ /dev/null @@ -1,37 +0,0 @@ -package simulation_test - -import ( - "math/rand" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/x/slashing/simulation" -) - -func TestParamChanges(t *testing.T) { - s := rand.NewSource(1) - r := rand.New(s) - - expected := []struct { - composedKey string - key string - simValue string - subspace string - }{ - {"slashing/SignedBlocksWindow", "SignedBlocksWindow", "\"231\"", "slashing"}, - {"slashing/MinSignedPerWindow", "MinSignedPerWindow", "\"0.700000000000000000\"", "slashing"}, - {"slashing/SlashFractionDowntime", "SlashFractionDowntime", "\"0.020833333333333333\"", "slashing"}, - } - - paramChanges := simulation.ParamChanges(r) - - require.Len(t, paramChanges, 3) - - for i, p := range paramChanges { - require.Equal(t, expected[i].composedKey, p.ComposedKey()) - require.Equal(t, expected[i].key, p.Key()) - require.Equal(t, expected[i].simValue, p.SimValue()(r)) - require.Equal(t, expected[i].subspace, p.Subspace()) - } -} diff --git a/x/slashing/simulation/proposals.go b/x/slashing/simulation/proposals.go new file mode 100644 index 000000000000..6c17b9c44a0a --- /dev/null +++ b/x/slashing/simulation/proposals.go @@ -0,0 +1,48 @@ +package simulation + +import ( + "math/rand" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/simulation" + "github.com/cosmos/cosmos-sdk/x/slashing/types" +) + +// Simulation operation weights constants +const ( + DefaultWeightMsgUpdateParams int = 100 + + OpWeightMsgUpdateParams = "op_weight_msg_update_params" //nolint:gosec +) + +// ProposalMsgs defines the module weighted proposals' contents +func ProposalMsgs() []simtypes.WeightedProposalMsg { + return []simtypes.WeightedProposalMsg{ + simulation.NewWeightedProposalMsg( + OpWeightMsgUpdateParams, + DefaultWeightMsgUpdateParams, + SimulateMsgUpdateParams, + ), + } +} + +// SimulateMsgUpdateParams returns a random MsgUpdateParams +func SimulateMsgUpdateParams(r *rand.Rand, _ sdk.Context, _ []simtypes.Account) sdk.Msg { + // use the default gov module account address as authority + var authority sdk.AccAddress = address.Module("gov") + + params := types.DefaultParams() + params.DowntimeJailDuration = time.Duration(simtypes.RandTimestamp(r).UnixNano()) + params.SignedBlocksWindow = int64(simtypes.RandIntBetween(r, 1, 1000)) + params.MinSignedPerWindow = sdk.NewDecWithPrec(int64(simtypes.RandIntBetween(r, 1, 100)), 2) + params.SlashFractionDoubleSign = sdk.NewDecWithPrec(int64(simtypes.RandIntBetween(r, 1, 100)), 2) + params.SlashFractionDowntime = sdk.NewDecWithPrec(int64(simtypes.RandIntBetween(r, 1, 100)), 2) + + return &types.MsgUpdateParams{ + Authority: authority.String(), + Params: params, + } +} diff --git a/x/slashing/simulation/proposals_test.go b/x/slashing/simulation/proposals_test.go new file mode 100644 index 000000000000..4a8edf75e9cf --- /dev/null +++ b/x/slashing/simulation/proposals_test.go @@ -0,0 +1,46 @@ +package simulation_test + +import ( + "math/rand" + "testing" + "time" + + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + "gotest.tools/v3/assert" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/slashing/simulation" + "github.com/cosmos/cosmos-sdk/x/slashing/types" +) + +func TestProposalMsgs(t *testing.T) { + // initialize parameters + s := rand.NewSource(1) + r := rand.New(s) + + ctx := sdk.NewContext(nil, tmproto.Header{}, true, nil) + accounts := simtypes.RandomAccounts(r, 3) + + // execute ProposalMsgs function + weightedProposalMsgs := simulation.ProposalMsgs() + assert.Assert(t, len(weightedProposalMsgs) == 1) + + w0 := weightedProposalMsgs[0] + + // tests w0 interface: + assert.Equal(t, simulation.OpWeightMsgUpdateParams, w0.AppParamsKey()) + assert.Equal(t, simulation.DefaultWeightMsgUpdateParams, w0.DefaultWeight()) + + msg := w0.MsgSimulatorFn()(r, ctx, accounts) + msgUpdateParams, ok := msg.(*types.MsgUpdateParams) + assert.Assert(t, ok) + + assert.Equal(t, sdk.AccAddress(address.Module("gov")).String(), msgUpdateParams.Authority) + assert.Equal(t, int64(905), msgUpdateParams.Params.SignedBlocksWindow) + assert.DeepEqual(t, sdk.NewDecWithPrec(7, 2), msgUpdateParams.Params.MinSignedPerWindow) + assert.DeepEqual(t, sdk.NewDecWithPrec(60, 2), msgUpdateParams.Params.SlashFractionDoubleSign) + assert.DeepEqual(t, sdk.NewDecWithPrec(89, 2), msgUpdateParams.Params.SlashFractionDowntime) + assert.Equal(t, 3313479009*time.Second, msgUpdateParams.Params.DowntimeJailDuration) +} diff --git a/x/staking/module.go b/x/staking/module.go index 3cbadacaa20e..e79f7a43778c 100644 --- a/x/staking/module.go +++ b/x/staking/module.go @@ -289,9 +289,9 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) { simulation.RandomizedGenState(simState) } -// ProposalContents doesn't return any content functions for governance proposals. -func (AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent { - return nil +// ProposalMsgs returns msgs used for governance proposals for simulations. +func (AppModule) ProposalMsgs(simState module.SimulationState) []simtypes.WeightedProposalMsg { + return simulation.ProposalMsgs() } // RegisterStoreDecoder registers a decoder for staking module's types diff --git a/x/staking/simulation/params.go b/x/staking/simulation/params.go deleted file mode 100644 index e969c7bd22ee..000000000000 --- a/x/staking/simulation/params.go +++ /dev/null @@ -1,32 +0,0 @@ -package simulation - -import ( - "fmt" - "math/rand" - - simtypes "github.com/cosmos/cosmos-sdk/types/simulation" - "github.com/cosmos/cosmos-sdk/x/simulation" - "github.com/cosmos/cosmos-sdk/x/staking/types" -) - -// ParamChanges defines the parameters that can be modified by param change proposals -// on the simulation -func ParamChanges(r *rand.Rand) []simtypes.ParamChange { - return []simtypes.ParamChange{ - simulation.NewSimParamChange(types.ModuleName, string(types.KeyMaxValidators), - func(r *rand.Rand) string { - return fmt.Sprintf("%d", genMaxValidators(r)) - }, - ), - simulation.NewSimParamChange(types.ModuleName, string(types.KeyUnbondingTime), - func(r *rand.Rand) string { - return fmt.Sprintf("\"%d\"", genUnbondingTime(r)) - }, - ), - simulation.NewSimParamChange(types.ModuleName, string(types.KeyHistoricalEntries), - func(r *rand.Rand) string { - return fmt.Sprintf("%d", getHistEntries(r)) - }, - ), - } -} diff --git a/x/staking/simulation/params_test.go b/x/staking/simulation/params_test.go deleted file mode 100644 index 07da026645cf..000000000000 --- a/x/staking/simulation/params_test.go +++ /dev/null @@ -1,37 +0,0 @@ -package simulation_test - -import ( - "math/rand" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/x/staking/simulation" -) - -func TestParamChanges(t *testing.T) { - s := rand.NewSource(1) - r := rand.New(s) - - expected := []struct { - composedKey string - key string - simValue string - subspace string - }{ - {"staking/MaxValidators", "MaxValidators", "82", "staking"}, - {"staking/UnbondingTime", "UnbondingTime", "\"275307000000000\"", "staking"}, - {"staking/HistoricalEntries", "HistoricalEntries", "9149", "staking"}, - } - - paramChanges := simulation.ParamChanges(r) - - require.Len(t, paramChanges, 3) - - for i, p := range paramChanges { - require.Equal(t, expected[i].composedKey, p.ComposedKey()) - require.Equal(t, expected[i].key, p.Key()) - require.Equal(t, expected[i].simValue, p.SimValue()(r)) - require.Equal(t, expected[i].subspace, p.Subspace()) - } -} diff --git a/x/staking/simulation/proposals.go b/x/staking/simulation/proposals.go new file mode 100644 index 000000000000..6b1f43128247 --- /dev/null +++ b/x/staking/simulation/proposals.go @@ -0,0 +1,49 @@ +package simulation + +import ( + "math/rand" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/simulation" + "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +// Simulation operation weights constants +const ( + DefaultWeightMsgUpdateParams int = 100 + + OpWeightMsgUpdateParams = "op_weight_msg_update_params" //nolint:gosec +) + +// ProposalMsgs defines the module weighted proposals' contents +func ProposalMsgs() []simtypes.WeightedProposalMsg { + return []simtypes.WeightedProposalMsg{ + simulation.NewWeightedProposalMsg( + OpWeightMsgUpdateParams, + DefaultWeightMsgUpdateParams, + SimulateMsgUpdateParams, + ), + } +} + +// SimulateMsgUpdateParams returns a random MsgUpdateParams +func SimulateMsgUpdateParams(r *rand.Rand, _ sdk.Context, _ []simtypes.Account) sdk.Msg { + // use the default gov module account address as authority + var authority sdk.AccAddress = address.Module("gov") + + params := types.DefaultParams() + params.BondDenom = simtypes.RandStringOfLength(r, 10) + params.HistoricalEntries = uint32(simtypes.RandIntBetween(r, 0, 1000)) + params.MaxEntries = uint32(simtypes.RandIntBetween(r, 1, 1000)) + params.MaxValidators = uint32(simtypes.RandIntBetween(r, 1, 1000)) + params.UnbondingTime = time.Duration(simtypes.RandTimestamp(r).UnixNano()) + params.MinCommissionRate = simtypes.RandomDecAmount(r, sdk.NewDec(1)) + + return &types.MsgUpdateParams{ + Authority: authority.String(), + Params: params, + } +} diff --git a/x/staking/simulation/proposals_test.go b/x/staking/simulation/proposals_test.go new file mode 100644 index 000000000000..4f3f79f67a54 --- /dev/null +++ b/x/staking/simulation/proposals_test.go @@ -0,0 +1,47 @@ +package simulation_test + +import ( + "math/rand" + "testing" + "time" + + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + "gotest.tools/v3/assert" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/address" + simtypes "github.com/cosmos/cosmos-sdk/types/simulation" + "github.com/cosmos/cosmos-sdk/x/staking/simulation" + "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +func TestProposalMsgs(t *testing.T) { + // initialize parameters + s := rand.NewSource(1) + r := rand.New(s) + + ctx := sdk.NewContext(nil, tmproto.Header{}, true, nil) + accounts := simtypes.RandomAccounts(r, 3) + + // execute ProposalMsgs function + weightedProposalMsgs := simulation.ProposalMsgs() + assert.Assert(t, len(weightedProposalMsgs) == 1) + + w0 := weightedProposalMsgs[0] + + // tests w0 interface: + assert.Equal(t, simulation.OpWeightMsgUpdateParams, w0.AppParamsKey()) + assert.Equal(t, simulation.DefaultWeightMsgUpdateParams, w0.DefaultWeight()) + + msg := w0.MsgSimulatorFn()(r, ctx, accounts) + msgUpdateParams, ok := msg.(*types.MsgUpdateParams) + assert.Assert(t, ok) + + assert.Equal(t, sdk.AccAddress(address.Module("gov")).String(), msgUpdateParams.Authority) + assert.Equal(t, "GqiQWIXnku", msgUpdateParams.Params.BondDenom) + assert.Equal(t, uint32(213), msgUpdateParams.Params.MaxEntries) + assert.Equal(t, uint32(300), msgUpdateParams.Params.HistoricalEntries) + assert.Equal(t, uint32(539), msgUpdateParams.Params.MaxValidators) + assert.Equal(t, 8898194435*time.Second, msgUpdateParams.Params.UnbondingTime) + assert.DeepEqual(t, sdk.NewDecWithPrec(579040435581502128, 18), msgUpdateParams.Params.MinCommissionRate) +} diff --git a/x/staking/types/params.go b/x/staking/types/params.go index cbcacf67b413..9211cf9f5206 100644 --- a/x/staking/types/params.go +++ b/x/staking/types/params.go @@ -100,6 +100,10 @@ func (p Params) Validate() error { return err } + if err := validateHistoricalEntries(p.HistoricalEntries); err != nil { + return err + } + return nil }