Skip to content

Commit 91e75cb

Browse files
mossidalexanderbez
authored andcommitted
Merge PR #4403: Paramchange proposal skips omitempty fields
1 parent 8fecc77 commit 91e75cb

File tree

16 files changed

+225
-91
lines changed

16 files changed

+225
-91
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#4403 Allow for parameter change proposals to supply only desired fields to be updated
2+
in objects instead of the entire object (only applies to values that are objects).

x/gov/keeper.go

-14
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,12 @@ import (
1111
"github.com/tendermint/tendermint/libs/log"
1212
)
1313

14-
// Parameter store key
1514
var (
16-
ParamStoreKeyDepositParams = []byte("depositparams")
17-
ParamStoreKeyVotingParams = []byte("votingparams")
18-
ParamStoreKeyTallyParams = []byte("tallyparams")
19-
2015
// TODO: Find another way to implement this without using accounts, or find a cleaner way to implement it using accounts.
2116
DepositedCoinsAccAddr = sdk.AccAddress(crypto.AddressHash([]byte("govDepositedCoins")))
2217
BurnedDepositCoinsAccAddr = sdk.AccAddress(crypto.AddressHash([]byte("govBurnedDepositCoins")))
2318
)
2419

25-
// Key declaration for parameters
26-
func ParamKeyTable() params.KeyTable {
27-
return params.NewKeyTable(
28-
ParamStoreKeyDepositParams, DepositParams{},
29-
ParamStoreKeyVotingParams, VotingParams{},
30-
ParamStoreKeyTallyParams, TallyParams{},
31-
)
32-
}
33-
3420
// Governance Keeper
3521
type Keeper struct {
3622
// The reference to the Param Keeper to get and set Global Params

x/gov/params.go

+23-6
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,29 @@ import (
55
"time"
66

77
sdk "github.com/cosmos/cosmos-sdk/types"
8+
"github.com/cosmos/cosmos-sdk/x/params"
89
)
910

11+
// Parameter store key
12+
var (
13+
ParamStoreKeyDepositParams = []byte("depositparams")
14+
ParamStoreKeyVotingParams = []byte("votingparams")
15+
ParamStoreKeyTallyParams = []byte("tallyparams")
16+
)
17+
18+
// Key declaration for parameters
19+
func ParamKeyTable() params.KeyTable {
20+
return params.NewKeyTable(
21+
ParamStoreKeyDepositParams, DepositParams{},
22+
ParamStoreKeyVotingParams, VotingParams{},
23+
ParamStoreKeyTallyParams, TallyParams{},
24+
)
25+
}
26+
1027
// Param around deposits for governance
1128
type DepositParams struct {
12-
MinDeposit sdk.Coins `json:"min_deposit"` // Minimum deposit for a proposal to enter voting period.
13-
MaxDepositPeriod time.Duration `json:"max_deposit_period"` // Maximum period for Atom holders to deposit on a proposal. Initial value: 2 months
29+
MinDeposit sdk.Coins `json:"min_deposit,omitempty"` // Minimum deposit for a proposal to enter voting period.
30+
MaxDepositPeriod time.Duration `json:"max_deposit_period,omitempty"` // Maximum period for Atom holders to deposit on a proposal. Initial value: 2 months
1431
}
1532

1633
// NewDepositParams creates a new DepositParams object
@@ -34,9 +51,9 @@ func (dp DepositParams) Equal(dp2 DepositParams) bool {
3451

3552
// Param around Tallying votes in governance
3653
type TallyParams struct {
37-
Quorum sdk.Dec `json:"quorum"` // Minimum percentage of total stake needed to vote for a result to be considered valid
38-
Threshold sdk.Dec `json:"threshold"` // Minimum proportion of Yes votes for proposal to pass. Initial value: 0.5
39-
Veto sdk.Dec `json:"veto"` // Minimum value of Veto votes to Total votes ratio for proposal to be vetoed. Initial value: 1/3
54+
Quorum sdk.Dec `json:"quorum,omitempty"` // Minimum percentage of total stake needed to vote for a result to be considered valid
55+
Threshold sdk.Dec `json:"threshold,omitempty"` // Minimum proportion of Yes votes for proposal to pass. Initial value: 0.5
56+
Veto sdk.Dec `json:"veto,omitempty"` // Minimum value of Veto votes to Total votes ratio for proposal to be vetoed. Initial value: 1/3
4057
}
4158

4259
// NewTallyParams creates a new TallyParams object
@@ -58,7 +75,7 @@ func (tp TallyParams) String() string {
5875

5976
// Param around Voting in governance
6077
type VotingParams struct {
61-
VotingPeriod time.Duration `json:"voting_period"` // Length of the voting period.
78+
VotingPeriod time.Duration `json:"voting_period,omitempty"` // Length of the voting period.
6279
}
6380

6481
// NewVotingParams creates a new VotingParams object

x/gov/test_common.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,11 @@ func getMockApp(t *testing.T, numGenAccs int, genState GenesisState, genAccs []a
4040
tKeyStaking := sdk.NewTransientStoreKey(staking.TStoreKey)
4141
keyGov := sdk.NewKVStoreKey(StoreKey)
4242

43-
rtr := NewRouter().AddRoute(RouterKey, ProposalHandler)
44-
4543
pk := mApp.ParamsKeeper
44+
45+
rtr := NewRouter().
46+
AddRoute(RouterKey, ProposalHandler)
47+
4648
ck := bank.NewBaseKeeper(mApp.AccountKeeper, mApp.ParamsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace)
4749
sk := staking.NewKeeper(mApp.Cdc, keyStaking, tKeyStaking, ck, pk.Subspace(staking.DefaultParamspace), staking.DefaultCodespace)
4850
keeper := NewKeeper(mApp.Cdc, keyGov, pk, pk.Subspace("testgov"), ck, sk, DefaultCodespace, rtr)

x/params/alias.go

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ var (
3737
ErrEmptyValue = types.ErrEmptyValue
3838
NewParameterChangeProposal = types.NewParameterChangeProposal
3939
NewParamChange = types.NewParamChange
40+
NewParamChangeWithSubkey = types.NewParamChangeWithSubkey
4041
ValidateChanges = types.ValidateChanges
4142
)
4243

x/params/client/cli/tx.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,16 @@ func GetCmdSubmitProposal(cdc *codec.Codec) *cobra.Command {
2626
Short: "Submit a parameter change proposal",
2727
Long: strings.TrimSpace(
2828
fmt.Sprintf(`Submit a parameter proposal along with an initial deposit.
29-
The proposal details must be supplied via a JSON file.
29+
The proposal details must be supplied via a JSON file. For values that contains
30+
objects, only non-empty fields will be updated.
3031
3132
IMPORTANT: Currently parameter changes are evaluated but not validated, so it is
3233
very important that any "value" change is valid (ie. correct type and within bounds)
3334
for its respective parameter, eg. "MaxValidators" should be an integer and not a decimal.
3435
3536
Proper vetting of a parameter change proposal should prevent this from happening
3637
(no deposits should occur during the governance process), but it should be noted
37-
regardless.
38+
regardless.
3839
3940
Example:
4041
$ %s tx gov submit-proposal param-change <path/to/proposal.json> --from=<key_or_address>

x/params/client/utils/utils.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func NewParamChangeJSON(subspace, key, subkey string, value json.RawMessage) Par
5151

5252
// ToParamChange converts a ParamChangeJSON object to ParamChange.
5353
func (pcj ParamChangeJSON) ToParamChange() params.ParamChange {
54-
return params.NewParamChange(pcj.Subspace, pcj.Key, pcj.Subkey, string(pcj.Value))
54+
return params.NewParamChangeWithSubkey(pcj.Subspace, pcj.Key, pcj.Subkey, string(pcj.Value))
5555
}
5656

5757
// ToParamChanges converts a slice of ParamChangeJSON objects to a slice of

x/params/keeper_test.go

+34-40
Original file line numberDiff line numberDiff line change
@@ -6,40 +6,10 @@ import (
66

77
"github.com/stretchr/testify/require"
88

9-
abci "github.com/tendermint/tendermint/abci/types"
10-
dbm "github.com/tendermint/tendermint/libs/db"
11-
"github.com/tendermint/tendermint/libs/log"
12-
13-
"github.com/cosmos/cosmos-sdk/codec"
14-
"github.com/cosmos/cosmos-sdk/store"
159
"github.com/cosmos/cosmos-sdk/store/prefix"
1610
sdk "github.com/cosmos/cosmos-sdk/types"
1711
)
1812

19-
func defaultContext(key sdk.StoreKey, tkey sdk.StoreKey) sdk.Context {
20-
db := dbm.NewMemDB()
21-
cms := store.NewCommitMultiStore(db)
22-
cms.MountStoreWithDB(key, sdk.StoreTypeIAVL, db)
23-
cms.MountStoreWithDB(tkey, sdk.StoreTypeTransient, db)
24-
cms.LoadLatestVersion()
25-
ctx := sdk.NewContext(cms, abci.Header{}, false, log.NewNopLogger())
26-
return ctx
27-
}
28-
29-
type invalid struct{}
30-
31-
type s struct {
32-
I int
33-
}
34-
35-
func createTestCodec() *codec.Codec {
36-
cdc := codec.New()
37-
sdk.RegisterCodec(cdc)
38-
cdc.RegisterConcrete(s{}, "test/s", nil)
39-
cdc.RegisterConcrete(invalid{}, "test/invalid", nil)
40-
return cdc
41-
}
42-
4313
func TestKeeper(t *testing.T) {
4414
kvs := []struct {
4515
key string
@@ -66,11 +36,8 @@ func TestKeeper(t *testing.T) {
6636
[]byte("extra2"), string(""),
6737
)
6838

69-
cdc := codec.New()
70-
skey := sdk.NewKVStoreKey("test")
71-
tkey := sdk.NewTransientStoreKey("transient_test")
72-
ctx := defaultContext(skey, tkey)
73-
keeper := NewKeeper(cdc, skey, tkey, DefaultCodespace)
39+
cdc, ctx, skey, _, keeper := testComponents()
40+
7441
store := prefix.NewStore(ctx.KVStore(skey), []byte("test/"))
7542
space := keeper.Subspace("test").WithKeyTable(table)
7643

@@ -137,11 +104,7 @@ func indirect(ptr interface{}) interface{} {
137104
}
138105

139106
func TestSubspace(t *testing.T) {
140-
cdc := createTestCodec()
141-
key := sdk.NewKVStoreKey("test")
142-
tkey := sdk.NewTransientStoreKey("transient_test")
143-
ctx := defaultContext(key, tkey)
144-
keeper := NewKeeper(cdc, key, tkey, DefaultCodespace)
107+
cdc, ctx, key, _, keeper := testComponents()
145108

146109
kvs := []struct {
147110
key string
@@ -216,3 +179,34 @@ func TestSubspace(t *testing.T) {
216179
require.Equal(t, kv.param, indirect(kv.ptr), "stored param not equal, tc #%d", i)
217180
}
218181
}
182+
183+
type paramJSON struct {
184+
Param1 int64 `json:"param1,omitempty"`
185+
Param2 string `json:"param2,omitempty"`
186+
}
187+
188+
func TestJSONUpdate(t *testing.T) {
189+
_, ctx, _, _, keeper := testComponents()
190+
191+
key := []byte("key")
192+
193+
space := keeper.Subspace("test").WithKeyTable(NewKeyTable(key, paramJSON{}))
194+
195+
var param paramJSON
196+
197+
space.Update(ctx, key, []byte(`{"param1": "10241024"}`))
198+
space.Get(ctx, key, &param)
199+
require.Equal(t, paramJSON{10241024, ""}, param)
200+
201+
space.Update(ctx, key, []byte(`{"param2": "helloworld"}`))
202+
space.Get(ctx, key, &param)
203+
require.Equal(t, paramJSON{10241024, "helloworld"}, param)
204+
205+
space.Update(ctx, key, []byte(`{"param1": "20482048"}`))
206+
space.Get(ctx, key, &param)
207+
require.Equal(t, paramJSON{20482048, "helloworld"}, param)
208+
209+
space.Update(ctx, key, []byte(`{"param1": "40964096", "param2": "goodbyeworld"}`))
210+
space.Get(ctx, key, &param)
211+
require.Equal(t, paramJSON{40964096, "goodbyeworld"}, param)
212+
}

x/params/proposal_handler.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,13 @@ func handleParameterChangeProposal(ctx sdk.Context, k Keeper, p ParameterChangeP
3232
k.Logger(ctx).Info(
3333
fmt.Sprintf("setting new parameter; key: %s, value: %s", c.Key, c.Value),
3434
)
35-
err = ss.SetRaw(ctx, []byte(c.Key), []byte(c.Value))
35+
36+
err = ss.Update(ctx, []byte(c.Key), []byte(c.Value))
3637
} else {
3738
k.Logger(ctx).Info(
3839
fmt.Sprintf("setting new parameter; key: %s, subkey: %s, value: %s", c.Key, c.Subspace, c.Value),
3940
)
40-
err = ss.SetRawWithSubkey(ctx, []byte(c.Key), []byte(c.Subkey), []byte(c.Value))
41+
err = ss.UpdateWithSubkey(ctx, []byte(c.Key), []byte(c.Subkey), []byte(c.Value))
4142
}
4243

4344
if err != nil {

x/params/proposal_handler_test.go

+33-3
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,24 @@ var (
2727
_ subspace.ParamSet = (*testParams)(nil)
2828

2929
keyMaxValidators = "MaxValidators"
30+
keySlashingRate = "SlashingRate"
3031
testSubspace = "TestSubspace"
3132
)
3233

34+
type testParamsSlashingRate struct {
35+
DoubleSign uint16 `json:"double_sign,omitempty"`
36+
Downtime uint16 `json:"downtime,omitempty"`
37+
}
38+
3339
type testParams struct {
34-
MaxValidators uint16 `json:"max_validators"` // maximum number of validators (max uint16 = 65535)
40+
MaxValidators uint16 `json:"max_validators"` // maximum number of validators (max uint16 = 65535)
41+
SlashingRate testParamsSlashingRate `json:"slashing_rate"`
3542
}
3643

3744
func (tp *testParams) ParamSetPairs() subspace.ParamSetPairs {
3845
return subspace.ParamSetPairs{
3946
{[]byte(keyMaxValidators), &tp.MaxValidators},
47+
{[]byte(keySlashingRate), &tp.SlashingRate},
4048
}
4149
}
4250

@@ -76,7 +84,7 @@ func TestProposalHandlerPassed(t *testing.T) {
7684
params.NewKeyTable().RegisterParamSet(&testParams{}),
7785
)
7886

79-
tp := testProposal(params.NewParamChange(testSubspace, keyMaxValidators, "", "1"))
87+
tp := testProposal(params.NewParamChange(testSubspace, keyMaxValidators, "1"))
8088
hdlr := params.NewParamChangeProposalHandler(input.keeper)
8189
require.NoError(t, hdlr(input.ctx, tp))
8290

@@ -91,9 +99,31 @@ func TestProposalHandlerFailed(t *testing.T) {
9199
params.NewKeyTable().RegisterParamSet(&testParams{}),
92100
)
93101

94-
tp := testProposal(params.NewParamChange(testSubspace, keyMaxValidators, "", "invalidType"))
102+
tp := testProposal(params.NewParamChange(testSubspace, keyMaxValidators, "invalidType"))
95103
hdlr := params.NewParamChangeProposalHandler(input.keeper)
96104
require.Error(t, hdlr(input.ctx, tp))
97105

98106
require.False(t, ss.Has(input.ctx, []byte(keyMaxValidators)))
99107
}
108+
109+
func TestProposalHandlerUpdateOmitempty(t *testing.T) {
110+
input := newTestInput(t)
111+
ss := input.keeper.Subspace(testSubspace).WithKeyTable(
112+
params.NewKeyTable().RegisterParamSet(&testParams{}),
113+
)
114+
115+
hdlr := params.NewParamChangeProposalHandler(input.keeper)
116+
var param testParamsSlashingRate
117+
118+
tp := testProposal(params.NewParamChange(testSubspace, keySlashingRate, `{"downtime": 7}`))
119+
require.NoError(t, hdlr(input.ctx, tp))
120+
121+
ss.Get(input.ctx, []byte(keySlashingRate), &param)
122+
require.Equal(t, testParamsSlashingRate{0, 7}, param)
123+
124+
tp = testProposal(params.NewParamChange(testSubspace, keySlashingRate, `{"double_sign": 10}`))
125+
require.NoError(t, hdlr(input.ctx, tp))
126+
127+
ss.Get(input.ctx, []byte(keySlashingRate), &param)
128+
require.Equal(t, testParamsSlashingRate{10, 7}, param)
129+
}

0 commit comments

Comments
 (0)