From eb607ae954db7e88f0f5f9e50d9111c1b8117438 Mon Sep 17 00:00:00 2001 From: Marie Gauthier Date: Fri, 8 Apr 2022 12:03:43 +0200 Subject: [PATCH] chore: x/gov v1 Completeness audit (#11567) ## Description Closes: https://github.com/cosmos/cosmos-sdk/issues/11086 --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [x] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] added `!` to the type prefix if API or client breaking change - [x] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting)) - [x] provided a link to the relevant issue or specification - [ ] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules) - [ ] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing) - [ ] added a changelog entry to `CHANGELOG.md` - [ ] included comments for [documenting Go code](https://blog.golang.org/godoc) - [ ] updated the relevant documentation or specification - [ ] reviewed "Files changed" and left comments if necessary - [ ] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] confirmed `!` in the type prefix if API or client breaking change - [ ] confirmed all author checklist items have been addressed - [ ] reviewed state machine logic - [ ] reviewed API design and naming - [ ] reviewed documentation is accurate - [ ] reviewed tests and test coverage - [ ] manually tested (if applicable) --- CHANGELOG.md | 1 - x/gov/client/cli/parse.go | 6 - x/gov/client/cli/parse_test.go | 60 ++- x/gov/client/cli/tx.go | 12 +- x/gov/client/testutil/helpers.go | 14 - x/gov/client/testutil/query.go | 536 ++++++++++++++++++++++ x/gov/client/testutil/{suite.go => tx.go} | 525 --------------------- x/gov/migrations/v046/convert_test.go | 175 +++++++ x/gov/spec/02_state.md | 2 +- x/gov/spec/03_messages.md | 2 +- x/gov/spec/07_client.md | 8 +- x/gov/types/v1/genesis.go | 2 +- x/gov/types/v1/genesis_test.go | 72 ++- x/upgrade/client/cli/tx.go | 4 +- 14 files changed, 847 insertions(+), 572 deletions(-) create mode 100644 x/gov/client/testutil/query.go rename x/gov/client/testutil/{suite.go => tx.go} (57%) create mode 100644 x/gov/migrations/v046/convert_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index c5ee595fc5..2b87ecd0d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -171,7 +171,6 @@ Ref: https://keepachangelog.com/en/1.0.0/ * [\#9780](https://github.com/cosmos/cosmos-sdk/pull/9780) Use sigs.k8s.io for yaml, which might lead to minor YAML output changes * [\#10625](https://github.com/cosmos/cosmos-sdk/pull/10625) Rename `--fee-account` CLI flag to `--fee-granter` * [\#10684](https://github.com/cosmos/cosmos-sdk/pull/10684) Rename `edit-validator` command's `--moniker` flag to `--new-moniker` -* [\#11116](https://github.com/cosmos/cosmos-sdk/pull/11116) `software-upgrade` and `cancel-software-upgrade` gov proposal commands have changed to `legacy-software-upgrade` and `legacy-cancel-software-upgrade`. * (authz)[\#11060](https://github.com/cosmos/cosmos-sdk/pull/11060) Changed the default value of the `--expiration` `tx grant` CLI Flag: was now + 1year, update: null (no expire date). ### Improvements diff --git a/x/gov/client/cli/parse.go b/x/gov/client/cli/parse.go index e5a6cc3cb9..a43d7f868c 100644 --- a/x/gov/client/cli/parse.go +++ b/x/gov/client/cli/parse.go @@ -40,12 +40,6 @@ func parseSubmitLegacyProposalFlags(fs *pflag.FlagSet) (*legacyProposal, error) if proposalFile == "" { proposalType, _ := fs.GetString(FlagProposalType) - title, _ := fs.GetString(FlagTitle) - description, _ := fs.GetString(FlagDescription) - if proposalType == "" && title == "" && description == "" { - return nil, fmt.Errorf("one of the --proposal or (--title, --description and --type) flags are required") - } - proposal.Title, _ = fs.GetString(FlagTitle) proposal.Description, _ = fs.GetString(FlagDescription) proposal.Type = govutils.NormalizeProposalType(proposalType) diff --git a/x/gov/client/cli/parse_test.go b/x/gov/client/cli/parse_test.go index e3c1afa22f..e80c8c7c1a 100644 --- a/x/gov/client/cli/parse_test.go +++ b/x/gov/client/cli/parse_test.go @@ -60,17 +60,57 @@ func TestParseSubmitLegacyProposalFlags(t *testing.T) { // no --proposal, only flags fs.Set(FlagProposal, "") - fs.Set(FlagTitle, proposal1.Title) - fs.Set(FlagDescription, proposal1.Description) - fs.Set(FlagProposalType, proposal1.Type) - fs.Set(FlagDeposit, proposal1.Deposit) - proposal2, err := parseSubmitLegacyProposalFlags(fs) + flagTestCases := map[string]struct { + pTitle string + pDescription string + pType string + expErr bool + errMsg string + }{ + "valid flags": { + pTitle: proposal1.Title, + pDescription: proposal1.Description, + pType: proposal1.Type, + }, + "empty type": { + pTitle: proposal1.Title, + pDescription: proposal1.Description, + expErr: true, + errMsg: "proposal type is required", + }, + "empty title": { + pDescription: proposal1.Description, + pType: proposal1.Type, + expErr: true, + errMsg: "proposal title is required", + }, + "empty description": { + pTitle: proposal1.Title, + pType: proposal1.Type, + expErr: true, + errMsg: "proposal description is required", + }, + } + for name, tc := range flagTestCases { + t.Run(name, func(t *testing.T) { + fs.Set(FlagTitle, tc.pTitle) + fs.Set(FlagDescription, tc.pDescription) + fs.Set(FlagProposalType, tc.pType) + fs.Set(FlagDeposit, proposal1.Deposit) + proposal2, err := parseSubmitLegacyProposalFlags(fs) - require.Nil(t, err, "unexpected error") - require.Equal(t, proposal1.Title, proposal2.Title) - require.Equal(t, proposal1.Description, proposal2.Description) - require.Equal(t, proposal1.Type, proposal2.Type) - require.Equal(t, proposal1.Deposit, proposal2.Deposit) + if tc.expErr { + require.Error(t, err) + require.Contains(t, err.Error(), tc.errMsg) + } else { + require.NoError(t, err) + require.Equal(t, proposal1.Title, proposal2.Title) + require.Equal(t, proposal1.Description, proposal2.Description) + require.Equal(t, proposal1.Type, proposal2.Type) + require.Equal(t, proposal1.Deposit, proposal2.Deposit) + } + }) + } err = okJSON.Close() require.Nil(t, err, "unexpected error") diff --git a/x/gov/client/cli/tx.go b/x/gov/client/cli/tx.go index fcb030e146..bdf74f4493 100644 --- a/x/gov/client/cli/tx.go +++ b/x/gov/client/cli/tx.go @@ -35,7 +35,7 @@ const ( FlagProposal = "proposal" ) -// ProposalFlags defines the core required fields of a proposal. It is used to +// ProposalFlags defines the core required fields of a legacy proposal. It is used to // verify that these values are not provided in conjunction with a JSON proposal // file. var ProposalFlags = []string{ @@ -47,7 +47,7 @@ var ProposalFlags = []string{ // NewTxCmd returns the transaction commands for this module // governance ModuleClient is slightly different from other ModuleClients in that -// it contains a slice of "proposal" child commands. These commands are respective +// it contains a slice of legacy "proposal" child commands. These commands are respective // to the proposal type handlers that are implemented in other modules but are mounted // under the governance CLI (eg. parameter change proposals). func NewTxCmd(legacyPropCmds []*cobra.Command) *cobra.Command { @@ -81,12 +81,12 @@ func NewTxCmd(legacyPropCmds []*cobra.Command) *cobra.Command { // NewCmdSubmitProposal implements submitting a proposal transaction command. func NewCmdSubmitProposal() *cobra.Command { cmd := &cobra.Command{ - Use: "submit-proposal", - Short: "Submit a proposal along with some messages and metadata", + Use: "submit-proposal [path/to/proposal.json]", + Short: "Submit a proposal along with some messages, metadata and deposit", Args: cobra.ExactArgs(1), Long: strings.TrimSpace( - fmt.Sprintf(`Submit a proposal along with some messages and metadata. -Messages, metadata and deposit are defined in a JSON file. + fmt.Sprintf(`Submit a proposal along with some messages, metadata and deposit. +They should be defined in a JSON file. Example: $ %s tx gov submit-proposal path/to/proposal.json diff --git a/x/gov/client/testutil/helpers.go b/x/gov/client/testutil/helpers.go index 0e17ead4a5..6dbb0d8722 100644 --- a/x/gov/client/testutil/helpers.go +++ b/x/gov/client/testutil/helpers.go @@ -17,20 +17,6 @@ var commonArgs = []string{ fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(10))).String()), } -// MsgSubmitProposal creates a tx for submit proposal -func MsgSubmitProposal(clientCtx client.Context, from, title, description, proposalType string, extraArgs ...string) (testutil.BufferWriter, error) { - args := append([]string{ - fmt.Sprintf("--%s=%s", govcli.FlagTitle, title), - fmt.Sprintf("--%s=%s", govcli.FlagDescription, description), - fmt.Sprintf("--%s=%s", govcli.FlagProposalType, proposalType), - fmt.Sprintf("--%s=%s", flags.FlagFrom, from), - }, commonArgs...) - - args = append(args, extraArgs...) - - return clitestutil.ExecTestCLICmd(clientCtx, govcli.NewCmdSubmitProposal(), args) -} - // MsgSubmitLegacyProposal creates a tx for submit legacy proposal func MsgSubmitLegacyProposal(clientCtx client.Context, from, title, description, proposalType string, extraArgs ...string) (testutil.BufferWriter, error) { args := append([]string{ diff --git a/x/gov/client/testutil/query.go b/x/gov/client/testutil/query.go new file mode 100644 index 0000000000..5f0502a8f0 --- /dev/null +++ b/x/gov/client/testutil/query.go @@ -0,0 +1,536 @@ +package testutil + +import ( + "fmt" + "strings" + + tmcli "github.com/tendermint/tendermint/libs/cli" + + clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/gov/client/cli" + v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" +) + +func (s *IntegrationTestSuite) TestCmdParams() { + val := s.network.Validators[0] + + testCases := []struct { + name string + args []string + expectedOutput string + }{ + { + "json output", + []string{fmt.Sprintf("--%s=json", tmcli.OutputFlag)}, + `{"voting_params":{"voting_period":"172800000000000"},"tally_params":{"quorum":"0.334000000000000000","threshold":"0.500000000000000000","veto_threshold":"0.334000000000000000"},"deposit_params":{"min_deposit":[{"denom":"stake","amount":"10000000"}],"max_deposit_period":"172800000000000"}}`, + }, + { + "text output", + []string{}, + ` +deposit_params: + max_deposit_period: "172800000000000" + min_deposit: + - amount: "10000000" + denom: stake +tally_params: + quorum: "0.334000000000000000" + threshold: "0.500000000000000000" + veto_threshold: "0.334000000000000000" +voting_params: + voting_period: "172800000000000" + `, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetCmdQueryParams() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + s.Require().NoError(err) + s.Require().Equal(strings.TrimSpace(tc.expectedOutput), strings.TrimSpace(out.String())) + }) + } +} + +func (s *IntegrationTestSuite) TestCmdParam() { + val := s.network.Validators[0] + + testCases := []struct { + name string + args []string + expectedOutput string + }{ + { + "voting params", + []string{ + "voting", + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + `{"voting_period":"172800000000000"}`, + }, + { + "tally params", + []string{ + "tallying", + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + `{"quorum":"0.334000000000000000","threshold":"0.500000000000000000","veto_threshold":"0.334000000000000000"}`, + }, + { + "deposit params", + []string{ + "deposit", + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + `{"min_deposit":[{"denom":"stake","amount":"10000000"}],"max_deposit_period":"172800000000000"}`, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetCmdQueryParam() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + s.Require().NoError(err) + s.Require().Equal(strings.TrimSpace(tc.expectedOutput), strings.TrimSpace(out.String())) + }) + } +} + +func (s *IntegrationTestSuite) TestCmdProposer() { + val := s.network.Validators[0] + + testCases := []struct { + name string + args []string + expectErr bool + expectedOutput string + }{ + { + "without proposal id", + []string{ + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + true, + ``, + }, + { + "json output", + []string{ + "1", + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + false, + fmt.Sprintf("{\"proposal_id\":\"%s\",\"proposer\":\"%s\"}", "1", val.Address.String()), + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetCmdQueryProposer() + clientCtx := val.ClientCtx + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + s.Require().Equal(strings.TrimSpace(tc.expectedOutput), strings.TrimSpace(out.String())) + } + }) + } +} + +func (s *IntegrationTestSuite) TestCmdTally() { + val := s.network.Validators[0] + + testCases := []struct { + name string + args []string + expectErr bool + expectedOutput v1.TallyResult + }{ + { + "without proposal id", + []string{ + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + true, + v1.TallyResult{}, + }, + { + "json output", + []string{ + "2", + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + false, + v1.NewTallyResult(sdk.NewInt(0), sdk.NewInt(0), sdk.NewInt(0), sdk.NewInt(0)), + }, + { + "json output", + []string{ + "1", + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + false, + v1.NewTallyResult(s.cfg.BondedTokens, sdk.NewInt(0), sdk.NewInt(0), sdk.NewInt(0)), + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetCmdQueryTally() + clientCtx := val.ClientCtx + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + + if tc.expectErr { + s.Require().Error(err) + } else { + var tally v1.TallyResult + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &tally), out.String()) + s.Require().Equal(tally, tc.expectedOutput) + } + }) + } +} + +func (s *IntegrationTestSuite) TestCmdGetProposal() { + val := s.network.Validators[0] + + title := "Text Proposal 1" + + testCases := []struct { + name string + args []string + expectErr bool + }{ + { + "get non existing proposal", + []string{ + "10", + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + true, + }, + { + "get proposal with json response", + []string{ + "1", + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetCmdQueryProposal() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + var proposal v1.Proposal + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &proposal), out.String()) + s.Require().Equal(title, proposal.Messages[0].GetCachedValue().(*v1.MsgExecLegacyContent).Content.GetCachedValue().(v1beta1.Content).GetTitle()) + } + }) + } +} + +func (s *IntegrationTestSuite) TestCmdGetProposals() { + val := s.network.Validators[0] + + testCases := []struct { + name string + args []string + expectErr bool + }{ + { + "get proposals as json response", + []string{ + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + false, + }, + { + "get proposals with invalid status", + []string{ + "--status=unknown", + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + true, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + cmd := cli.GetCmdQueryProposals() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + var proposals v1.QueryProposalsResponse + + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &proposals), out.String()) + s.Require().Len(proposals.Proposals, 3) + } + }) + } +} + +func (s *IntegrationTestSuite) TestCmdQueryDeposits() { + val := s.network.Validators[0] + + testCases := []struct { + name string + args []string + expectErr bool + }{ + { + "get deposits of non existing proposal", + []string{ + "10", + }, + true, + }, + { + "get deposits(valid req)", + []string{ + "1", + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + cmd := cli.GetCmdQueryDeposits() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + + var deposits v1.QueryDepositsResponse + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &deposits), out.String()) + s.Require().Len(deposits.Deposits, 1) + } + }) + } +} + +func (s *IntegrationTestSuite) TestCmdQueryDeposit() { + val := s.network.Validators[0] + depositAmount := sdk.NewCoin(s.cfg.BondDenom, v1.DefaultMinDepositTokens) + + testCases := []struct { + name string + args []string + expectErr bool + }{ + { + "get deposit with no depositer", + []string{ + "1", + }, + true, + }, + { + "get deposit with wrong deposit address", + []string{ + "1", + "wrong address", + }, + true, + }, + { + "get deposit (valid req)", + []string{ + "1", + val.Address.String(), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + cmd := cli.GetCmdQueryDeposit() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + + var deposit v1.Deposit + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &deposit), out.String()) + s.Require().Equal(depositAmount.String(), sdk.Coins(deposit.Amount).String()) + } + }) + } +} + +func (s *IntegrationTestSuite) TestCmdQueryVotes() { + val := s.network.Validators[0] + + testCases := []struct { + name string + args []string + expectErr bool + }{ + { + "get votes with no proposal id", + []string{}, + true, + }, + { + "get votes of non existed proposal", + []string{ + "10", + }, + true, + }, + { + "vote for invalid proposal", + []string{ + "1", + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + cmd := cli.GetCmdQueryVotes() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + + var votes v1.QueryVotesResponse + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &votes), out.String()) + s.Require().Len(votes.Votes, 1) + } + }) + } +} + +func (s *IntegrationTestSuite) TestCmdQueryVote() { + val := s.network.Validators[0] + + testCases := []struct { + name string + args []string + expectErr bool + expVoteOptions v1.WeightedVoteOptions + }{ + { + "get vote of non existing proposal", + []string{ + "10", + val.Address.String(), + }, + true, + v1.NewNonSplitVoteOption(v1.OptionYes), + }, + { + "get vote by wrong voter", + []string{ + "1", + "wrong address", + }, + true, + v1.NewNonSplitVoteOption(v1.OptionYes), + }, + { + "vote for valid proposal", + []string{ + "1", + val.Address.String(), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + false, + v1.NewNonSplitVoteOption(v1.OptionYes), + }, + { + "split vote for valid proposal", + []string{ + "3", + val.Address.String(), + fmt.Sprintf("--%s=json", tmcli.OutputFlag), + }, + false, + v1.WeightedVoteOptions{ + &v1.WeightedVoteOption{Option: v1.OptionYes, Weight: sdk.NewDecWithPrec(60, 2).String()}, + &v1.WeightedVoteOption{Option: v1.OptionNo, Weight: sdk.NewDecWithPrec(30, 2).String()}, + &v1.WeightedVoteOption{Option: v1.OptionAbstain, Weight: sdk.NewDecWithPrec(5, 2).String()}, + &v1.WeightedVoteOption{Option: v1.OptionNoWithVeto, Weight: sdk.NewDecWithPrec(5, 2).String()}, + }, + }, + } + + for _, tc := range testCases { + tc := tc + s.Run(tc.name, func() { + cmd := cli.GetCmdQueryVote() + clientCtx := val.ClientCtx + + out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) + + if tc.expectErr { + s.Require().Error(err) + } else { + s.Require().NoError(err) + + var vote v1.Vote + s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &vote), out.String()) + s.Require().Equal(len(vote.Options), len(tc.expVoteOptions)) + for i, option := range tc.expVoteOptions { + s.Require().Equal(option.Option, vote.Options[i].Option) + s.Require().Equal(option.Weight, vote.Options[i].Weight) + } + } + }) + } +} diff --git a/x/gov/client/testutil/suite.go b/x/gov/client/testutil/tx.go similarity index 57% rename from x/gov/client/testutil/suite.go rename to x/gov/client/testutil/tx.go index bbd5bbc2c2..f3f5a52c49 100644 --- a/x/gov/client/testutil/suite.go +++ b/x/gov/client/testutil/tx.go @@ -3,15 +3,12 @@ package testutil import ( "encoding/base64" "fmt" - "strings" "github.com/cosmos/cosmos-sdk/testutil" "github.com/gogo/protobuf/proto" "github.com/stretchr/testify/suite" - tmcli "github.com/tendermint/tendermint/libs/cli" - "github.com/cosmos/cosmos-sdk/client/flags" clitestutil "github.com/cosmos/cosmos-sdk/testutil/cli" "github.com/cosmos/cosmos-sdk/testutil/network" @@ -83,202 +80,6 @@ func (s *IntegrationTestSuite) TearDownSuite() { s.network.Cleanup() } -func (s *IntegrationTestSuite) TestCmdParams() { - val := s.network.Validators[0] - - testCases := []struct { - name string - args []string - expectedOutput string - }{ - { - "json output", - []string{fmt.Sprintf("--%s=json", tmcli.OutputFlag)}, - `{"voting_params":{"voting_period":"172800000000000"},"tally_params":{"quorum":"0.334000000000000000","threshold":"0.500000000000000000","veto_threshold":"0.334000000000000000"},"deposit_params":{"min_deposit":[{"denom":"stake","amount":"10000000"}],"max_deposit_period":"172800000000000"}}`, - }, - { - "text output", - []string{}, - ` -deposit_params: - max_deposit_period: "172800000000000" - min_deposit: - - amount: "10000000" - denom: stake -tally_params: - quorum: "0.334000000000000000" - threshold: "0.500000000000000000" - veto_threshold: "0.334000000000000000" -voting_params: - voting_period: "172800000000000" - `, - }, - } - - for _, tc := range testCases { - tc := tc - - s.Run(tc.name, func() { - cmd := cli.GetCmdQueryParams() - clientCtx := val.ClientCtx - - out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) - s.Require().NoError(err) - s.Require().Equal(strings.TrimSpace(tc.expectedOutput), strings.TrimSpace(out.String())) - }) - } -} - -func (s *IntegrationTestSuite) TestCmdParam() { - val := s.network.Validators[0] - - testCases := []struct { - name string - args []string - expectedOutput string - }{ - { - "voting params", - []string{ - "voting", - fmt.Sprintf("--%s=json", tmcli.OutputFlag), - }, - `{"voting_period":"172800000000000"}`, - }, - { - "tally params", - []string{ - "tallying", - fmt.Sprintf("--%s=json", tmcli.OutputFlag), - }, - `{"quorum":"0.334000000000000000","threshold":"0.500000000000000000","veto_threshold":"0.334000000000000000"}`, - }, - { - "deposit params", - []string{ - "deposit", - fmt.Sprintf("--%s=json", tmcli.OutputFlag), - }, - `{"min_deposit":[{"denom":"stake","amount":"10000000"}],"max_deposit_period":"172800000000000"}`, - }, - } - - for _, tc := range testCases { - tc := tc - - s.Run(tc.name, func() { - cmd := cli.GetCmdQueryParam() - clientCtx := val.ClientCtx - - out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) - s.Require().NoError(err) - s.Require().Equal(strings.TrimSpace(tc.expectedOutput), strings.TrimSpace(out.String())) - }) - } -} - -func (s *IntegrationTestSuite) TestCmdProposer() { - val := s.network.Validators[0] - - testCases := []struct { - name string - args []string - expectErr bool - expectedOutput string - }{ - { - "without proposal id", - []string{ - fmt.Sprintf("--%s=json", tmcli.OutputFlag), - }, - true, - ``, - }, - { - "json output", - []string{ - "1", - fmt.Sprintf("--%s=json", tmcli.OutputFlag), - }, - false, - fmt.Sprintf("{\"proposal_id\":\"%s\",\"proposer\":\"%s\"}", "1", val.Address.String()), - }, - } - - for _, tc := range testCases { - tc := tc - - s.Run(tc.name, func() { - cmd := cli.GetCmdQueryProposer() - clientCtx := val.ClientCtx - out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) - - if tc.expectErr { - s.Require().Error(err) - } else { - s.Require().NoError(err) - s.Require().Equal(strings.TrimSpace(tc.expectedOutput), strings.TrimSpace(out.String())) - } - }) - } -} - -func (s *IntegrationTestSuite) TestCmdTally() { - val := s.network.Validators[0] - - testCases := []struct { - name string - args []string - expectErr bool - expectedOutput v1.TallyResult - }{ - { - "without proposal id", - []string{ - fmt.Sprintf("--%s=json", tmcli.OutputFlag), - }, - true, - v1.TallyResult{}, - }, - { - "json output", - []string{ - "2", - fmt.Sprintf("--%s=json", tmcli.OutputFlag), - }, - false, - v1.NewTallyResult(sdk.NewInt(0), sdk.NewInt(0), sdk.NewInt(0), sdk.NewInt(0)), - }, - { - "json output", - []string{ - "1", - fmt.Sprintf("--%s=json", tmcli.OutputFlag), - }, - false, - v1.NewTallyResult(s.cfg.BondedTokens, sdk.NewInt(0), sdk.NewInt(0), sdk.NewInt(0)), - }, - } - - for _, tc := range testCases { - tc := tc - - s.Run(tc.name, func() { - cmd := cli.GetCmdQueryTally() - clientCtx := val.ClientCtx - out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) - - if tc.expectErr { - s.Require().Error(err) - } else { - var tally v1.TallyResult - s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &tally), out.String()) - s.Require().Equal(tally, tc.expectedOutput) - } - }) - } -} - func (s *IntegrationTestSuite) TestNewCmdSubmitProposal() { val := s.network.Validators[0] @@ -453,202 +254,6 @@ func (s *IntegrationTestSuite) TestNewCmdSubmitLegacyProposal() { } } -func (s *IntegrationTestSuite) TestCmdGetProposal() { - val := s.network.Validators[0] - - title := "Text Proposal 1" - - testCases := []struct { - name string - args []string - expectErr bool - }{ - { - "get non existing proposal", - []string{ - "10", - fmt.Sprintf("--%s=json", tmcli.OutputFlag), - }, - true, - }, - { - "get proposal with json response", - []string{ - "1", - fmt.Sprintf("--%s=json", tmcli.OutputFlag), - }, - false, - }, - } - - for _, tc := range testCases { - tc := tc - - s.Run(tc.name, func() { - cmd := cli.GetCmdQueryProposal() - clientCtx := val.ClientCtx - - out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) - if tc.expectErr { - s.Require().Error(err) - } else { - s.Require().NoError(err) - var proposal v1.Proposal - s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &proposal), out.String()) - s.Require().Equal(title, proposal.Messages[0].GetCachedValue().(*v1.MsgExecLegacyContent).Content.GetCachedValue().(v1beta1.Content).GetTitle()) - } - }) - } -} - -func (s *IntegrationTestSuite) TestCmdGetProposals() { - val := s.network.Validators[0] - - testCases := []struct { - name string - args []string - expectErr bool - }{ - { - "get proposals as json response", - []string{ - fmt.Sprintf("--%s=json", tmcli.OutputFlag), - }, - false, - }, - { - "get proposals with invalid status", - []string{ - "--status=unknown", - fmt.Sprintf("--%s=json", tmcli.OutputFlag), - }, - true, - }, - } - - for _, tc := range testCases { - tc := tc - - s.Run(tc.name, func() { - cmd := cli.GetCmdQueryProposals() - clientCtx := val.ClientCtx - - out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) - if tc.expectErr { - s.Require().Error(err) - } else { - s.Require().NoError(err) - var proposals v1.QueryProposalsResponse - - s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &proposals), out.String()) - s.Require().Len(proposals.Proposals, 3) - } - }) - } -} - -func (s *IntegrationTestSuite) TestCmdQueryDeposits() { - val := s.network.Validators[0] - - testCases := []struct { - name string - args []string - expectErr bool - }{ - { - "get deposits of non existing proposal", - []string{ - "10", - }, - true, - }, - { - "get deposits(valid req)", - []string{ - "1", - fmt.Sprintf("--%s=json", tmcli.OutputFlag), - }, - false, - }, - } - - for _, tc := range testCases { - tc := tc - s.Run(tc.name, func() { - cmd := cli.GetCmdQueryDeposits() - clientCtx := val.ClientCtx - - out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) - - if tc.expectErr { - s.Require().Error(err) - } else { - s.Require().NoError(err) - - var deposits v1.QueryDepositsResponse - s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &deposits), out.String()) - s.Require().Len(deposits.Deposits, 1) - } - }) - } -} - -func (s *IntegrationTestSuite) TestCmdQueryDeposit() { - val := s.network.Validators[0] - depositAmount := sdk.NewCoin(s.cfg.BondDenom, v1.DefaultMinDepositTokens) - - testCases := []struct { - name string - args []string - expectErr bool - }{ - { - "get deposit with no depositer", - []string{ - "1", - }, - true, - }, - { - "get deposit with wrong deposit address", - []string{ - "1", - "wrong address", - }, - true, - }, - { - "get deposit (valid req)", - []string{ - "1", - val.Address.String(), - fmt.Sprintf("--%s=json", tmcli.OutputFlag), - }, - false, - }, - } - - for _, tc := range testCases { - tc := tc - s.Run(tc.name, func() { - cmd := cli.GetCmdQueryDeposit() - clientCtx := val.ClientCtx - - out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) - - if tc.expectErr { - s.Require().Error(err) - } else { - s.Require().NoError(err) - - var deposit v1.Deposit - s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &deposit), out.String()) - s.Require().Equal(depositAmount.String(), sdk.Coins(deposit.Amount).String()) - } - }) - } -} - func (s *IntegrationTestSuite) TestNewCmdDeposit() { val := s.network.Validators[0] @@ -727,136 +332,6 @@ func (s *IntegrationTestSuite) TestNewCmdDeposit() { } } -func (s *IntegrationTestSuite) TestCmdQueryVotes() { - val := s.network.Validators[0] - - testCases := []struct { - name string - args []string - expectErr bool - }{ - { - "get votes with no proposal id", - []string{}, - true, - }, - { - "get votes of non existed proposal", - []string{ - "10", - }, - true, - }, - { - "vote for invalid proposal", - []string{ - "1", - fmt.Sprintf("--%s=json", tmcli.OutputFlag), - }, - false, - }, - } - - for _, tc := range testCases { - tc := tc - s.Run(tc.name, func() { - cmd := cli.GetCmdQueryVotes() - clientCtx := val.ClientCtx - - out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) - - if tc.expectErr { - s.Require().Error(err) - } else { - s.Require().NoError(err) - - var votes v1.QueryVotesResponse - s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &votes), out.String()) - s.Require().Len(votes.Votes, 1) - } - }) - } -} - -func (s *IntegrationTestSuite) TestCmdQueryVote() { - val := s.network.Validators[0] - - testCases := []struct { - name string - args []string - expectErr bool - expVoteOptions v1.WeightedVoteOptions - }{ - { - "get vote of non existing proposal", - []string{ - "10", - val.Address.String(), - }, - true, - v1.NewNonSplitVoteOption(v1.OptionYes), - }, - { - "get vote by wrong voter", - []string{ - "1", - "wrong address", - }, - true, - v1.NewNonSplitVoteOption(v1.OptionYes), - }, - { - "vote for valid proposal", - []string{ - "1", - val.Address.String(), - fmt.Sprintf("--%s=json", tmcli.OutputFlag), - }, - false, - v1.NewNonSplitVoteOption(v1.OptionYes), - }, - { - "split vote for valid proposal", - []string{ - "3", - val.Address.String(), - fmt.Sprintf("--%s=json", tmcli.OutputFlag), - }, - false, - v1.WeightedVoteOptions{ - &v1.WeightedVoteOption{Option: v1.OptionYes, Weight: sdk.NewDecWithPrec(60, 2).String()}, - &v1.WeightedVoteOption{Option: v1.OptionNo, Weight: sdk.NewDecWithPrec(30, 2).String()}, - &v1.WeightedVoteOption{Option: v1.OptionAbstain, Weight: sdk.NewDecWithPrec(5, 2).String()}, - &v1.WeightedVoteOption{Option: v1.OptionNoWithVeto, Weight: sdk.NewDecWithPrec(5, 2).String()}, - }, - }, - } - - for _, tc := range testCases { - tc := tc - s.Run(tc.name, func() { - cmd := cli.GetCmdQueryVote() - clientCtx := val.ClientCtx - - out, err := clitestutil.ExecTestCLICmd(clientCtx, cmd, tc.args) - - if tc.expectErr { - s.Require().Error(err) - } else { - s.Require().NoError(err) - - var vote v1.Vote - s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &vote), out.String()) - s.Require().Equal(len(vote.Options), len(tc.expVoteOptions)) - for i, option := range tc.expVoteOptions { - s.Require().Equal(option.Option, vote.Options[i].Option) - s.Require().Equal(option.Weight, vote.Options[i].Weight) - } - } - }) - } -} - func (s *IntegrationTestSuite) TestNewCmdVote() { val := s.network.Validators[0] diff --git a/x/gov/migrations/v046/convert_test.go b/x/gov/migrations/v046/convert_test.go new file mode 100644 index 0000000000..e8cbfedc26 --- /dev/null +++ b/x/gov/migrations/v046/convert_test.go @@ -0,0 +1,175 @@ +package v046_test + +import ( + "testing" + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/tx" + v046 "github.com/cosmos/cosmos-sdk/x/gov/migrations/v046" + v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + "github.com/stretchr/testify/require" +) + +func TestConvertToLegacyProposal(t *testing.T) { + propTime := time.Unix(1e9, 0) + legacyContentMsg, err := v1.NewLegacyContent(v1beta1.NewTextProposal("title", "description"), "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh") + require.NoError(t, err) + msgs := []sdk.Msg{legacyContentMsg} + msgsAny, err := tx.SetMsgs(msgs) + require.NoError(t, err) + proposal := v1.Proposal{ + Id: 1, + Status: v1.StatusDepositPeriod, + Messages: msgsAny, + SubmitTime: &propTime, + DepositEndTime: &propTime, + VotingStartTime: &propTime, + VotingEndTime: &propTime, + Metadata: "proposal metadata", + } + + testCases := map[string]struct { + tallyResult v1.TallyResult + expErr bool + }{ + "valid": { + tallyResult: v1.EmptyTallyResult(), + }, + "invalid final tally result": { + tallyResult: v1.TallyResult{}, + expErr: true, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + proposal.FinalTallyResult = &tc.tallyResult + v1beta1Proposal, err := v046.ConvertToLegacyProposal(proposal) + if tc.expErr { + require.Error(t, err) + } else { + require.NoError(t, err) + require.Equal(t, v1beta1Proposal.ProposalId, proposal.Id) + require.Equal(t, v1beta1Proposal.VotingStartTime, *proposal.VotingStartTime) + require.Equal(t, v1beta1Proposal.VotingEndTime, *proposal.VotingEndTime) + require.Equal(t, v1beta1Proposal.SubmitTime, *proposal.SubmitTime) + require.Equal(t, v1beta1Proposal.DepositEndTime, *proposal.DepositEndTime) + require.Equal(t, v1beta1Proposal.FinalTallyResult.Yes, sdk.NewInt(0)) + require.Equal(t, v1beta1Proposal.FinalTallyResult.No, sdk.NewInt(0)) + require.Equal(t, v1beta1Proposal.FinalTallyResult.NoWithVeto, sdk.NewInt(0)) + require.Equal(t, v1beta1Proposal.FinalTallyResult.Abstain, sdk.NewInt(0)) + } + }) + } +} + +func TestConvertToLegacyTallyResult(t *testing.T) { + tallyResult := v1.EmptyTallyResult() + testCases := map[string]struct { + tallyResult v1.TallyResult + expErr bool + }{ + "valid": { + tallyResult: tallyResult, + }, + "invalid yes count": { + tallyResult: v1.TallyResult{ + YesCount: "invalid", + NoCount: tallyResult.NoCount, + AbstainCount: tallyResult.AbstainCount, + NoWithVetoCount: tallyResult.NoWithVetoCount, + }, + expErr: true, + }, + "invalid no count": { + tallyResult: v1.TallyResult{ + YesCount: tallyResult.YesCount, + NoCount: "invalid", + AbstainCount: tallyResult.AbstainCount, + NoWithVetoCount: tallyResult.NoWithVetoCount, + }, + expErr: true, + }, + "invalid abstain count": { + tallyResult: v1.TallyResult{ + YesCount: tallyResult.YesCount, + NoCount: tallyResult.NoCount, + AbstainCount: "invalid", + NoWithVetoCount: tallyResult.NoWithVetoCount, + }, + expErr: true, + }, + "invalid no with veto count": { + tallyResult: v1.TallyResult{ + YesCount: tallyResult.YesCount, + NoCount: tallyResult.NoCount, + AbstainCount: tallyResult.AbstainCount, + NoWithVetoCount: "invalid", + }, + expErr: true, + }, + } + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + _, err := v046.ConvertToLegacyTallyResult(&tc.tallyResult) + if tc.expErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} + +func TestConvertToLegacyVote(t *testing.T) { + vote := v1.Vote{ + ProposalId: 1, + Voter: "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh", + Metadata: "vote metadata", + } + + testCases := map[string]struct { + options []*v1.WeightedVoteOption + expErr bool + }{ + "valid": { + options: v1.NewNonSplitVoteOption(v1.OptionYes), + }, + "invalid options": { + options: []*v1.WeightedVoteOption{{Option: 1, Weight: "invalid"}}, + expErr: true, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + vote.Options = tc.options + v1beta1Vote, err := v046.ConvertToLegacyVote(vote) + if tc.expErr { + require.Error(t, err) + } else { + require.NoError(t, err) + require.Equal(t, v1beta1Vote.ProposalId, vote.ProposalId) + require.Equal(t, v1beta1Vote.Voter, vote.Voter) + require.Equal(t, v1beta1Vote.Options[0].Option, v1beta1.OptionYes) + require.Equal(t, v1beta1Vote.Options[0].Weight, sdk.NewDec(1)) + } + }) + } +} + +func TestConvertToLegacyDeposit(t *testing.T) { + deposit := v1.Deposit{ + ProposalId: 1, + Depositor: "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh", + Amount: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1))), + } + + v1beta1Deposit := v046.ConvertToLegacyDeposit(&deposit) + require.Equal(t, v1beta1Deposit.ProposalId, deposit.ProposalId) + require.Equal(t, v1beta1Deposit.Depositor, deposit.Depositor) + require.Equal(t, v1beta1Deposit.Amount[0], deposit.Amount[0]) + +} diff --git a/x/gov/spec/02_state.md b/x/gov/spec/02_state.md index 7c071531f2..f7032a368b 100644 --- a/x/gov/spec/02_state.md +++ b/x/gov/spec/02_state.md @@ -12,7 +12,7 @@ to resolve and then execute if the proposal passes. `Proposal`'s are identified unique id and contains a series of timestamps: `submit_time`, `deposit_end_time`, `voting_start_time`, `voting_end_time` which track the lifecycle of a proposal -+++ https://github.com/cosmos/cosmos-sdk/blob/4a129832eb16f37a89e97652a669f0cdc9196ca9/proto/cosmos/gov/v1beta2/gov.proto#L42-L52 ++++ https://github.com/cosmos/cosmos-sdk/blob/5bde3686c4538ce53356af6e9fe40b34e4ce4a06/proto/cosmos/gov/v1/gov.proto#L42-L59 A proposal will generally require more than just a set of messages to explain its purpose but need some greater justification and allow a means for interested participants diff --git a/x/gov/spec/03_messages.md b/x/gov/spec/03_messages.md index f1cb432028..7edc617f0f 100644 --- a/x/gov/spec/03_messages.md +++ b/x/gov/spec/03_messages.md @@ -9,7 +9,7 @@ order: 3 Proposals can be submitted by any account via a `MsgSubmitProposal` transaction. -+++ https://github.com/cosmos/cosmos-sdk/blob/ab9545527d630fe38761aa61cc5c95eabd68e0e6/proto/cosmos/gov/v1beta2/tx.proto#L34-L44 ++++ https://github.com/cosmos/cosmos-sdk/blob/5bde3686c4538ce53356af6e9fe40b34e4ce4a06/proto/cosmos/gov/v1/tx.proto#L33-L43 All `sdk.Msgs` passed into the `messages` field of a `MsgSubmitProposal` message must be registered in the app's `MsgServiceRouter`. Each of these messages must diff --git a/x/gov/spec/07_client.md b/x/gov/spec/07_client.md index 900a6f690a..0532ad907c 100644 --- a/x/gov/spec/07_client.md +++ b/x/gov/spec/07_client.md @@ -392,10 +392,10 @@ Example: simd tx gov submit-legacy-proposal --title="Test Proposal" --description="testing" --type="Text" --deposit="100000000stake" --from cosmos1.. ``` -Example (`legacy-cancel-software-upgrade`): +Example (`cancel-software-upgrade`): ```bash -simd tx gov submit-legacy-proposal legacy-cancel-software-upgrade --title="Test Proposal" --description="testing" --deposit="100000000stake" --from cosmos1.. +simd tx gov submit-legacy-proposal cancel-software-upgrade --title="Test Proposal" --description="testing" --deposit="100000000stake" --from cosmos1.. ``` Example (`community-pool-spend`): @@ -435,10 +435,10 @@ simd tx gov submit-legacy-proposal param-change proposal.json --from cosmos1.. } ``` -Example (`legacy-software-upgrade`): +Example (`software-upgrade`): ```bash -simd tx gov submit-legacy-proposal legacy-software-upgrade v2 --title="Test Proposal" --description="testing, testing, 1, 2, 3" --upgrade-height 1000000 --from cosmos1.. +simd tx gov submit-legacy-proposal software-upgrade v2 --title="Test Proposal" --description="testing, testing, 1, 2, 3" --upgrade-height 1000000 --from cosmos1.. ``` #### vote diff --git a/x/gov/types/v1/genesis.go b/x/gov/types/v1/genesis.go index b05c582f59..0e661b4a20 100644 --- a/x/gov/types/v1/genesis.go +++ b/x/gov/types/v1/genesis.go @@ -38,7 +38,7 @@ func (data GenesisState) Empty() bool { // ValidateGenesis checks if parameters are within valid ranges func ValidateGenesis(data *GenesisState) error { if data.StartingProposalId == 0 { - return errors.New("Starting proposal id must be greater than 0") + return errors.New("starting proposal id must be greater than 0") } if err := validateTallyParams(*data.TallyParams); err != nil { diff --git a/x/gov/types/v1/genesis_test.go b/x/gov/types/v1/genesis_test.go index e54c2ea5c6..eced377955 100644 --- a/x/gov/types/v1/genesis_test.go +++ b/x/gov/types/v1/genesis_test.go @@ -3,7 +3,7 @@ package v1_test import ( "testing" - "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" "github.com/stretchr/testify/require" ) @@ -14,3 +14,73 @@ func TestEmptyGenesis(t *testing.T) { state2 := v1.DefaultGenesisState() require.False(t, state2.Empty()) } + +func TestValidateGenesis(t *testing.T) { + depositParams := v1.DefaultDepositParams() + votingParams := v1.DefaultVotingParams() + tallyParams := v1.DefaultTallyParams() + + testCases := []struct { + name string + genesisState *v1.GenesisState + expErr bool + }{ + { + name: "valid", + genesisState: v1.DefaultGenesisState(), + }, + { + name: "invalid StartingProposalId", + genesisState: &v1.GenesisState{ + StartingProposalId: 0, + DepositParams: &depositParams, + VotingParams: &votingParams, + TallyParams: &tallyParams, + }, + expErr: true, + }, + { + name: "invalid TallyParams", + genesisState: &v1.GenesisState{ + StartingProposalId: v1.DefaultStartingProposalID, + DepositParams: &depositParams, + VotingParams: &votingParams, + TallyParams: &v1.TallyParams{}, + }, + expErr: true, + }, + { + name: "invalid VotingParams", + genesisState: &v1.GenesisState{ + StartingProposalId: v1.DefaultStartingProposalID, + DepositParams: &depositParams, + VotingParams: &v1.VotingParams{}, + TallyParams: &tallyParams, + }, + expErr: true, + }, + { + name: "invalid DepositParams", + genesisState: &v1.GenesisState{ + StartingProposalId: v1.DefaultStartingProposalID, + DepositParams: &v1.DepositParams{}, + VotingParams: &votingParams, + TallyParams: &tallyParams, + }, + expErr: true, + }, + } + + for _, tc := range testCases { + tc := tc + t.Run(tc.name, func(t *testing.T) { + + err := v1.ValidateGenesis(tc.genesisState) + if tc.expErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/x/upgrade/client/cli/tx.go b/x/upgrade/client/cli/tx.go index b4ad5e3668..fd672974d7 100644 --- a/x/upgrade/client/cli/tx.go +++ b/x/upgrade/client/cli/tx.go @@ -38,7 +38,7 @@ func GetTxCmd() *cobra.Command { // Deprecated: please use NewCmdSubmitUpgradeProposal instead. func NewCmdSubmitLegacyUpgradeProposal() *cobra.Command { cmd := &cobra.Command{ - Use: "legacy-software-upgrade [name] (--upgrade-height [height]) (--upgrade-info [info]) [flags]", + Use: "software-upgrade [name] (--upgrade-height [height]) (--upgrade-info [info]) [flags]", Args: cobra.ExactArgs(1), Short: "Submit a software upgrade proposal", Long: "Submit a software upgrade along with an initial deposit.\n" + @@ -108,7 +108,7 @@ func NewCmdSubmitLegacyUpgradeProposal() *cobra.Command { // Deprecated: please use NewCmdSubmitCancelUpgradeProposal instead. func NewCmdSubmitLegacyCancelUpgradeProposal() *cobra.Command { cmd := &cobra.Command{ - Use: "legacy-cancel-software-upgrade [flags]", + Use: "cancel-software-upgrade [flags]", Args: cobra.ExactArgs(0), Short: "Cancel the current software upgrade proposal", Long: "Cancel a software upgrade along with an initial deposit.",