Skip to content

Commit

Permalink
feat!: initial deposit requirement for proposals (#12771)
Browse files Browse the repository at this point in the history
* feat!: initial deposit requirement for proposals

* changelog

* fix genesis sim tests

* msg server test and err check

* fix e2e gov tests

* fix param tests

* fix sim and migration tests

* remove redundant check

* uncomment tests and revert the consensus version change

* migrations comment

* fix comment in simulation genesis

* restore zero ratio check

* remove gogoproto tag from new param

* upgrading.md

Co-authored-by: Aleksandr Bezobchuk <[email protected]>
  • Loading branch information
p0mvn and alexanderbez authored Aug 2, 2022
1 parent 0f7e56c commit 07f7035
Show file tree
Hide file tree
Showing 27 changed files with 584 additions and 171 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (x/gov) [#12631](https://github.com/cosmos/cosmos-sdk/pull/12631) Migrate `x/gov` to self-managed parameters and deprecate it's usage of `x/params`.
* (x/staking) [#12409](https://github.com/cosmos/cosmos-sdk/pull/12409) Migrate `x/staking` to self-managed parameters and deprecate it's usage of `x/params`.
* (x/bank) [#11859](https://github.com/cosmos/cosmos-sdk/pull/11859) Move the SendEnabled information out of the Params and into the state store directly.
* (x/gov) [#12771](https://github.com/cosmos/cosmos-sdk/pull/12771) Initial deposit requirement for proposals at submission time.

### API Breaking Changes

Expand Down
14 changes: 13 additions & 1 deletion UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,26 @@ This means you can replace your usage of `simapp.MakeTestEncodingConfig` in test

### Client Changes

### `x/gov` v1
### `x/gov`

#### `types/v1`

The `gov` module has been greatly improved. The previous API has been moved to `v1beta1` while the new implementation is called `v1`.

In order to submit a proposal with `submit-proposal` you now need to pass a `proposal.json` file.
You can still use the old way by using `submit-legacy-proposal`. This is not recommended.
More information can be found in the gov module [client documentation](https://docs.cosmos.network/v0.46/modules/gov/07_client.html).

#### Minimum Proposal Deposit At Time of Submission

The `gov` module has been updated to support a minimum proposal deposit at submission time. It is determined by a new
parameter called `MinInitialDepositRatio`. When multiplied by the existing `MinDeposit` parameter, it produces
the necessary proportion of coins needed at the proposal submission time. The motivation for this change is to prevent proposal spamming.

By default, the new `MinInitialDepositRatio` parameter is set to zero during migration. The value of zero signifies that this
feature is disabled. If chains wish to utilize the minimum proposal deposits at time of submission, the migration logic needs to be
modified to set the new parameter to the desired value.

### Keyring

The keyring has been refactored in v0.46.
Expand Down
2 changes: 1 addition & 1 deletion api/cosmos/distribution/v1beta1/distribution.pulsar.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

160 changes: 119 additions & 41 deletions api/cosmos/gov/v1/gov.pulsar.go

Large diffs are not rendered by default.

2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,6 @@ cosmossdk.io/errors v1.0.0-beta.7 h1:gypHW76pTQGVnHKo6QBkb4yFOJjC+sUGRc5Al3Odj1w
cosmossdk.io/errors v1.0.0-beta.7/go.mod h1:mz6FQMJRku4bY7aqS/Gwfcmr/ue91roMEKAmDUDpBfE=
cosmossdk.io/math v1.0.0-beta.3 h1:TbZxSopz2LqjJ7aXYfn7nJSb8vNaBklW6BLpcei1qwM=
cosmossdk.io/math v1.0.0-beta.3/go.mod h1:3LYasri3Zna4XpbrTNdKsWmD5fHHkaNAod/mNT9XdE4=
cosmossdk.io/math v1.0.0-beta.3.0.20220726092710-f848e4300a8a h1:3lmQIAF6ScBJ8kW5ZNejcBUJpwWhE2y57qEUI+OBESU=
cosmossdk.io/math v1.0.0-beta.3.0.20220726092710-f848e4300a8a/go.mod h1:3LYasri3Zna4XpbrTNdKsWmD5fHHkaNAod/mNT9XdE4=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU=
filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
Expand Down
4 changes: 2 additions & 2 deletions proto/cosmos/bank/v1beta1/authz.proto
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ message SendAuthorization {
repeated cosmos.base.v1beta1.Coin spend_limit = 1
[(gogoproto.nullable) = false, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins"];

// allow_list specifies an optional list of addresses to whom the grantee can send tokens on behalf of the
// granter. If omitted, any recipient is allowed.
// allow_list specifies an optional list of addresses to whom the grantee can send tokens on behalf of the
// granter. If omitted, any recipient is allowed.
//
// Since: cosmos-sdk 0.47
repeated string allow_list = 2;
Expand Down
6 changes: 3 additions & 3 deletions proto/cosmos/gov/v1/genesis.proto
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ message GenesisState {
repeated Proposal proposals = 4;
// Deprecated: Prefer to use `params` instead.
// deposit_params defines all the paramaters of related to deposit.
DepositParams deposit_params = 5 [deprecated=true];
DepositParams deposit_params = 5 [deprecated = true];
// Deprecated: Prefer to use `params` instead.
// voting_params defines all the paramaters of related to voting.
VotingParams voting_params = 6 [deprecated=true];
VotingParams voting_params = 6 [deprecated = true];
// Deprecated: Prefer to use `params` instead.
// tally_params defines all the paramaters of related to tally.
TallyParams tally_params = 7 [deprecated=true];
TallyParams tally_params = 7 [deprecated = true];
// params defines all the paramaters of x/gov module.
//
// Since: cosmos-sdk 0.47
Expand Down
3 changes: 3 additions & 0 deletions proto/cosmos/gov/v1/gov.proto
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,7 @@ message Params {
// Minimum value of Veto votes to Total votes ratio for proposal to be
// vetoed. Default value: 1/3.
string veto_threshold = 6 [(cosmos_proto.scalar) = "cosmos.Dec"];

// The ratio representing the proportion of the deposit value that must be paid at proposal submission.
string min_initial_deposit_ratio = 7 [(cosmos_proto.scalar) = "cosmos.Dec"];
}
6 changes: 3 additions & 3 deletions proto/cosmos/gov/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -132,13 +132,13 @@ message QueryParamsRequest {
message QueryParamsResponse {
// Deprecated: Prefer to use `params` instead.
// voting_params defines the parameters related to voting.
VotingParams voting_params = 1 [deprecated=true];
VotingParams voting_params = 1 [deprecated = true];
// Deprecated: Prefer to use `params` instead.
// deposit_params defines the parameters related to deposit.
DepositParams deposit_params = 2 [deprecated=true];
DepositParams deposit_params = 2 [deprecated = true];
// Deprecated: Prefer to use `params` instead.
// tally_params defines the parameters related to tally.
TallyParams tally_params = 3 [deprecated=true];
TallyParams tally_params = 3 [deprecated = true];
// params defines all the paramaters of x/gov module.
//
// Since: cosmos-sdk 0.47
Expand Down
2 changes: 1 addition & 1 deletion x/distribution/types/distribution.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion x/gov/client/testutil/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func (s *IntegrationTestSuite) TestCmdParams() {
{
"json output",
[]string{fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
`{"voting_params":{"voting_period":"172800s"},"deposit_params":{"min_deposit":[{"denom":"stake","amount":"10000000"}],"max_deposit_period":"172800s"},"tally_params":{"quorum":"0.334000000000000000","threshold":"0.500000000000000000","veto_threshold":"0.334000000000000000"},"params":{"min_deposit":[{"denom":"stake","amount":"10000000"}],"max_deposit_period":"172800s","voting_period":"172800s","quorum":"0.334000000000000000","threshold":"0.500000000000000000","veto_threshold":"0.334000000000000000"}}`,
`{"voting_params":{"voting_period":"172800s"},"deposit_params":{"min_deposit":[{"denom":"stake","amount":"10000000"}],"max_deposit_period":"172800s"},"tally_params":{"quorum":"0.334000000000000000","threshold":"0.500000000000000000","veto_threshold":"0.334000000000000000"},"params":{"min_deposit":[{"denom":"stake","amount":"10000000"}],"max_deposit_period":"172800s","voting_period":"172800s","quorum":"0.334000000000000000","threshold":"0.500000000000000000","veto_threshold":"0.334000000000000000","min_initial_deposit_ratio":"0.000000000000000000"}}`,
},
{
"text output",
Expand All @@ -40,6 +40,7 @@ params:
min_deposit:
- amount: "10000000"
denom: stake
min_initial_deposit_ratio: "0.000000000000000000"
quorum: "0.334000000000000000"
threshold: "0.500000000000000000"
veto_threshold: "0.334000000000000000"
Expand Down
20 changes: 10 additions & 10 deletions x/gov/client/testutil/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,18 +165,18 @@ func (s *IntegrationTestSuite) TestNewCmdSubmitProposal() {
func (s *IntegrationTestSuite) TestNewCmdSubmitLegacyProposal() {
val := s.network.Validators[0]
invalidProp := `{
"title": "",
"description": "Where is the title!?",
"type": "Text",
"deposit": "-324foocoin"
}`
"title": "",
"description": "Where is the title!?",
"type": "Text",
"deposit": "-324foocoin"
}`
invalidPropFile := testutil.WriteToNewTempFile(s.T(), invalidProp)
validProp := fmt.Sprintf(`{
"title": "Text Proposal",
"description": "Hello, World!",
"type": "Text",
"deposit": "%s"
}`, sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(5431)))
"title": "Text Proposal",
"description": "Hello, World!",
"type": "Text",
"deposit": "%s"
}`, sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(5431)))
validPropFile := testutil.WriteToNewTempFile(s.T(), validProp)
testCases := []struct {
name string
Expand Down
22 changes: 22 additions & 0 deletions x/gov/keeper/deposit.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,3 +178,25 @@ func (keeper Keeper) RefundAndDeleteDeposits(ctx sdk.Context, proposalID uint64)
return false
})
}

// validateInitialDeposit validates if initial deposit is greater than or equal to the minimum
// required at the time of proposal submission. This threshold amount is determined by
// the deposit parameters. Returns nil on success, error otherwise.
func (keeper Keeper) validateInitialDeposit(ctx sdk.Context, initialDeposit sdk.Coins) error {
params := keeper.GetParams(ctx)
minInitialDepositRatio, err := sdk.NewDecFromStr(params.MinInitialDepositRatio)
if err != nil {
return err
}
if minInitialDepositRatio.IsZero() {
return nil
}
minDepositCoins := params.MinDeposit
for i := range minDepositCoins {
minDepositCoins[i].Amount = sdk.NewDecFromInt(minDepositCoins[i].Amount).Mul(minInitialDepositRatio).RoundInt()
}
if !initialDeposit.IsAllGTE(minDepositCoins) {
return sdkerrors.Wrapf(types.ErrMinDepositTooSmall, "was (%s), need (%s)", initialDeposit, minDepositCoins)
}
return nil
}
105 changes: 105 additions & 0 deletions x/gov/keeper/deposit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ import (

"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
)

const (
baseDepositTestAmount = 100
baseDepositTestPercent = 25
)

func TestDeposits(t *testing.T) {
Expand Down Expand Up @@ -111,3 +117,102 @@ func TestDeposits(t *testing.T) {
require.Len(t, deposits, 0)
require.Equal(t, addr0Initial.Sub(fourStake...), app.BankKeeper.GetAllBalances(ctx, TestAddrs[0]))
}

func TestValidateInitialDeposit(t *testing.T) {
testcases := map[string]struct {
minDeposit sdk.Coins
minInitialDepositPercent int64
initialDeposit sdk.Coins

expectError bool
}{
"min deposit * initial percent == initial deposit: success": {
minDeposit: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(baseDepositTestAmount))),
minInitialDepositPercent: baseDepositTestPercent,
initialDeposit: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(baseDepositTestAmount*baseDepositTestPercent/100))),
},
"min deposit * initial percent < initial deposit: success": {
minDeposit: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(baseDepositTestAmount))),
minInitialDepositPercent: baseDepositTestPercent,
initialDeposit: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(baseDepositTestAmount*baseDepositTestPercent/100+1))),
},
"min deposit * initial percent > initial deposit: error": {
minDeposit: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(baseDepositTestAmount))),
minInitialDepositPercent: baseDepositTestPercent,
initialDeposit: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(baseDepositTestAmount*baseDepositTestPercent/100-1))),

expectError: true,
},
"min deposit * initial percent == initial deposit (non-base values and denom): success": {
minDeposit: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(56912))),
minInitialDepositPercent: 50,
initialDeposit: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(56912/2+10))),
},
"min deposit * initial percent == initial deposit but different denoms: error": {
minDeposit: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(baseDepositTestAmount))),
minInitialDepositPercent: baseDepositTestPercent,
initialDeposit: sdk.NewCoins(sdk.NewCoin("uosmo", sdk.NewInt(baseDepositTestAmount*baseDepositTestPercent/100))),

expectError: true,
},
"min deposit * initial percent == initial deposit (multiple coins): success": {
minDeposit: sdk.NewCoins(
sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(baseDepositTestAmount)),
sdk.NewCoin("uosmo", sdk.NewInt(baseDepositTestAmount*2))),
minInitialDepositPercent: baseDepositTestPercent,
initialDeposit: sdk.NewCoins(
sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(baseDepositTestAmount*baseDepositTestPercent/100)),
sdk.NewCoin("uosmo", sdk.NewInt(baseDepositTestAmount*2*baseDepositTestPercent/100)),
),
},
"min deposit * initial percent > initial deposit (multiple coins): error": {
minDeposit: sdk.NewCoins(
sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(baseDepositTestAmount)),
sdk.NewCoin("uosmo", sdk.NewInt(baseDepositTestAmount*2))),
minInitialDepositPercent: baseDepositTestPercent,
initialDeposit: sdk.NewCoins(
sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(baseDepositTestAmount*baseDepositTestPercent/100)),
sdk.NewCoin("uosmo", sdk.NewInt(baseDepositTestAmount*2*baseDepositTestPercent/100-1)),
),

expectError: true,
},
"min deposit * initial percent < initial deposit (multiple coins - coin not required by min deposit): success": {
minDeposit: sdk.NewCoins(
sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(baseDepositTestAmount))),
minInitialDepositPercent: baseDepositTestPercent,
initialDeposit: sdk.NewCoins(
sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(baseDepositTestAmount*baseDepositTestPercent/100)),
sdk.NewCoin("uosmo", sdk.NewInt(baseDepositTestAmount*baseDepositTestPercent/100-1)),
),
},
"0 initial percent: success": {
minDeposit: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(baseDepositTestAmount))),
minInitialDepositPercent: 0,
initialDeposit: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(baseDepositTestAmount*baseDepositTestPercent/100))),
},
}

for name, tc := range testcases {
t.Run(name, func(t *testing.T) {
app := simapp.Setup(t, false)
ctx := app.BaseApp.NewContext(false, tmproto.Header{})

govKeeper := app.GovKeeper

params := v1.DefaultParams()
params.MinDeposit = tc.minDeposit
params.MinInitialDepositRatio = sdk.NewDec(tc.minInitialDepositPercent).Quo(sdk.NewDec(100)).String()

govKeeper.SetParams(ctx, params)

err := govKeeper.ValidateInitialDeposit(ctx, tc.initialDeposit)

if tc.expectError {
require.Error(t, err)
return
}
require.NoError(t, err)
})
}
}
7 changes: 7 additions & 0 deletions x/gov/keeper/export_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package keeper

import sdk "github.com/cosmos/cosmos-sdk/types"

func (k Keeper) ValidateInitialDeposit(ctx sdk.Context, initialDeposit sdk.Coins) error {
return k.validateInitialDeposit(ctx, initialDeposit)
}
7 changes: 6 additions & 1 deletion x/gov/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,16 @@ var _ v1.MsgServer = msgServer{}
func (k msgServer) SubmitProposal(goCtx context.Context, msg *v1.MsgSubmitProposal) (*v1.MsgSubmitProposalResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

initialDeposit := msg.GetInitialDeposit()

if err := k.validateInitialDeposit(ctx, initialDeposit); err != nil {
return nil, err
}

proposalMsgs, err := msg.GetMsgs()
if err != nil {
return nil, err
}

proposal, err := k.Keeper.SubmitProposal(ctx, proposalMsgs, msg.Metadata)
if err != nil {
return nil, err
Expand Down
Loading

0 comments on commit 07f7035

Please sign in to comment.