diff --git a/.pending/improvements/sdk/4403-parameter-chang b/.pending/improvements/sdk/4403-parameter-chang new file mode 100644 index 000000000000..6cbcb03fc177 --- /dev/null +++ b/.pending/improvements/sdk/4403-parameter-chang @@ -0,0 +1,2 @@ +#4403 Allow for parameter change proposals to supply only desired fields to be updated +in objects instead of the entire object (only applies to values that are objects). \ No newline at end of file diff --git a/x/gov/keeper.go b/x/gov/keeper.go index 04da774923b8..79786cc0ba00 100644 --- a/x/gov/keeper.go +++ b/x/gov/keeper.go @@ -11,26 +11,12 @@ import ( "github.com/tendermint/tendermint/libs/log" ) -// Parameter store key var ( - ParamStoreKeyDepositParams = []byte("depositparams") - ParamStoreKeyVotingParams = []byte("votingparams") - ParamStoreKeyTallyParams = []byte("tallyparams") - // TODO: Find another way to implement this without using accounts, or find a cleaner way to implement it using accounts. DepositedCoinsAccAddr = sdk.AccAddress(crypto.AddressHash([]byte("govDepositedCoins"))) BurnedDepositCoinsAccAddr = sdk.AccAddress(crypto.AddressHash([]byte("govBurnedDepositCoins"))) ) -// Key declaration for parameters -func ParamKeyTable() params.KeyTable { - return params.NewKeyTable( - ParamStoreKeyDepositParams, DepositParams{}, - ParamStoreKeyVotingParams, VotingParams{}, - ParamStoreKeyTallyParams, TallyParams{}, - ) -} - // Governance Keeper type Keeper struct { // The reference to the Param Keeper to get and set Global Params diff --git a/x/gov/params.go b/x/gov/params.go index c15d35614f3e..d12658967a6f 100644 --- a/x/gov/params.go +++ b/x/gov/params.go @@ -5,12 +5,29 @@ import ( "time" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/params" ) +// Parameter store key +var ( + ParamStoreKeyDepositParams = []byte("depositparams") + ParamStoreKeyVotingParams = []byte("votingparams") + ParamStoreKeyTallyParams = []byte("tallyparams") +) + +// Key declaration for parameters +func ParamKeyTable() params.KeyTable { + return params.NewKeyTable( + ParamStoreKeyDepositParams, DepositParams{}, + ParamStoreKeyVotingParams, VotingParams{}, + ParamStoreKeyTallyParams, TallyParams{}, + ) +} + // Param around deposits for governance type DepositParams struct { - MinDeposit sdk.Coins `json:"min_deposit"` // Minimum deposit for a proposal to enter voting period. - MaxDepositPeriod time.Duration `json:"max_deposit_period"` // Maximum period for Atom holders to deposit on a proposal. Initial value: 2 months + MinDeposit sdk.Coins `json:"min_deposit,omitempty"` // Minimum deposit for a proposal to enter voting period. + MaxDepositPeriod time.Duration `json:"max_deposit_period,omitempty"` // Maximum period for Atom holders to deposit on a proposal. Initial value: 2 months } // NewDepositParams creates a new DepositParams object @@ -34,9 +51,9 @@ func (dp DepositParams) Equal(dp2 DepositParams) bool { // Param around Tallying votes in governance type TallyParams struct { - Quorum sdk.Dec `json:"quorum"` // Minimum percentage of total stake needed to vote for a result to be considered valid - Threshold sdk.Dec `json:"threshold"` // Minimum proportion of Yes votes for proposal to pass. Initial value: 0.5 - Veto sdk.Dec `json:"veto"` // Minimum value of Veto votes to Total votes ratio for proposal to be vetoed. Initial value: 1/3 + Quorum sdk.Dec `json:"quorum,omitempty"` // Minimum percentage of total stake needed to vote for a result to be considered valid + Threshold sdk.Dec `json:"threshold,omitempty"` // Minimum proportion of Yes votes for proposal to pass. Initial value: 0.5 + Veto sdk.Dec `json:"veto,omitempty"` // Minimum value of Veto votes to Total votes ratio for proposal to be vetoed. Initial value: 1/3 } // NewTallyParams creates a new TallyParams object @@ -58,7 +75,7 @@ func (tp TallyParams) String() string { // Param around Voting in governance type VotingParams struct { - VotingPeriod time.Duration `json:"voting_period"` // Length of the voting period. + VotingPeriod time.Duration `json:"voting_period,omitempty"` // Length of the voting period. } // NewVotingParams creates a new VotingParams object diff --git a/x/gov/test_common.go b/x/gov/test_common.go index 2953fd98d4f6..b9d857c0d67f 100644 --- a/x/gov/test_common.go +++ b/x/gov/test_common.go @@ -40,9 +40,11 @@ func getMockApp(t *testing.T, numGenAccs int, genState GenesisState, genAccs []a tKeyStaking := sdk.NewTransientStoreKey(staking.TStoreKey) keyGov := sdk.NewKVStoreKey(StoreKey) - rtr := NewRouter().AddRoute(RouterKey, ProposalHandler) - pk := mApp.ParamsKeeper + + rtr := NewRouter(). + AddRoute(RouterKey, ProposalHandler) + ck := bank.NewBaseKeeper(mApp.AccountKeeper, mApp.ParamsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace) sk := staking.NewKeeper(mApp.Cdc, keyStaking, tKeyStaking, ck, pk.Subspace(staking.DefaultParamspace), staking.DefaultCodespace) keeper := NewKeeper(mApp.Cdc, keyGov, pk, pk.Subspace("testgov"), ck, sk, DefaultCodespace, rtr) diff --git a/x/params/alias.go b/x/params/alias.go index 0244c93837a3..be51ad53d0f3 100644 --- a/x/params/alias.go +++ b/x/params/alias.go @@ -37,6 +37,7 @@ var ( ErrEmptyValue = types.ErrEmptyValue NewParameterChangeProposal = types.NewParameterChangeProposal NewParamChange = types.NewParamChange + NewParamChangeWithSubkey = types.NewParamChangeWithSubkey ValidateChanges = types.ValidateChanges ) diff --git a/x/params/client/cli/tx.go b/x/params/client/cli/tx.go index a4fc82ad623e..71c1d797388b 100644 --- a/x/params/client/cli/tx.go +++ b/x/params/client/cli/tx.go @@ -26,7 +26,8 @@ func GetCmdSubmitProposal(cdc *codec.Codec) *cobra.Command { Short: "Submit a parameter change proposal", Long: strings.TrimSpace( fmt.Sprintf(`Submit a parameter proposal along with an initial deposit. -The proposal details must be supplied via a JSON file. +The proposal details must be supplied via a JSON file. For values that contains +objects, only non-empty fields will be updated. IMPORTANT: Currently parameter changes are evaluated but not validated, so it is very important that any "value" change is valid (ie. correct type and within bounds) @@ -34,7 +35,7 @@ for its respective parameter, eg. "MaxValidators" should be an integer and not a Proper vetting of a parameter change proposal should prevent this from happening (no deposits should occur during the governance process), but it should be noted -regardless. +regardless. Example: $ %s tx gov submit-proposal param-change --from= diff --git a/x/params/client/utils/utils.go b/x/params/client/utils/utils.go index e390b3d326bc..245d5c06b618 100644 --- a/x/params/client/utils/utils.go +++ b/x/params/client/utils/utils.go @@ -51,7 +51,7 @@ func NewParamChangeJSON(subspace, key, subkey string, value json.RawMessage) Par // ToParamChange converts a ParamChangeJSON object to ParamChange. func (pcj ParamChangeJSON) ToParamChange() params.ParamChange { - return params.NewParamChange(pcj.Subspace, pcj.Key, pcj.Subkey, string(pcj.Value)) + return params.NewParamChangeWithSubkey(pcj.Subspace, pcj.Key, pcj.Subkey, string(pcj.Value)) } // ToParamChanges converts a slice of ParamChangeJSON objects to a slice of diff --git a/x/params/keeper_test.go b/x/params/keeper_test.go index 8504e168d4af..27c4e94a0850 100644 --- a/x/params/keeper_test.go +++ b/x/params/keeper_test.go @@ -6,40 +6,10 @@ import ( "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - dbm "github.com/tendermint/tendermint/libs/db" - "github.com/tendermint/tendermint/libs/log" - - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/store" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" ) -func defaultContext(key sdk.StoreKey, tkey sdk.StoreKey) sdk.Context { - db := dbm.NewMemDB() - cms := store.NewCommitMultiStore(db) - cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) - cms.MountStoreWithDB(tkey, sdk.StoreTypeTransient, db) - cms.LoadLatestVersion() - ctx := sdk.NewContext(cms, abci.Header{}, false, log.NewNopLogger()) - return ctx -} - -type invalid struct{} - -type s struct { - I int -} - -func createTestCodec() *codec.Codec { - cdc := codec.New() - sdk.RegisterCodec(cdc) - cdc.RegisterConcrete(s{}, "test/s", nil) - cdc.RegisterConcrete(invalid{}, "test/invalid", nil) - return cdc -} - func TestKeeper(t *testing.T) { kvs := []struct { key string @@ -66,11 +36,8 @@ func TestKeeper(t *testing.T) { []byte("extra2"), string(""), ) - cdc := codec.New() - skey := sdk.NewKVStoreKey("test") - tkey := sdk.NewTransientStoreKey("transient_test") - ctx := defaultContext(skey, tkey) - keeper := NewKeeper(cdc, skey, tkey, DefaultCodespace) + cdc, ctx, skey, _, keeper := testComponents() + store := prefix.NewStore(ctx.KVStore(skey), []byte("test/")) space := keeper.Subspace("test").WithKeyTable(table) @@ -137,11 +104,7 @@ func indirect(ptr interface{}) interface{} { } func TestSubspace(t *testing.T) { - cdc := createTestCodec() - key := sdk.NewKVStoreKey("test") - tkey := sdk.NewTransientStoreKey("transient_test") - ctx := defaultContext(key, tkey) - keeper := NewKeeper(cdc, key, tkey, DefaultCodespace) + cdc, ctx, key, _, keeper := testComponents() kvs := []struct { key string @@ -216,3 +179,34 @@ func TestSubspace(t *testing.T) { require.Equal(t, kv.param, indirect(kv.ptr), "stored param not equal, tc #%d", i) } } + +type paramJSON struct { + Param1 int64 `json:"param1,omitempty"` + Param2 string `json:"param2,omitempty"` +} + +func TestJSONUpdate(t *testing.T) { + _, ctx, _, _, keeper := testComponents() + + key := []byte("key") + + space := keeper.Subspace("test").WithKeyTable(NewKeyTable(key, paramJSON{})) + + var param paramJSON + + space.Update(ctx, key, []byte(`{"param1": "10241024"}`)) + space.Get(ctx, key, ¶m) + require.Equal(t, paramJSON{10241024, ""}, param) + + space.Update(ctx, key, []byte(`{"param2": "helloworld"}`)) + space.Get(ctx, key, ¶m) + require.Equal(t, paramJSON{10241024, "helloworld"}, param) + + space.Update(ctx, key, []byte(`{"param1": "20482048"}`)) + space.Get(ctx, key, ¶m) + require.Equal(t, paramJSON{20482048, "helloworld"}, param) + + space.Update(ctx, key, []byte(`{"param1": "40964096", "param2": "goodbyeworld"}`)) + space.Get(ctx, key, ¶m) + require.Equal(t, paramJSON{40964096, "goodbyeworld"}, param) +} diff --git a/x/params/proposal_handler.go b/x/params/proposal_handler.go index 1c4b847540d5..a40d8df838dd 100644 --- a/x/params/proposal_handler.go +++ b/x/params/proposal_handler.go @@ -32,12 +32,13 @@ func handleParameterChangeProposal(ctx sdk.Context, k Keeper, p ParameterChangeP k.Logger(ctx).Info( fmt.Sprintf("setting new parameter; key: %s, value: %s", c.Key, c.Value), ) - err = ss.SetRaw(ctx, []byte(c.Key), []byte(c.Value)) + + err = ss.Update(ctx, []byte(c.Key), []byte(c.Value)) } else { k.Logger(ctx).Info( fmt.Sprintf("setting new parameter; key: %s, subkey: %s, value: %s", c.Key, c.Subspace, c.Value), ) - err = ss.SetRawWithSubkey(ctx, []byte(c.Key), []byte(c.Subkey), []byte(c.Value)) + err = ss.UpdateWithSubkey(ctx, []byte(c.Key), []byte(c.Subkey), []byte(c.Value)) } if err != nil { diff --git a/x/params/proposal_handler_test.go b/x/params/proposal_handler_test.go index 532fddb1ba9a..b6cc5b34fade 100644 --- a/x/params/proposal_handler_test.go +++ b/x/params/proposal_handler_test.go @@ -27,16 +27,24 @@ var ( _ subspace.ParamSet = (*testParams)(nil) keyMaxValidators = "MaxValidators" + keySlashingRate = "SlashingRate" testSubspace = "TestSubspace" ) +type testParamsSlashingRate struct { + DoubleSign uint16 `json:"double_sign,omitempty"` + Downtime uint16 `json:"downtime,omitempty"` +} + type testParams struct { - MaxValidators uint16 `json:"max_validators"` // maximum number of validators (max uint16 = 65535) + MaxValidators uint16 `json:"max_validators"` // maximum number of validators (max uint16 = 65535) + SlashingRate testParamsSlashingRate `json:"slashing_rate"` } func (tp *testParams) ParamSetPairs() subspace.ParamSetPairs { return subspace.ParamSetPairs{ {[]byte(keyMaxValidators), &tp.MaxValidators}, + {[]byte(keySlashingRate), &tp.SlashingRate}, } } @@ -76,7 +84,7 @@ func TestProposalHandlerPassed(t *testing.T) { params.NewKeyTable().RegisterParamSet(&testParams{}), ) - tp := testProposal(params.NewParamChange(testSubspace, keyMaxValidators, "", "1")) + tp := testProposal(params.NewParamChange(testSubspace, keyMaxValidators, "1")) hdlr := params.NewParamChangeProposalHandler(input.keeper) require.NoError(t, hdlr(input.ctx, tp)) @@ -91,9 +99,31 @@ func TestProposalHandlerFailed(t *testing.T) { params.NewKeyTable().RegisterParamSet(&testParams{}), ) - tp := testProposal(params.NewParamChange(testSubspace, keyMaxValidators, "", "invalidType")) + tp := testProposal(params.NewParamChange(testSubspace, keyMaxValidators, "invalidType")) hdlr := params.NewParamChangeProposalHandler(input.keeper) require.Error(t, hdlr(input.ctx, tp)) require.False(t, ss.Has(input.ctx, []byte(keyMaxValidators))) } + +func TestProposalHandlerUpdateOmitempty(t *testing.T) { + input := newTestInput(t) + ss := input.keeper.Subspace(testSubspace).WithKeyTable( + params.NewKeyTable().RegisterParamSet(&testParams{}), + ) + + hdlr := params.NewParamChangeProposalHandler(input.keeper) + var param testParamsSlashingRate + + tp := testProposal(params.NewParamChange(testSubspace, keySlashingRate, `{"downtime": 7}`)) + require.NoError(t, hdlr(input.ctx, tp)) + + ss.Get(input.ctx, []byte(keySlashingRate), ¶m) + require.Equal(t, testParamsSlashingRate{0, 7}, param) + + tp = testProposal(params.NewParamChange(testSubspace, keySlashingRate, `{"double_sign": 10}`)) + require.NoError(t, hdlr(input.ctx, tp)) + + ss.Get(input.ctx, []byte(keySlashingRate), ¶m) + require.Equal(t, testParamsSlashingRate{10, 7}, param) +} diff --git a/x/params/simulation/msgs.go b/x/params/simulation/msgs.go index 3ac4b31531c4..c77e3db80fce 100644 --- a/x/params/simulation/msgs.go +++ b/x/params/simulation/msgs.go @@ -1,6 +1,7 @@ package simulation import ( + "encoding/json" "fmt" "math/rand" "time" @@ -26,8 +27,6 @@ func (spc simParamChange) compKey() string { // paramChangePool defines a static slice of possible simulated parameter changes // where each simParamChange corresponds to a ParamChange with a simValue // function to generate a simulated new value. -// -// TODO: governance parameters (blocked on an upgrade to go-amino) var paramChangePool = []simParamChange{ // staking parameters { @@ -80,6 +79,55 @@ var paramChangePool = []simParamChange{ return fmt.Sprintf("\"%s\"", simulation.ModuleParamSimulator["InflationRateChange"](r).(sdk.Dec)) }, }, + // gov parameters + { + "gov", + "votingparams", + "", + func(r *rand.Rand) string { + return fmt.Sprintf(`{"voting_period": "%d"}`, simulation.ModuleParamSimulator["VotingParams/VotingPeriod"](r).(time.Duration)) + }, + }, + { + "gov", + "depositparams", + "", + func(r *rand.Rand) string { + return fmt.Sprintf(`{"max_deposit_period": "%d"}`, simulation.ModuleParamSimulator["VotingParams/VotingPeriod"](r).(time.Duration)) + }, + }, + { + "gov", + "tallyparams", + "", + func(r *rand.Rand) string { + changes := []struct { + key string + value sdk.Dec + }{ + {"quorum", simulation.ModuleParamSimulator["TallyParams/Quorum"](r).(sdk.Dec)}, + {"threshold", simulation.ModuleParamSimulator["TallyParams/Threshold"](r).(sdk.Dec)}, + {"veto", simulation.ModuleParamSimulator["TallyParams/Veto"](r).(sdk.Dec)}, + } + + pc := make(map[string]string) + numChanges := simulation.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) + }, + }, // auth parameters { "auth", @@ -126,7 +174,7 @@ func SimulateParamChangeProposalContent(r *rand.Rand, _ *baseapp.BaseApp, _ sdk. } paramChangesKeys[spc.compKey()] = struct{}{} - paramChanges[i] = params.NewParamChange(spc.subspace, spc.key, spc.subkey, spc.simValue(r)) + paramChanges[i] = params.NewParamChangeWithSubkey(spc.subspace, spc.key, spc.subkey, spc.simValue(r)) } return params.NewParameterChangeProposal( diff --git a/x/params/subspace/subspace.go b/x/params/subspace/subspace.go index af3ebd0b2b0f..457c0133345d 100644 --- a/x/params/subspace/subspace.go +++ b/x/params/subspace/subspace.go @@ -177,10 +177,10 @@ func (s Subspace) Set(ctx sdk.Context, key []byte, param interface{}) { } -// SetRaw stores raw parameter bytes. It returns error if the stored parameter +// Update stores raw parameter bytes. It returns error if the stored parameter // has a different type from the input. It also sets to the transient store to // record change. -func (s Subspace) SetRaw(ctx sdk.Context, key []byte, param []byte) error { +func (s Subspace) Update(ctx sdk.Context, key []byte, param []byte) error { attr, ok := s.table.m[string(key)] if !ok { panic("Parameter not registered") @@ -188,13 +188,13 @@ func (s Subspace) SetRaw(ctx sdk.Context, key []byte, param []byte) error { ty := attr.ty dest := reflect.New(ty).Interface() + s.GetIfExists(ctx, key, dest) err := s.cdc.UnmarshalJSON(param, dest) if err != nil { return err } - store := s.kvStore(ctx) - store.Set(key, param) + s.Set(ctx, key, dest) tStore := s.transientStore(ctx) tStore.Set(key, []byte{}) @@ -220,9 +220,9 @@ func (s Subspace) SetWithSubkey(ctx sdk.Context, key []byte, subkey []byte, para tstore.Set(newkey, []byte{}) } -// SetRawWithSubkey stores raw parameter bytes with a key and subkey. It checks +// UpdateWithSubkey stores raw parameter bytes with a key and subkey. It checks // the parameter type only over the key. -func (s Subspace) SetRawWithSubkey(ctx sdk.Context, key []byte, subkey []byte, param []byte) error { +func (s Subspace) UpdateWithSubkey(ctx sdk.Context, key []byte, subkey []byte, param []byte) error { concatkey := concatKeys(key, subkey) attr, ok := s.table.m[string(concatkey)] @@ -232,13 +232,13 @@ func (s Subspace) SetRawWithSubkey(ctx sdk.Context, key []byte, subkey []byte, p ty := attr.ty dest := reflect.New(ty).Interface() - err := s.cdc.UnmarshalJSON(param, &dest) + s.GetWithSubkeyIfExists(ctx, key, subkey, dest) + err := s.cdc.UnmarshalJSON(param, dest) if err != nil { return err } - store := s.kvStore(ctx) - store.Set(concatkey, param) + s.SetWithSubkey(ctx, key, subkey, dest) tStore := s.transientStore(ctx) tStore.Set(concatkey, []byte{}) diff --git a/x/params/test_common.go b/x/params/test_common.go new file mode 100644 index 000000000000..3cbd5db83727 --- /dev/null +++ b/x/params/test_common.go @@ -0,0 +1,48 @@ +package params + +import ( + abci "github.com/tendermint/tendermint/abci/types" + dbm "github.com/tendermint/tendermint/libs/db" + "github.com/tendermint/tendermint/libs/log" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/store" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +type invalid struct{} + +type s struct { + I int +} + +func createTestCodec() *codec.Codec { + cdc := codec.New() + sdk.RegisterCodec(cdc) + cdc.RegisterConcrete(s{}, "test/s", nil) + cdc.RegisterConcrete(invalid{}, "test/invalid", nil) + return cdc +} + +func defaultContext(key sdk.StoreKey, tkey sdk.StoreKey) sdk.Context { + db := dbm.NewMemDB() + cms := store.NewCommitMultiStore(db) + cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db) + cms.MountStoreWithDB(tkey, sdk.StoreTypeTransient, db) + err := cms.LoadLatestVersion() + if err != nil { + panic(err) + } + ctx := sdk.NewContext(cms, abci.Header{}, false, log.NewNopLogger()) + return ctx +} + +func testComponents() (*codec.Codec, sdk.Context, sdk.StoreKey, sdk.StoreKey, Keeper) { + cdc := createTestCodec() + mkey := sdk.NewKVStoreKey("test") + tkey := sdk.NewTransientStoreKey("transient_test") + ctx := defaultContext(mkey, tkey) + keeper := NewKeeper(cdc, mkey, tkey, DefaultCodespace) + + return cdc, ctx, mkey, tkey, keeper +} diff --git a/x/params/types/proposal.go b/x/params/types/proposal.go index c9f69c2cfea0..9c4ff7eebc83 100644 --- a/x/params/types/proposal.go +++ b/x/params/types/proposal.go @@ -85,7 +85,11 @@ type ParamChange struct { Value string `json:"value"` } -func NewParamChange(subspace, key, subkey, value string) ParamChange { +func NewParamChange(subspace, key, value string) ParamChange { + return ParamChange{subspace, key, "", value} +} + +func NewParamChangeWithSubkey(subspace, key, subkey, value string) ParamChange { return ParamChange{subspace, key, subkey, value} } diff --git a/x/params/types/proposal_test.go b/x/params/types/proposal_test.go index 14206c731fc3..e4865aad7ad8 100644 --- a/x/params/types/proposal_test.go +++ b/x/params/types/proposal_test.go @@ -7,8 +7,8 @@ import ( ) func TestParameterChangeProposal(t *testing.T) { - pc1 := NewParamChange("sub", "foo", "", "baz") - pc2 := NewParamChange("sub", "bar", "cat", "dog") + pc1 := NewParamChange("sub", "foo", "baz") + pc2 := NewParamChangeWithSubkey("sub", "bar", "cat", "dog") pcp := NewParameterChangeProposal("test title", "test description", []ParamChange{pc1, pc2}) require.Equal(t, "test title", pcp.GetTitle()) @@ -17,15 +17,15 @@ func TestParameterChangeProposal(t *testing.T) { require.Equal(t, ProposalTypeChange, pcp.ProposalType()) require.Nil(t, pcp.ValidateBasic()) - pc3 := NewParamChange("", "bar", "cat", "dog") + pc3 := NewParamChangeWithSubkey("", "bar", "cat", "dog") pcp = NewParameterChangeProposal("test title", "test description", []ParamChange{pc3}) require.Error(t, pcp.ValidateBasic()) - pc4 := NewParamChange("sub", "", "cat", "dog") + pc4 := NewParamChangeWithSubkey("sub", "", "cat", "dog") pcp = NewParameterChangeProposal("test title", "test description", []ParamChange{pc4}) require.Error(t, pcp.ValidateBasic()) - pc5 := NewParamChange("sub", "foo", "cat", "") + pc5 := NewParamChangeWithSubkey("sub", "foo", "cat", "") pcp = NewParameterChangeProposal("test title", "test description", []ParamChange{pc5}) require.Error(t, pcp.ValidateBasic()) } diff --git a/x/simulation/params.go b/x/simulation/params.go index 47b039af5c68..a4667ab9cd46 100644 --- a/x/simulation/params.go +++ b/x/simulation/params.go @@ -62,13 +62,13 @@ var ( return time.Duration(RandIntBetween(r, 1, 2*60*60*24*2)) * time.Second }, "TallyParams/Quorum": func(r *rand.Rand) interface{} { - return sdk.NewDecWithPrec(334, 3) + return sdk.NewDecWithPrec(int64(RandIntBetween(r, 334, 500)), 3) }, "TallyParams/Threshold": func(r *rand.Rand) interface{} { - return sdk.NewDecWithPrec(5, 1) + return sdk.NewDecWithPrec(int64(RandIntBetween(r, 450, 550)), 3) }, "TallyParams/Veto": func(r *rand.Rand) interface{} { - return sdk.NewDecWithPrec(334, 3) + return sdk.NewDecWithPrec(int64(RandIntBetween(r, 250, 334)), 3) }, "UnbondingTime": func(r *rand.Rand) interface{} { return time.Duration(RandIntBetween(r, 60, 60*60*24*3*2)) * time.Second