diff --git a/x/gov/keeper/grpc_query_test.go b/x/gov/keeper/grpc_query_test.go index 0c27b32e6e..14b4286eeb 100644 --- a/x/gov/keeper/grpc_query_test.go +++ b/x/gov/keeper/grpc_query_test.go @@ -312,6 +312,51 @@ func (suite *KeeperTestSuite) TestGRPCQueryProposals() { } } +func (suite *KeeperTestSuite) TestLegacyGRPCQueryProposals() { + app, ctx, queryClient := suite.app, suite.ctx, suite.legacyQueryClient + + var ( + req *v1beta1.QueryProposalsRequest + ) + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "valid request", + func() { + req = &v1beta1.QueryProposalsRequest{} + testProposal := v1beta1.NewTextProposal("Proposal", "testing proposal") + msgContent, err := v1.NewLegacyContent(testProposal, govAcct.String()) + suite.Require().NoError(err) + submittedProposal, err := app.GovKeeper.SubmitProposal(ctx, []sdk.Msg{msgContent}, "") + suite.Require().NoError(err) + suite.Require().NotEmpty(submittedProposal) + }, + true, + }, + } + + for _, testCase := range testCases { + suite.Run(fmt.Sprintf("Case %s", testCase.msg), func() { + testCase.malleate() + + proposalRes, err := queryClient.Proposals(gocontext.Background(), req) + + if testCase.expPass { + suite.Require().NoError(err) + suite.Require().NotNil(proposalRes.Proposals) + suite.Require().Equal(len(proposalRes.Proposals), 1) + } else { + suite.Require().Error(err) + suite.Require().Nil(proposalRes) + } + }) + } +} + func (suite *KeeperTestSuite) TestGRPCQueryVote() { app, ctx, queryClient, addrs := suite.app, suite.ctx, suite.queryClient, suite.addrs @@ -426,6 +471,120 @@ func (suite *KeeperTestSuite) TestGRPCQueryVote() { } } +func (suite *KeeperTestSuite) TestLegacyGRPCQueryVote() { + app, ctx, queryClient, addrs := suite.app, suite.ctx, suite.legacyQueryClient, suite.addrs + + var ( + req *v1beta1.QueryVoteRequest + expRes *v1beta1.QueryVoteResponse + proposal v1.Proposal + ) + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "empty request", + func() { + req = &v1beta1.QueryVoteRequest{} + }, + false, + }, + { + "zero proposal id request", + func() { + req = &v1beta1.QueryVoteRequest{ + ProposalId: 0, + Voter: addrs[0].String(), + } + }, + false, + }, + { + "empty voter request", + func() { + req = &v1beta1.QueryVoteRequest{ + ProposalId: 1, + Voter: "", + } + }, + false, + }, + { + "non existed proposal", + func() { + req = &v1beta1.QueryVoteRequest{ + ProposalId: 3, + Voter: addrs[0].String(), + } + }, + false, + }, + { + "no votes present", + func() { + var err error + proposal, err = app.GovKeeper.SubmitProposal(ctx, TestProposal, "") + suite.Require().NoError(err) + + req = &v1beta1.QueryVoteRequest{ + ProposalId: proposal.Id, + Voter: addrs[0].String(), + } + + expRes = &v1beta1.QueryVoteResponse{} + }, + false, + }, + { + "valid request", + func() { + proposal.Status = v1.StatusVotingPeriod + app.GovKeeper.SetProposal(ctx, proposal) + suite.Require().NoError(app.GovKeeper.AddVote(ctx, proposal.Id, addrs[0], v1.NewNonSplitVoteOption(v1.OptionAbstain), "")) + + req = &v1beta1.QueryVoteRequest{ + ProposalId: proposal.Id, + Voter: addrs[0].String(), + } + + expRes = &v1beta1.QueryVoteResponse{Vote: v1beta1.Vote{ProposalId: proposal.Id, Voter: addrs[0].String(), Options: []v1beta1.WeightedVoteOption{{Option: v1beta1.OptionAbstain, Weight: sdk.MustNewDecFromStr("1.0")}}}} + }, + true, + }, + { + "wrong voter id request", + func() { + req = &v1beta1.QueryVoteRequest{ + ProposalId: proposal.Id, + Voter: addrs[1].String(), + } + + expRes = &v1beta1.QueryVoteResponse{} + }, + false, + }, + } + + for _, testCase := range testCases { + suite.Run(fmt.Sprintf("Case %s", testCase.msg), func() { + testCase.malleate() + + vote, err := queryClient.Vote(gocontext.Background(), req) + + if testCase.expPass { + suite.Require().NoError(err) + suite.Require().Equal(expRes, vote) + } else { + suite.Require().Error(err) + suite.Require().Nil(vote) + } + }) + } +} + func (suite *KeeperTestSuite) TestGRPCQueryVotes() { app, ctx, queryClient := suite.app, suite.ctx, suite.queryClient @@ -901,6 +1060,108 @@ func (suite *KeeperTestSuite) TestGRPCQueryDeposit() { } } +func (suite *KeeperTestSuite) TestLegacyGRPCQueryDeposit() { + app, ctx, queryClient, addrs := suite.app, suite.ctx, suite.legacyQueryClient, suite.addrs + + var ( + req *v1beta1.QueryDepositRequest + expRes *v1beta1.QueryDepositResponse + proposal v1.Proposal + ) + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "empty request", + func() { + req = &v1beta1.QueryDepositRequest{} + }, + false, + }, + { + "zero proposal id request", + func() { + req = &v1beta1.QueryDepositRequest{ + ProposalId: 0, + Depositor: addrs[0].String(), + } + }, + false, + }, + { + "empty deposit address request", + func() { + req = &v1beta1.QueryDepositRequest{ + ProposalId: 1, + Depositor: "", + } + }, + false, + }, + { + "non existed proposal", + func() { + req = &v1beta1.QueryDepositRequest{ + ProposalId: 2, + Depositor: addrs[0].String(), + } + }, + false, + }, + { + "no deposits proposal", + func() { + var err error + proposal, err = app.GovKeeper.SubmitProposal(ctx, TestProposal, "") + suite.Require().NoError(err) + suite.Require().NotNil(proposal) + + req = &v1beta1.QueryDepositRequest{ + ProposalId: proposal.Id, + Depositor: addrs[0].String(), + } + }, + false, + }, + { + "valid request", + func() { + depositCoins := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 20))) + deposit := v1beta1.NewDeposit(proposal.Id, addrs[0], depositCoins) + v1deposit := v1.NewDeposit(proposal.Id, addrs[0], depositCoins) + app.GovKeeper.SetDeposit(ctx, v1deposit) + + req = &v1beta1.QueryDepositRequest{ + ProposalId: proposal.Id, + Depositor: addrs[0].String(), + } + + expRes = &v1beta1.QueryDepositResponse{Deposit: deposit} + }, + true, + }, + } + + for _, testCase := range testCases { + suite.Run(fmt.Sprintf("Case %s", testCase.msg), func() { + testCase.malleate() + + deposit, err := queryClient.Deposit(gocontext.Background(), req) + + if testCase.expPass { + suite.Require().NoError(err) + suite.Require().Equal(deposit.GetDeposit(), expRes.GetDeposit()) + } else { + suite.Require().Error(err) + suite.Require().Nil(expRes) + } + }) + } +} + func (suite *KeeperTestSuite) TestGRPCQueryDeposits() { app, ctx, queryClient, addrs := suite.app, suite.ctx, suite.queryClient, suite.addrs @@ -995,6 +1256,102 @@ func (suite *KeeperTestSuite) TestGRPCQueryDeposits() { } } +func (suite *KeeperTestSuite) TestLegacyGRPCQueryDeposits() { + app, ctx, queryClient, addrs := suite.app, suite.ctx, suite.legacyQueryClient, suite.addrs + + var ( + req *v1beta1.QueryDepositsRequest + expRes *v1beta1.QueryDepositsResponse + proposal v1.Proposal + ) + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "empty request", + func() { + req = &v1beta1.QueryDepositsRequest{} + }, + false, + }, + { + "zero proposal id request", + func() { + req = &v1beta1.QueryDepositsRequest{ + ProposalId: 0, + } + }, + false, + }, + { + "non existed proposal", + func() { + req = &v1beta1.QueryDepositsRequest{ + ProposalId: 2, + } + }, + true, + }, + { + "create a proposal and get deposits", + func() { + var err error + proposal, err = app.GovKeeper.SubmitProposal(ctx, TestProposal, "") + suite.Require().NoError(err) + + req = &v1beta1.QueryDepositsRequest{ + ProposalId: proposal.Id, + } + }, + true, + }, + { + "get deposits with default limit", + func() { + depositAmount1 := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 20))) + deposit1 := v1beta1.NewDeposit(proposal.Id, addrs[0], depositAmount1) + v1deposit1 := v1.NewDeposit(proposal.Id, addrs[0], depositAmount1) + app.GovKeeper.SetDeposit(ctx, v1deposit1) + + depositAmount2 := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, app.StakingKeeper.TokensFromConsensusPower(ctx, 30))) + deposit2 := v1beta1.NewDeposit(proposal.Id, addrs[1], depositAmount2) + v1deposit2 := v1.NewDeposit(proposal.Id, addrs[1], depositAmount2) + app.GovKeeper.SetDeposit(ctx, v1deposit2) + + deposits := v1beta1.Deposits{deposit1, deposit2} + + req = &v1beta1.QueryDepositsRequest{ + ProposalId: proposal.Id, + } + + expRes = &v1beta1.QueryDepositsResponse{ + Deposits: deposits, + } + }, + true, + }, + } + + for _, testCase := range testCases { + suite.Run(fmt.Sprintf("Case %s", testCase.msg), func() { + testCase.malleate() + + deposits, err := queryClient.Deposits(gocontext.Background(), req) + + if testCase.expPass { + suite.Require().NoError(err) + suite.Require().Equal(expRes.GetDeposits(), deposits.GetDeposits()) + } else { + suite.Require().Error(err) + suite.Require().Nil(deposits) + } + }) + } +} + func (suite *KeeperTestSuite) TestGRPCQueryTally() { app, ctx, queryClient := suite.app, suite.ctx, suite.queryClient @@ -1105,3 +1462,127 @@ func (suite *KeeperTestSuite) TestGRPCQueryTally() { }) } } + +func (suite *KeeperTestSuite) TestLegacyGRPCQueryTally() { + app, ctx, queryClient := suite.app, suite.ctx, suite.legacyQueryClient + + addrs, _ := createValidators(suite.T(), ctx, app, []int64{5, 5, 5}) + + var ( + req *v1beta1.QueryTallyResultRequest + expRes *v1beta1.QueryTallyResultResponse + proposal v1.Proposal + ) + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "empty request", + func() { + req = &v1beta1.QueryTallyResultRequest{} + }, + false, + }, + { + "zero proposal id request", + func() { + req = &v1beta1.QueryTallyResultRequest{ProposalId: 0} + }, + false, + }, + { + "query non existed proposal", + func() { + req = &v1beta1.QueryTallyResultRequest{ProposalId: 1} + }, + false, + }, + { + "create a proposal and get tally", + func() { + var err error + proposal, err = app.GovKeeper.SubmitProposal(ctx, TestProposal, "") + suite.Require().NoError(err) + suite.Require().NotNil(proposal) + + req = &v1beta1.QueryTallyResultRequest{ProposalId: proposal.Id} + + tallyResult := v1beta1.EmptyTallyResult() + expRes = &v1beta1.QueryTallyResultResponse{ + Tally: tallyResult, + } + }, + true, + }, + { + "request tally after few votes", + func() { + proposal.Status = v1.StatusVotingPeriod + app.GovKeeper.SetProposal(ctx, proposal) + + suite.Require().NoError(app.GovKeeper.AddVote(ctx, proposal.Id, addrs[0], v1.NewNonSplitVoteOption(v1.OptionYes), "")) + suite.Require().NoError(app.GovKeeper.AddVote(ctx, proposal.Id, addrs[1], v1.NewNonSplitVoteOption(v1.OptionYes), "")) + suite.Require().NoError(app.GovKeeper.AddVote(ctx, proposal.Id, addrs[2], v1.NewNonSplitVoteOption(v1.OptionYes), "")) + + req = &v1beta1.QueryTallyResultRequest{ProposalId: proposal.Id} + + expRes = &v1beta1.QueryTallyResultResponse{ + Tally: v1beta1.TallyResult{ + Yes: sdk.NewInt(3 * 5 * 1000000), + No: sdk.NewInt(0), + Abstain: sdk.NewInt(0), + NoWithVeto: sdk.NewInt(0), + }, + } + }, + true, + }, + { + "request final tally after status changed", + func() { + proposal.Status = v1.StatusPassed + app.GovKeeper.SetProposal(ctx, proposal) + proposal, _ = app.GovKeeper.GetProposal(ctx, proposal.Id) + + req = &v1beta1.QueryTallyResultRequest{ProposalId: proposal.Id} + + expRes = &v1beta1.QueryTallyResultResponse{ + Tally: v1TallyToV1Beta1Tally(*proposal.FinalTallyResult), + } + }, + true, + }, + } + + for _, testCase := range testCases { + suite.Run(fmt.Sprintf("Case %s", testCase.msg), func() { + testCase.malleate() + + tally, err := queryClient.TallyResult(gocontext.Background(), req) + + if testCase.expPass { + suite.Require().NoError(err) + suite.Require().Equal(expRes.String(), tally.String()) + } else { + suite.Require().Error(err) + suite.Require().Nil(tally) + } + }) + } +} + +func v1TallyToV1Beta1Tally(t v1.TallyResult) v1beta1.TallyResult { + yes, _ := sdk.NewIntFromString(t.YesCount) + no, _ := sdk.NewIntFromString(t.NoCount) + noWithVeto, _ := sdk.NewIntFromString(t.NoWithVetoCount) + abstain, _ := sdk.NewIntFromString(t.AbstainCount) + return v1beta1.TallyResult{ + Yes: yes, + No: no, + NoWithVeto: noWithVeto, + Abstain: abstain, + } +} diff --git a/x/gov/keeper/keeper_test.go b/x/gov/keeper/keeper_test.go index 2b9e09895a..95daf0797e 100644 --- a/x/gov/keeper/keeper_test.go +++ b/x/gov/keeper/keeper_test.go @@ -25,6 +25,8 @@ type KeeperTestSuite struct { queryClient v1.QueryClient legacyQueryClient v1beta1.QueryClient addrs []sdk.AccAddress + msgSrvr v1.MsgServer + legacyMsgSrvr v1beta1.MsgServer } func (suite *KeeperTestSuite) SetupTest() { @@ -50,6 +52,10 @@ func (suite *KeeperTestSuite) SetupTest() { suite.ctx = ctx suite.queryClient = queryClient suite.legacyQueryClient = legacyQueryClient + suite.msgSrvr = keeper.NewMsgServerImpl(suite.app.GovKeeper) + + govAcct := suite.app.GovKeeper.GetGovernanceAccount(suite.ctx).GetAddress() + suite.legacyMsgSrvr = keeper.NewLegacyMsgServerImpl(govAcct.String(), suite.msgSrvr) suite.addrs = simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(30000000)) } diff --git a/x/gov/keeper/msg_server_test.go b/x/gov/keeper/msg_server_test.go new file mode 100644 index 0000000000..5bdd995108 --- /dev/null +++ b/x/gov/keeper/msg_server_test.go @@ -0,0 +1,734 @@ +package keeper_test + +import ( + "strings" + + "github.com/cosmos/cosmos-sdk/testutil/testdata" + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" + "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" +) + +func (suite *KeeperTestSuite) TestSubmitProposalReq() { + govAcct := suite.app.GovKeeper.GetGovernanceAccount(suite.ctx).GetAddress() + addrs := suite.addrs + proposer := addrs[0] + + coins := sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(100))) + initialDeposit := coins + minDeposit := suite.app.GovKeeper.GetDepositParams(suite.ctx).MinDeposit + bankMsg := &banktypes.MsgSend{ + FromAddress: govAcct.String(), + ToAddress: proposer.String(), + Amount: coins, + } + + cases := map[string]struct { + preRun func() (*v1.MsgSubmitProposal, error) + expErr bool + expErrMsg string + }{ + "metadata too long": { + preRun: func() (*v1.MsgSubmitProposal, error) { + return v1.NewMsgSubmitProposal( + []sdk.Msg{bankMsg}, + initialDeposit, + proposer.String(), + strings.Repeat("1", 300), + ) + }, + expErr: true, + expErrMsg: "metadata too long", + }, + "many signers": { + preRun: func() (*v1.MsgSubmitProposal, error) { + return v1.NewMsgSubmitProposal( + []sdk.Msg{testdata.NewTestMsg(govAcct, addrs[0])}, + initialDeposit, + proposer.String(), + "", + ) + }, + expErr: true, + expErrMsg: "expected gov account as only signer for proposal message", + }, + "signer isn't gov account": { + preRun: func() (*v1.MsgSubmitProposal, error) { + return v1.NewMsgSubmitProposal( + []sdk.Msg{testdata.NewTestMsg(addrs[0])}, + initialDeposit, + proposer.String(), + "", + ) + }, + expErr: true, + expErrMsg: "expected gov account as only signer for proposal message", + }, + "invalid msg handler": { + preRun: func() (*v1.MsgSubmitProposal, error) { + return v1.NewMsgSubmitProposal( + []sdk.Msg{testdata.NewTestMsg(govAcct)}, + initialDeposit, + proposer.String(), + "", + ) + }, + expErr: true, + expErrMsg: "proposal message not recognized by router", + }, + "all good": { + preRun: func() (*v1.MsgSubmitProposal, error) { + return v1.NewMsgSubmitProposal( + []sdk.Msg{bankMsg}, + initialDeposit, + proposer.String(), + "", + ) + }, + expErr: false, + }, + "all good with min deposit": { + preRun: func() (*v1.MsgSubmitProposal, error) { + return v1.NewMsgSubmitProposal( + []sdk.Msg{bankMsg}, + minDeposit, + proposer.String(), + "", + ) + }, + expErr: false, + }, + } + + for name, tc := range cases { + suite.Run(name, func() { + msg, err := tc.preRun() + suite.Require().NoError(err) + res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) + if tc.expErr { + suite.Require().Error(err) + suite.Require().Contains(err.Error(), tc.expErrMsg) + } else { + suite.Require().NoError(err) + suite.Require().NotNil(res.ProposalId) + } + }) + } +} + +func (suite *KeeperTestSuite) TestVoteReq() { + govAcct := suite.app.GovKeeper.GetGovernanceAccount(suite.ctx).GetAddress() + addrs := suite.addrs + proposer := addrs[0] + + coins := sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(100))) + minDeposit := suite.app.GovKeeper.GetDepositParams(suite.ctx).MinDeposit + bankMsg := &banktypes.MsgSend{ + FromAddress: govAcct.String(), + ToAddress: proposer.String(), + Amount: coins, + } + + msg, err := v1.NewMsgSubmitProposal( + []sdk.Msg{bankMsg}, + minDeposit, + proposer.String(), + "", + ) + suite.Require().NoError(err) + + res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) + suite.Require().NoError(err) + suite.Require().NotNil(res.ProposalId) + proposalId := res.ProposalId + + cases := map[string]struct { + preRun func() uint64 + expErr bool + expErrMsg string + option v1.VoteOption + metadata string + voter sdk.AccAddress + }{ + "vote on inactive proposal": { + preRun: func() uint64 { + msg, err := v1.NewMsgSubmitProposal( + []sdk.Msg{bankMsg}, + coins, + proposer.String(), + "", + ) + suite.Require().NoError(err) + + res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) + suite.Require().NoError(err) + suite.Require().NotNil(res.ProposalId) + return res.ProposalId + }, + option: v1.VoteOption_VOTE_OPTION_YES, + voter: proposer, + metadata: "", + expErr: true, + expErrMsg: "inactive proposal", + }, + "metadata too long": { + preRun: func() uint64 { + return proposalId + }, + option: v1.VoteOption_VOTE_OPTION_YES, + voter: proposer, + metadata: strings.Repeat("a", 300), + expErr: true, + expErrMsg: "metadata too long", + }, + "voter error": { + preRun: func() uint64 { + return proposalId + }, + option: v1.VoteOption_VOTE_OPTION_YES, + voter: sdk.AccAddress(strings.Repeat("a", 300)), + metadata: "", + expErr: true, + expErrMsg: "address max length is 255", + }, + "all good": { + preRun: func() uint64 { + msg, err := v1.NewMsgSubmitProposal( + []sdk.Msg{bankMsg}, + minDeposit, + proposer.String(), + "", + ) + suite.Require().NoError(err) + + res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) + suite.Require().NoError(err) + suite.Require().NotNil(res.ProposalId) + return res.ProposalId + }, + option: v1.VoteOption_VOTE_OPTION_YES, + voter: proposer, + metadata: "", + expErr: false, + }, + } + + for name, tc := range cases { + suite.Run(name, func() { + pId := tc.preRun() + voteReq := v1.NewMsgVote(tc.voter, pId, tc.option, tc.metadata) + _, err := suite.msgSrvr.Vote(suite.ctx, voteReq) + if tc.expErr { + suite.Require().Error(err) + suite.Require().Contains(err.Error(), tc.expErrMsg) + } else { + suite.Require().NoError(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestVoteWeightedReq() { + govAcct := suite.app.GovKeeper.GetGovernanceAccount(suite.ctx).GetAddress() + addrs := suite.addrs + proposer := addrs[0] + + coins := sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(100))) + minDeposit := suite.app.GovKeeper.GetDepositParams(suite.ctx).MinDeposit + bankMsg := &banktypes.MsgSend{ + FromAddress: govAcct.String(), + ToAddress: proposer.String(), + Amount: coins, + } + + msg, err := v1.NewMsgSubmitProposal( + []sdk.Msg{bankMsg}, + minDeposit, + proposer.String(), + "", + ) + suite.Require().NoError(err) + + res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) + suite.Require().NoError(err) + suite.Require().NotNil(res.ProposalId) + proposalId := res.ProposalId + + cases := map[string]struct { + preRun func() uint64 + vote *v1.MsgVote + expErr bool + expErrMsg string + option v1.VoteOption + metadata string + voter sdk.AccAddress + }{ + "vote on inactive proposal": { + preRun: func() uint64 { + msg, err := v1.NewMsgSubmitProposal( + []sdk.Msg{bankMsg}, + coins, + proposer.String(), + "", + ) + suite.Require().NoError(err) + + res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) + suite.Require().NoError(err) + suite.Require().NotNil(res.ProposalId) + return res.ProposalId + }, + option: v1.VoteOption_VOTE_OPTION_YES, + voter: proposer, + metadata: "", + expErr: true, + expErrMsg: "inactive proposal", + }, + "metadata too long": { + preRun: func() uint64 { + return proposalId + }, + option: v1.VoteOption_VOTE_OPTION_YES, + voter: proposer, + metadata: strings.Repeat("a", 300), + expErr: true, + expErrMsg: "metadata too long", + }, + "voter error": { + preRun: func() uint64 { + return proposalId + }, + option: v1.VoteOption_VOTE_OPTION_YES, + voter: sdk.AccAddress(strings.Repeat("a", 300)), + metadata: "", + expErr: true, + expErrMsg: "address max length is 255", + }, + "all good": { + preRun: func() uint64 { + msg, err := v1.NewMsgSubmitProposal( + []sdk.Msg{bankMsg}, + minDeposit, + proposer.String(), + "", + ) + suite.Require().NoError(err) + + res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) + suite.Require().NoError(err) + suite.Require().NotNil(res.ProposalId) + return res.ProposalId + }, + option: v1.VoteOption_VOTE_OPTION_YES, + voter: proposer, + metadata: "", + expErr: false, + }, + } + + for name, tc := range cases { + suite.Run(name, func() { + pId := tc.preRun() + voteReq := v1.NewMsgVoteWeighted(tc.voter, pId, v1.NewNonSplitVoteOption(tc.option), tc.metadata) + _, err := suite.msgSrvr.VoteWeighted(suite.ctx, voteReq) + if tc.expErr { + suite.Require().Error(err) + suite.Require().Contains(err.Error(), tc.expErrMsg) + } else { + suite.Require().NoError(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestDepositReq() { + govAcct := suite.app.GovKeeper.GetGovernanceAccount(suite.ctx).GetAddress() + addrs := suite.addrs + proposer := addrs[0] + + coins := sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(100))) + minDeposit := suite.app.GovKeeper.GetDepositParams(suite.ctx).MinDeposit + bankMsg := &banktypes.MsgSend{ + FromAddress: govAcct.String(), + ToAddress: proposer.String(), + Amount: coins, + } + + msg, err := v1.NewMsgSubmitProposal( + []sdk.Msg{bankMsg}, + coins, + proposer.String(), + "", + ) + suite.Require().NoError(err) + + res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) + suite.Require().NoError(err) + suite.Require().NotNil(res.ProposalId) + pId := res.ProposalId + + cases := map[string]struct { + preRun func() uint64 + expErr bool + proposalId uint64 + depositor sdk.AccAddress + deposit sdk.Coins + options v1.WeightedVoteOptions + }{ + "wrong proposal id": { + preRun: func() uint64 { + return 0 + }, + depositor: proposer, + deposit: coins, + expErr: true, + options: v1.NewNonSplitVoteOption(v1.OptionYes), + }, + "all good": { + preRun: func() uint64 { + return pId + }, + depositor: proposer, + deposit: minDeposit, + expErr: false, + options: v1.NewNonSplitVoteOption(v1.OptionYes), + }, + } + + for name, tc := range cases { + suite.Run(name, func() { + proposalId := tc.preRun() + depositReq := v1.NewMsgDeposit(tc.depositor, proposalId, tc.deposit) + _, err := suite.msgSrvr.Deposit(suite.ctx, depositReq) + if tc.expErr { + suite.Require().Error(err) + } else { + suite.Require().NoError(err) + } + }) + } +} + +// legacy msg server tests +func (suite *KeeperTestSuite) TestLegacyMsgSubmitProposal() { + addrs := suite.addrs + proposer := addrs[0] + + coins := sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(100))) + initialDeposit := coins + minDeposit := suite.app.GovKeeper.GetDepositParams(suite.ctx).MinDeposit + + cases := map[string]struct { + preRun func() (*v1beta1.MsgSubmitProposal, error) + expErr bool + }{ + "all good": { + preRun: func() (*v1beta1.MsgSubmitProposal, error) { + return v1beta1.NewMsgSubmitProposal( + v1beta1.NewTextProposal("test", "I am test"), + initialDeposit, + proposer, + ) + }, + expErr: false, + }, + "all good with min deposit": { + preRun: func() (*v1beta1.MsgSubmitProposal, error) { + return v1beta1.NewMsgSubmitProposal( + v1beta1.NewTextProposal("test", "I am test"), + minDeposit, + proposer, + ) + }, + expErr: false, + }, + } + + for name, c := range cases { + suite.Run(name, func() { + msg, err := c.preRun() + suite.Require().NoError(err) + res, err := suite.legacyMsgSrvr.SubmitProposal(suite.ctx, msg) + if c.expErr { + suite.Require().Error(err) + } else { + suite.Require().NoError(err) + suite.Require().NotNil(res.ProposalId) + } + }) + } +} + +func (suite *KeeperTestSuite) TestLegacyMsgVote() { + govAcct := suite.app.GovKeeper.GetGovernanceAccount(suite.ctx).GetAddress() + addrs := suite.addrs + proposer := addrs[0] + + coins := sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(100))) + minDeposit := suite.app.GovKeeper.GetDepositParams(suite.ctx).MinDeposit + bankMsg := &banktypes.MsgSend{ + FromAddress: govAcct.String(), + ToAddress: proposer.String(), + Amount: coins, + } + + msg, err := v1.NewMsgSubmitProposal( + []sdk.Msg{bankMsg}, + minDeposit, + proposer.String(), + "", + ) + suite.Require().NoError(err) + + res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) + suite.Require().NoError(err) + suite.Require().NotNil(res.ProposalId) + proposalId := res.ProposalId + + cases := map[string]struct { + preRun func() uint64 + expErr bool + expErrMsg string + option v1beta1.VoteOption + metadata string + voter sdk.AccAddress + }{ + "vote on inactive proposal": { + preRun: func() uint64 { + msg, err := v1.NewMsgSubmitProposal( + []sdk.Msg{bankMsg}, + coins, + proposer.String(), + "", + ) + suite.Require().NoError(err) + + res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) + suite.Require().NoError(err) + suite.Require().NotNil(res.ProposalId) + return res.ProposalId + }, + option: v1beta1.OptionYes, + voter: proposer, + metadata: "", + expErr: true, + expErrMsg: "inactive proposal", + }, + "voter error": { + preRun: func() uint64 { + return proposalId + }, + option: v1beta1.OptionYes, + voter: sdk.AccAddress(strings.Repeat("a", 300)), + metadata: "", + expErr: true, + expErrMsg: "address max length is 255", + }, + "all good": { + preRun: func() uint64 { + msg, err := v1.NewMsgSubmitProposal( + []sdk.Msg{bankMsg}, + minDeposit, + proposer.String(), + "", + ) + suite.Require().NoError(err) + + res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) + suite.Require().NoError(err) + suite.Require().NotNil(res.ProposalId) + return res.ProposalId + }, + option: v1beta1.OptionYes, + voter: proposer, + metadata: "", + expErr: false, + }, + } + + for name, tc := range cases { + suite.Run(name, func() { + pId := tc.preRun() + voteReq := v1beta1.NewMsgVote(tc.voter, pId, tc.option) + _, err := suite.legacyMsgSrvr.Vote(suite.ctx, voteReq) + if tc.expErr { + suite.Require().Error(err) + suite.Require().Contains(err.Error(), tc.expErrMsg) + } else { + suite.Require().NoError(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestLegacyVoteWeighted() { + govAcct := suite.app.GovKeeper.GetGovernanceAccount(suite.ctx).GetAddress() + addrs := suite.addrs + proposer := addrs[0] + + coins := sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(100))) + minDeposit := suite.app.GovKeeper.GetDepositParams(suite.ctx).MinDeposit + bankMsg := &banktypes.MsgSend{ + FromAddress: govAcct.String(), + ToAddress: proposer.String(), + Amount: coins, + } + + msg, err := v1.NewMsgSubmitProposal( + []sdk.Msg{bankMsg}, + minDeposit, + proposer.String(), + "", + ) + suite.Require().NoError(err) + + res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) + suite.Require().NoError(err) + suite.Require().NotNil(res.ProposalId) + proposalId := res.ProposalId + + cases := map[string]struct { + preRun func() uint64 + vote *v1beta1.MsgVote + expErr bool + expErrMsg string + option v1beta1.VoteOption + metadata string + voter sdk.AccAddress + }{ + "vote on inactive proposal": { + preRun: func() uint64 { + msg, err := v1.NewMsgSubmitProposal( + []sdk.Msg{bankMsg}, + coins, + proposer.String(), + "", + ) + suite.Require().NoError(err) + + res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) + suite.Require().NoError(err) + suite.Require().NotNil(res.ProposalId) + return res.ProposalId + }, + option: v1beta1.OptionYes, + voter: proposer, + metadata: "", + expErr: true, + expErrMsg: "inactive proposal", + }, + "voter error": { + preRun: func() uint64 { + return proposalId + }, + option: v1beta1.OptionYes, + voter: sdk.AccAddress(strings.Repeat("a", 300)), + metadata: "", + expErr: true, + expErrMsg: "address max length is 255", + }, + "all good": { + preRun: func() uint64 { + msg, err := v1.NewMsgSubmitProposal( + []sdk.Msg{bankMsg}, + minDeposit, + proposer.String(), + "", + ) + suite.Require().NoError(err) + + res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) + suite.Require().NoError(err) + suite.Require().NotNil(res.ProposalId) + return res.ProposalId + }, + option: v1beta1.OptionYes, + voter: proposer, + metadata: "", + expErr: false, + }, + } + + for name, tc := range cases { + suite.Run(name, func() { + pId := tc.preRun() + voteReq := v1beta1.NewMsgVoteWeighted(tc.voter, pId, v1beta1.NewNonSplitVoteOption(v1beta1.VoteOption(tc.option))) + _, err := suite.legacyMsgSrvr.VoteWeighted(suite.ctx, voteReq) + if tc.expErr { + suite.Require().Error(err) + suite.Require().Contains(err.Error(), tc.expErrMsg) + } else { + suite.Require().NoError(err) + } + }) + } +} + +func (suite *KeeperTestSuite) TestLegacyMsgDeposit() { + govAcct := suite.app.GovKeeper.GetGovernanceAccount(suite.ctx).GetAddress() + addrs := suite.addrs + proposer := addrs[0] + + coins := sdk.NewCoins(sdk.NewCoin("stake", sdk.NewInt(100))) + minDeposit := suite.app.GovKeeper.GetDepositParams(suite.ctx).MinDeposit + bankMsg := &banktypes.MsgSend{ + FromAddress: govAcct.String(), + ToAddress: proposer.String(), + Amount: coins, + } + + msg, err := v1.NewMsgSubmitProposal( + []sdk.Msg{bankMsg}, + coins, + proposer.String(), + "", + ) + suite.Require().NoError(err) + + res, err := suite.msgSrvr.SubmitProposal(suite.ctx, msg) + suite.Require().NoError(err) + suite.Require().NotNil(res.ProposalId) + pId := res.ProposalId + + cases := map[string]struct { + preRun func() uint64 + expErr bool + proposalId uint64 + depositor sdk.AccAddress + deposit sdk.Coins + options v1beta1.WeightedVoteOptions + }{ + "wrong proposal id": { + preRun: func() uint64 { + return 0 + }, + depositor: proposer, + deposit: coins, + expErr: true, + options: v1beta1.NewNonSplitVoteOption(v1beta1.OptionYes), + }, + "all good": { + preRun: func() uint64 { + return pId + }, + depositor: proposer, + deposit: minDeposit, + expErr: false, + options: v1beta1.NewNonSplitVoteOption(v1beta1.OptionYes), + }, + } + + for name, tc := range cases { + suite.Run(name, func() { + proposalId := tc.preRun() + depositReq := v1beta1.NewMsgDeposit(tc.depositor, proposalId, tc.deposit) + _, err := suite.legacyMsgSrvr.Deposit(suite.ctx, depositReq) + if tc.expErr { + suite.Require().Error(err) + } else { + suite.Require().NoError(err) + } + }) + } +} diff --git a/x/gov/keeper/querier.go b/x/gov/keeper/querier.go index b83dc169d9..14e8bc83b2 100644 --- a/x/gov/keeper/querier.go +++ b/x/gov/keeper/querier.go @@ -1,5 +1,7 @@ package keeper +// DONTCOVER + import ( abci "github.com/tendermint/tendermint/abci/types"