From c50478448919bcaafa256c9adad1c1e76afa0103 Mon Sep 17 00:00:00 2001 From: antstalepresh Date: Wed, 28 Oct 2020 22:05:35 +1000 Subject: [PATCH] Fix build errors and tests after struct modification --- x/gov/abci_test.go | 4 +- x/gov/client/cli/cli_test.go | 3 +- x/gov/client/cli/tx.go | 2 +- x/gov/client/rest/grpc_query_test.go | 3 +- x/gov/client/rest/tx.go | 2 +- x/gov/client/utils/query_test.go | 22 ++++---- x/gov/keeper/grpc_query_test.go | 20 ++++---- x/gov/keeper/proposal_test.go | 2 +- x/gov/keeper/querier_test.go | 8 +-- x/gov/keeper/tally.go | 32 +++++++++--- x/gov/keeper/tally_test.go | 77 ++++++++++++++-------------- x/gov/keeper/vote.go | 10 ++-- x/gov/keeper/vote_test.go | 27 ++++++---- x/gov/legacy/v040/migrate.go | 2 +- x/gov/simulation/decoder_test.go | 2 +- x/gov/simulation/operations.go | 2 +- x/gov/simulation/operations_test.go | 3 +- x/gov/types/events.go | 1 + x/gov/types/msgs_test.go | 2 +- x/gov/types/tally.go | 6 +-- x/gov/types/vote.go | 8 +++ 21 files changed, 137 insertions(+), 101 deletions(-) diff --git a/x/gov/abci_test.go b/x/gov/abci_test.go index bfda1b3590..30a3afe3bc 100644 --- a/x/gov/abci_test.go +++ b/x/gov/abci_test.go @@ -307,7 +307,7 @@ func TestProposalPassedEndblocker(t *testing.T) { deposits := initialModuleAccCoins.Add(proposal.TotalDeposit...).Add(proposalCoins...) require.True(t, moduleAccCoins.IsEqual(deposits)) - err = app.GovKeeper.AddVote(ctx, proposal.ProposalId, addrs[0], types.OptionYes) + err = app.GovKeeper.AddVote(ctx, proposal.ProposalId, addrs[0], types.SubVotes{types.NewSubVote(types.OptionYes, 1)}) require.NoError(t, err) newHeader := ctx.BlockHeader() @@ -348,7 +348,7 @@ func TestEndBlockerProposalHandlerFailed(t *testing.T) { handleAndCheck(t, gov.NewHandler(app.GovKeeper), ctx, newDepositMsg) - err = app.GovKeeper.AddVote(ctx, proposal.ProposalId, addrs[0], types.OptionYes) + err = app.GovKeeper.AddVote(ctx, proposal.ProposalId, addrs[0], types.SubVotes{types.NewSubVote(types.OptionYes, 1)}) require.NoError(t, err) newHeader := ctx.BlockHeader() diff --git a/x/gov/client/cli/cli_test.go b/x/gov/client/cli/cli_test.go index c1367eabe0..ec2ebfd92c 100644 --- a/x/gov/client/cli/cli_test.go +++ b/x/gov/client/cli/cli_test.go @@ -735,7 +735,8 @@ func (s *IntegrationTestSuite) TestCmdQueryVote() { var vote types.Vote s.Require().NoError(clientCtx.JSONMarshaler.UnmarshalJSON(out.Bytes(), &vote), out.String()) - s.Require().Equal(types.OptionYes, vote.Option) + s.Require().True(len(vote.SubVotes) == 1) + s.Require().Equal(types.OptionYes, vote.SubVotes[0].Option) } }) } diff --git a/x/gov/client/cli/tx.go b/x/gov/client/cli/tx.go index 5f04d9184c..bda8cf9e6f 100644 --- a/x/gov/client/cli/tx.go +++ b/x/gov/client/cli/tx.go @@ -237,7 +237,7 @@ $ %s tx gov vote 1 yes --from mykey } // Build vote message and run basic validation - msg := types.NewMsgVote(from, proposalID, byteVoteOption) + msg := types.NewMsgVote(from, proposalID, types.SubVotes{types.NewSubVote(byteVoteOption, 1)}) err = msg.ValidateBasic() if err != nil { return err diff --git a/x/gov/client/rest/grpc_query_test.go b/x/gov/client/rest/grpc_query_test.go index 23a282d5d3..b9a4c76402 100644 --- a/x/gov/client/rest/grpc_query_test.go +++ b/x/gov/client/rest/grpc_query_test.go @@ -193,7 +193,8 @@ func (s *IntegrationTestSuite) TestGetProposalVoteGRPC() { } else { s.Require().NoError(err) s.Require().NotEmpty(vote.Vote) - s.Require().Equal(types.OptionYes, vote.Vote.Option) + s.Require().True(len(vote.Vote.SubVotes) == 1) + s.Require().Equal(types.OptionYes, vote.Vote.SubVotes[0].Option) } }) } diff --git a/x/gov/client/rest/tx.go b/x/gov/client/rest/tx.go index 4f010f27b7..e427fbf7a7 100644 --- a/x/gov/client/rest/tx.go +++ b/x/gov/client/rest/tx.go @@ -117,7 +117,7 @@ func newVoteHandlerFn(clientCtx client.Context) http.HandlerFunc { } // create the message - msg := types.NewMsgVote(req.Voter, proposalID, []types.SubVote{types.NewSubVote(voteOption, 1)}) + msg := types.NewMsgVote(req.Voter, proposalID, types.SubVotes{types.NewSubVote(voteOption, 1)}) if rest.CheckBadRequestError(w, msg.ValidateBasic()) { return } diff --git a/x/gov/client/utils/query_test.go b/x/gov/client/utils/query_test.go index c6f999e86e..8f792ff1a2 100644 --- a/x/gov/client/utils/query_test.go +++ b/x/gov/client/utils/query_test.go @@ -70,12 +70,12 @@ func TestGetPaginatedVotes(t *testing.T) { acc2 := make(sdk.AccAddress, 20) acc2[0] = 2 acc1Msgs := []sdk.Msg{ - types.NewMsgVote(acc1, 0, types.OptionYes), - types.NewMsgVote(acc1, 0, types.OptionYes), + types.NewMsgVote(acc1, 0, types.SubVotes{types.NewSubVote(types.OptionYes, 1)}), + types.NewMsgVote(acc1, 0, types.SubVotes{types.NewSubVote(types.OptionYes, 1)}), } acc2Msgs := []sdk.Msg{ - types.NewMsgVote(acc2, 0, types.OptionYes), - types.NewMsgVote(acc2, 0, types.OptionYes), + types.NewMsgVote(acc2, 0, types.SubVotes{types.NewSubVote(types.OptionYes, 1)}), + types.NewMsgVote(acc2, 0, types.SubVotes{types.NewSubVote(types.OptionYes, 1)}), } for _, tc := range []testCase{ { @@ -87,8 +87,8 @@ func TestGetPaginatedVotes(t *testing.T) { acc2Msgs[:1], }, votes: []types.Vote{ - types.NewVote(0, acc1, types.OptionYes), - types.NewVote(0, acc2, types.OptionYes)}, + types.NewVote(0, acc1, types.SubVotes{types.NewSubVote(types.OptionYes, 1)}), + types.NewVote(0, acc2, types.SubVotes{types.NewSubVote(types.OptionYes, 1)})}, }, { description: "2MsgPerTx1Chunk", @@ -99,8 +99,8 @@ func TestGetPaginatedVotes(t *testing.T) { acc2Msgs, }, votes: []types.Vote{ - types.NewVote(0, acc1, types.OptionYes), - types.NewVote(0, acc1, types.OptionYes)}, + types.NewVote(0, acc1, types.SubVotes{types.NewSubVote(types.OptionYes, 1)}), + types.NewVote(0, acc1, types.SubVotes{types.NewSubVote(types.OptionYes, 1)})}, }, { description: "2MsgPerTx2Chunk", @@ -111,8 +111,8 @@ func TestGetPaginatedVotes(t *testing.T) { acc2Msgs, }, votes: []types.Vote{ - types.NewVote(0, acc2, types.OptionYes), - types.NewVote(0, acc2, types.OptionYes)}, + types.NewVote(0, acc2, types.SubVotes{types.NewSubVote(types.OptionYes, 1)}), + types.NewVote(0, acc2, types.SubVotes{types.NewSubVote(types.OptionYes, 1)})}, }, { description: "IncompleteSearchTx", @@ -121,7 +121,7 @@ func TestGetPaginatedVotes(t *testing.T) { msgs: [][]sdk.Msg{ acc1Msgs[:1], }, - votes: []types.Vote{types.NewVote(0, acc1, types.OptionYes)}, + votes: []types.Vote{types.NewVote(0, acc1, types.SubVotes{types.NewSubVote(types.OptionYes, 1)})}, }, { description: "InvalidPage", diff --git a/x/gov/keeper/grpc_query_test.go b/x/gov/keeper/grpc_query_test.go index dc330d7348..a170c0c0e0 100644 --- a/x/gov/keeper/grpc_query_test.go +++ b/x/gov/keeper/grpc_query_test.go @@ -183,7 +183,7 @@ func (suite *KeeperTestSuite) TestGRPCQueryProposals() { func() { testProposals[1].Status = types.StatusVotingPeriod app.GovKeeper.SetProposal(ctx, testProposals[1]) - suite.Require().NoError(app.GovKeeper.AddVote(ctx, testProposals[1].ProposalId, addrs[0], types.OptionAbstain)) + suite.Require().NoError(app.GovKeeper.AddVote(ctx, testProposals[1].ProposalId, addrs[0], types.SubVotes{types.NewSubVote(types.OptionAbstain, 1)})) req = &types.QueryProposalsRequest{ Voter: addrs[0].String(), @@ -291,14 +291,14 @@ func (suite *KeeperTestSuite) TestGRPCQueryVote() { func() { proposal.Status = types.StatusVotingPeriod app.GovKeeper.SetProposal(ctx, proposal) - suite.Require().NoError(app.GovKeeper.AddVote(ctx, proposal.ProposalId, addrs[0], types.OptionAbstain)) + suite.Require().NoError(app.GovKeeper.AddVote(ctx, proposal.ProposalId, addrs[0], types.SubVotes{types.NewSubVote(types.OptionAbstain, 1)})) req = &types.QueryVoteRequest{ ProposalId: proposal.ProposalId, Voter: addrs[0].String(), } - expRes = &types.QueryVoteResponse{Vote: types.NewVote(proposal.ProposalId, addrs[0], types.OptionAbstain)} + expRes = &types.QueryVoteResponse{Vote: types.NewVote(proposal.ProposalId, addrs[0], types.SubVotes{types.NewSubVote(types.OptionAbstain, 1)})} }, true, }, @@ -395,15 +395,15 @@ func (suite *KeeperTestSuite) TestGRPCQueryVotes() { app.GovKeeper.SetProposal(ctx, proposal) votes = []types.Vote{ - {proposal.ProposalId, addrs[0].String(), types.OptionAbstain}, - {proposal.ProposalId, addrs[1].String(), types.OptionYes}, + {proposal.ProposalId, addrs[0].String(), types.SubVotes{types.NewSubVote(types.OptionAbstain, 1)}}, + {proposal.ProposalId, addrs[1].String(), types.SubVotes{types.NewSubVote(types.OptionYes, 1)}}, } accAddr1, err1 := sdk.AccAddressFromBech32(votes[0].Voter) accAddr2, err2 := sdk.AccAddressFromBech32(votes[1].Voter) suite.Require().NoError(err1) suite.Require().NoError(err2) - suite.Require().NoError(app.GovKeeper.AddVote(ctx, proposal.ProposalId, accAddr1, votes[0].Option)) - suite.Require().NoError(app.GovKeeper.AddVote(ctx, proposal.ProposalId, accAddr2, votes[1].Option)) + suite.Require().NoError(app.GovKeeper.AddVote(ctx, proposal.ProposalId, accAddr1, votes[0].SubVotes)) + suite.Require().NoError(app.GovKeeper.AddVote(ctx, proposal.ProposalId, accAddr2, votes[1].SubVotes)) req = &types.QueryVotesRequest{ ProposalId: proposal.ProposalId, @@ -769,9 +769,9 @@ func (suite *KeeperTestSuite) TestGRPCQueryTally() { proposal.Status = types.StatusVotingPeriod app.GovKeeper.SetProposal(ctx, proposal) - suite.Require().NoError(app.GovKeeper.AddVote(ctx, proposal.ProposalId, addrs[0], types.OptionYes)) - suite.Require().NoError(app.GovKeeper.AddVote(ctx, proposal.ProposalId, addrs[1], types.OptionYes)) - suite.Require().NoError(app.GovKeeper.AddVote(ctx, proposal.ProposalId, addrs[2], types.OptionYes)) + suite.Require().NoError(app.GovKeeper.AddVote(ctx, proposal.ProposalId, addrs[0], types.SubVotes{types.NewSubVote(types.OptionYes, 1)})) + suite.Require().NoError(app.GovKeeper.AddVote(ctx, proposal.ProposalId, addrs[1], types.SubVotes{types.NewSubVote(types.OptionYes, 1)})) + suite.Require().NoError(app.GovKeeper.AddVote(ctx, proposal.ProposalId, addrs[2], types.SubVotes{types.NewSubVote(types.OptionYes, 1)})) req = &types.QueryTallyResultRequest{ProposalId: proposal.ProposalId} diff --git a/x/gov/keeper/proposal_test.go b/x/gov/keeper/proposal_test.go index 1a833737d9..c6c2d80376 100644 --- a/x/gov/keeper/proposal_test.go +++ b/x/gov/keeper/proposal_test.go @@ -101,7 +101,7 @@ func TestGetProposalsFiltered(t *testing.T) { if i%2 == 0 { d := types.NewDeposit(proposalID, addr1, nil) - v := types.NewVote(proposalID, addr1, types.OptionYes) + v := types.NewVote(proposalID, addr1, types.SubVotes{types.NewSubVote(types.OptionYes, 1)}) app.GovKeeper.SetDeposit(ctx, d) app.GovKeeper.SetVote(ctx, v) } diff --git a/x/gov/keeper/querier_test.go b/x/gov/keeper/querier_test.go index 9960fb116b..3e2345b0c7 100644 --- a/x/gov/keeper/querier_test.go +++ b/x/gov/keeper/querier_test.go @@ -251,13 +251,13 @@ func TestQueries(t *testing.T) { require.Equal(t, proposal3, proposals[1]) // Addrs[0] votes on proposals #2 & #3 - vote1 := types.NewVote(proposal2.ProposalId, TestAddrs[0], types.OptionYes) - vote2 := types.NewVote(proposal3.ProposalId, TestAddrs[0], types.OptionYes) + vote1 := types.NewVote(proposal2.ProposalId, TestAddrs[0], types.SubVotes{types.NewSubVote(types.OptionYes, 1)}) + vote2 := types.NewVote(proposal3.ProposalId, TestAddrs[0], types.SubVotes{types.NewSubVote(types.OptionYes, 1)}) app.GovKeeper.SetVote(ctx, vote1) app.GovKeeper.SetVote(ctx, vote2) // Addrs[1] votes on proposal #3 - vote3 := types.NewVote(proposal3.ProposalId, TestAddrs[1], types.OptionYes) + vote3 := types.NewVote(proposal3.ProposalId, TestAddrs[1], types.SubVotes{types.NewSubVote(types.OptionYes, 1)}) app.GovKeeper.SetVote(ctx, vote3) // Test query voted by TestAddrs[0] @@ -323,7 +323,7 @@ func TestPaginatedVotesQuery(t *testing.T) { vote := types.Vote{ ProposalId: proposal.ProposalId, Voter: addr.String(), - Option: types.OptionYes, + SubVotes: types.SubVotes{types.NewSubVote(types.OptionYes, 1)}, } votes[i] = vote app.GovKeeper.SetVote(ctx, vote) diff --git a/x/gov/keeper/tally.go b/x/gov/keeper/tally.go index 796609db5a..5e7a9923ff 100644 --- a/x/gov/keeper/tally.go +++ b/x/gov/keeper/tally.go @@ -27,7 +27,7 @@ func (keeper Keeper) Tally(ctx sdk.Context, proposal types.Proposal) (passes boo validator.GetBondedTokens(), validator.GetDelegatorShares(), sdk.ZeroDec(), - types.OptionEmpty, + types.SubVotes{}, ) return false @@ -43,7 +43,7 @@ func (keeper Keeper) Tally(ctx sdk.Context, proposal types.Proposal) (passes boo valAddrStr := sdk.ValAddress(voter.Bytes()).String() if val, ok := currValidators[valAddrStr]; ok { - val.Vote = vote.Option + val.Vote = vote.SubVotes currValidators[valAddrStr] = val } @@ -60,8 +60,17 @@ func (keeper Keeper) Tally(ctx sdk.Context, proposal types.Proposal) (passes boo delegatorShare := delegation.GetShares().Quo(val.DelegatorShares) votingPower := delegatorShare.MulInt(val.BondedTokens) - results[vote.Option] = results[vote.Option].Add(votingPower) - totalVotingPower = totalVotingPower.Add(votingPower) + totalRates := sdk.NewDec(0) + for _, subvote := range vote.SubVotes { + totalRates = totalRates.Add(subvote.Rate) + } + for _, subvote := range vote.SubVotes { + subPower := sdk.NewDecFromBigInt(votingPower.BigInt().Div(votingPower.Mul(subvote.Rate).BigInt(), totalRates.BigInt())) + results[subvote.Option] = results[subvote.Option].Add(subPower) + totalVotingPower = totalVotingPower.Add(subPower) + } + // TODO how should handle remainder? + // TODO how should handle when totalRates == 0 } return false @@ -73,7 +82,7 @@ func (keeper Keeper) Tally(ctx sdk.Context, proposal types.Proposal) (passes boo // iterate over the validators again to tally their voting power for _, val := range currValidators { - if val.Vote == types.OptionEmpty { + if len(val.Vote) == 0 { continue } @@ -81,8 +90,17 @@ func (keeper Keeper) Tally(ctx sdk.Context, proposal types.Proposal) (passes boo fractionAfterDeductions := sharesAfterDeductions.Quo(val.DelegatorShares) votingPower := fractionAfterDeductions.MulInt(val.BondedTokens) - results[val.Vote] = results[val.Vote].Add(votingPower) - totalVotingPower = totalVotingPower.Add(votingPower) + totalRates := sdk.NewDec(0) + for _, subvote := range val.Vote { + totalRates = totalRates.Add(subvote.Rate) + } + for _, subvote := range val.Vote { + subPower := sdk.NewDecFromBigInt(votingPower.BigInt().Div(votingPower.Mul(subvote.Rate).BigInt(), totalRates.BigInt())) + results[subvote.Option] = results[subvote.Option].Add(subPower) + totalVotingPower = totalVotingPower.Add(subPower) + // TODO how should handle remainder? + // TODO how should handle when totalRates == 0 + } } tallyParams := keeper.GetTallyParams(ctx) diff --git a/x/gov/keeper/tally_test.go b/x/gov/keeper/tally_test.go index 6c23a510e9..61e07a8a3e 100644 --- a/x/gov/keeper/tally_test.go +++ b/x/gov/keeper/tally_test.go @@ -50,7 +50,7 @@ func TestTallyNoQuorum(t *testing.T) { proposal.Status = types.StatusVotingPeriod app.GovKeeper.SetProposal(ctx, proposal) - err = app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.OptionYes) + err = app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.SubVotes{types.NewSubVote(types.OptionYes, 1)}) require.Nil(t, err) proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) @@ -73,9 +73,9 @@ func TestTallyOnlyValidatorsAllYes(t *testing.T) { proposal.Status = types.StatusVotingPeriod app.GovKeeper.SetProposal(ctx, proposal) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.OptionYes)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.OptionYes)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[2], types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.SubVotes{types.NewSubVote(types.OptionYes, 1)})) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.SubVotes{types.NewSubVote(types.OptionYes, 1)})) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[2], types.SubVotes{types.NewSubVote(types.OptionYes, 1)})) proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) require.True(t, ok) @@ -99,8 +99,8 @@ func TestTallyOnlyValidators51No(t *testing.T) { proposal.Status = types.StatusVotingPeriod app.GovKeeper.SetProposal(ctx, proposal) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[0], types.OptionYes)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[1], types.OptionNo)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[0], types.SubVotes{types.NewSubVote(types.OptionYes, 1)})) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[1], types.SubVotes{types.NewSubVote(types.OptionNo, 1)})) proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) require.True(t, ok) @@ -123,8 +123,8 @@ func TestTallyOnlyValidators51Yes(t *testing.T) { proposal.Status = types.StatusVotingPeriod app.GovKeeper.SetProposal(ctx, proposal) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[0], types.OptionNo)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[1], types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[0], types.SubVotes{types.NewSubVote(types.OptionNo, 1)})) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[1], types.SubVotes{types.NewSubVote(types.OptionYes, 1)})) proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) require.True(t, ok) @@ -148,9 +148,9 @@ func TestTallyOnlyValidatorsVetoed(t *testing.T) { proposal.Status = types.StatusVotingPeriod app.GovKeeper.SetProposal(ctx, proposal) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[0], types.OptionYes)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[1], types.OptionYes)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[2], types.OptionNoWithVeto)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[0], types.SubVotes{types.NewSubVote(types.OptionYes, 1)})) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[1], types.SubVotes{types.NewSubVote(types.OptionYes, 1)})) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[2], types.SubVotes{types.NewSubVote(types.OptionNoWithVeto, 1)})) proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) require.True(t, ok) @@ -174,9 +174,9 @@ func TestTallyOnlyValidatorsAbstainPasses(t *testing.T) { proposal.Status = types.StatusVotingPeriod app.GovKeeper.SetProposal(ctx, proposal) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[0], types.OptionAbstain)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[1], types.OptionNo)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[2], types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[0], types.SubVotes{types.NewSubVote(types.OptionAbstain, 1)})) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[1], types.SubVotes{types.NewSubVote(types.OptionNo, 1)})) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[2], types.SubVotes{types.NewSubVote(types.OptionYes, 1)})) proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) require.True(t, ok) @@ -200,9 +200,9 @@ func TestTallyOnlyValidatorsAbstainFails(t *testing.T) { proposal.Status = types.StatusVotingPeriod app.GovKeeper.SetProposal(ctx, proposal) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[0], types.OptionAbstain)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[1], types.OptionYes)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[2], types.OptionNo)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[0], types.SubVotes{types.NewSubVote(types.OptionAbstain, 1)})) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[1], types.SubVotes{types.NewSubVote(types.OptionYes, 1)})) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddrs[2], types.SubVotes{types.NewSubVote(types.OptionNo, 1)})) proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) require.True(t, ok) @@ -227,8 +227,8 @@ func TestTallyOnlyValidatorsNonVoter(t *testing.T) { proposal.Status = types.StatusVotingPeriod app.GovKeeper.SetProposal(ctx, proposal) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr1, types.OptionYes)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr2, types.OptionNo)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr1, types.SubVotes{types.NewSubVote(types.OptionYes, 1)})) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, valAccAddr2, types.SubVotes{types.NewSubVote(types.OptionNo, 1)})) proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) require.True(t, ok) @@ -261,10 +261,10 @@ func TestTallyDelgatorOverride(t *testing.T) { proposal.Status = types.StatusVotingPeriod app.GovKeeper.SetProposal(ctx, proposal) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.OptionYes)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[2], types.OptionYes)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[3], types.OptionYes)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[4], types.OptionNo)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.SubVotes{types.NewSubVote(types.OptionYes, 1)})) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[2], types.SubVotes{types.NewSubVote(types.OptionYes, 1)})) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[3], types.SubVotes{types.NewSubVote(types.OptionYes, 1)})) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[4], types.SubVotes{types.NewSubVote(types.OptionNo, 1)})) proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) require.True(t, ok) @@ -297,9 +297,9 @@ func TestTallyDelgatorInherit(t *testing.T) { proposal.Status = types.StatusVotingPeriod app.GovKeeper.SetProposal(ctx, proposal) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.OptionNo)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.OptionNo)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[2], types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.SubVotes{types.NewSubVote(types.OptionNo, 1)})) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.SubVotes{types.NewSubVote(types.OptionNo, 1)})) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[2], types.SubVotes{types.NewSubVote(types.OptionYes, 1)})) proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) require.True(t, ok) @@ -336,10 +336,10 @@ func TestTallyDelgatorMultipleOverride(t *testing.T) { proposal.Status = types.StatusVotingPeriod app.GovKeeper.SetProposal(ctx, proposal) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.OptionYes)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.OptionYes)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[2], types.OptionYes)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[3], types.OptionNo)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.SubVotes{types.NewSubVote(types.OptionYes, 1)})) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.SubVotes{types.NewSubVote(types.OptionYes, 1)})) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[2], types.SubVotes{types.NewSubVote(types.OptionYes, 1)})) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[3], types.SubVotes{types.NewSubVote(types.OptionNo, 1)})) proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) require.True(t, ok) @@ -378,9 +378,9 @@ func TestTallyDelgatorMultipleInherit(t *testing.T) { proposal.Status = types.StatusVotingPeriod app.GovKeeper.SetProposal(ctx, proposal) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.OptionYes)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.OptionNo)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[2], types.OptionNo)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.SubVotes{types.NewSubVote(types.OptionYes, 1)})) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.SubVotes{types.NewSubVote(types.OptionNo, 1)})) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[2], types.SubVotes{types.NewSubVote(types.OptionNo, 1)})) proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) require.True(t, ok) @@ -421,9 +421,8 @@ func TestTallyJailedValidator(t *testing.T) { proposal.Status = types.StatusVotingPeriod app.GovKeeper.SetProposal(ctx, proposal) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.OptionYes)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.OptionNo)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[2], types.OptionNo)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.SubVotes{types.NewSubVote(types.OptionYes, 1)})) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.SubVotes{types.NewSubVote(types.OptionNo, 1)})) proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) require.True(t, ok) @@ -454,9 +453,9 @@ func TestTallyValidatorMultipleDelegations(t *testing.T) { proposal.Status = types.StatusVotingPeriod app.GovKeeper.SetProposal(ctx, proposal) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.OptionYes)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.OptionNo)) - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[2], types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.SubVotes{types.NewSubVote(types.OptionYes, 1)})) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.SubVotes{types.NewSubVote(types.OptionNo, 1)})) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[2], types.SubVotes{types.NewSubVote(types.OptionYes, 1)})) proposal, ok := app.GovKeeper.GetProposal(ctx, proposalID) require.True(t, ok) diff --git a/x/gov/keeper/vote.go b/x/gov/keeper/vote.go index c86a06872a..4a298697f5 100644 --- a/x/gov/keeper/vote.go +++ b/x/gov/keeper/vote.go @@ -9,7 +9,7 @@ import ( ) // AddVote adds a vote on a specific proposal -func (keeper Keeper) AddVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress, subvotes []types.SubVote) error { +func (keeper Keeper) AddVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.AccAddress, subvotes types.SubVotes) error { proposal, ok := keeper.GetProposal(ctx, proposalID) if !ok { return sdkerrors.Wrapf(types.ErrUnknownProposal, "%d", proposalID) @@ -18,8 +18,10 @@ func (keeper Keeper) AddVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.A return sdkerrors.Wrapf(types.ErrInactiveProposal, "%d", proposalID) } - if !types.ValidVoteOption(option) { - return sdkerrors.Wrap(types.ErrInvalidVote, option.String()) + for _, subvote := range subvotes { + if !types.ValidSubVote(subvote) { + return sdkerrors.Wrap(types.ErrInvalidVote, subvote.String()) + } } vote := types.NewVote(proposalID, voterAddr, subvotes) @@ -28,7 +30,7 @@ func (keeper Keeper) AddVote(ctx sdk.Context, proposalID uint64, voterAddr sdk.A ctx.EventManager().EmitEvent( sdk.NewEvent( types.EventTypeProposalVote, - sdk.NewAttribute(types.AttributeKeyOption, option.String()), + sdk.NewAttribute(types.AttributeKeyOption, subvotes.String()), sdk.NewAttribute(types.AttributeKeyProposalID, fmt.Sprintf("%d", proposalID)), ), ) diff --git a/x/gov/keeper/vote_test.go b/x/gov/keeper/vote_test.go index 5f5bf0cc73..6c9a78da45 100644 --- a/x/gov/keeper/vote_test.go +++ b/x/gov/keeper/vote_test.go @@ -24,37 +24,40 @@ func TestVotes(t *testing.T) { var invalidOption types.VoteOption = 0x10 - require.Error(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.OptionYes), "proposal not on voting period") - require.Error(t, app.GovKeeper.AddVote(ctx, 10, addrs[0], types.OptionYes), "invalid proposal ID") + require.Error(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.SubVotes{types.NewSubVote(types.OptionYes, 1)}), "proposal not on voting period") + require.Error(t, app.GovKeeper.AddVote(ctx, 10, addrs[0], types.SubVotes{types.NewSubVote(types.OptionYes, 1)}), "invalid proposal ID") proposal.Status = types.StatusVotingPeriod app.GovKeeper.SetProposal(ctx, proposal) - require.Error(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], invalidOption), "invalid option") + require.Error(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.SubVotes{types.NewSubVote(invalidOption, 1)}), "invalid option") // Test first vote - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.OptionAbstain)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.SubVotes{types.NewSubVote(types.OptionAbstain, 1)})) vote, found := app.GovKeeper.GetVote(ctx, proposalID, addrs[0]) require.True(t, found) require.Equal(t, addrs[0].String(), vote.Voter) require.Equal(t, proposalID, vote.ProposalId) - require.Equal(t, types.OptionAbstain, vote.Option) + require.True(t, len(vote.SubVotes) == 1) + require.Equal(t, types.OptionAbstain, vote.SubVotes[0].Option) // Test change of vote - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.OptionYes)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[0], types.SubVotes{types.NewSubVote(types.OptionYes, 1)})) vote, found = app.GovKeeper.GetVote(ctx, proposalID, addrs[0]) require.True(t, found) require.Equal(t, addrs[0].String(), vote.Voter) require.Equal(t, proposalID, vote.ProposalId) - require.Equal(t, types.OptionYes, vote.Option) + require.True(t, len(vote.SubVotes) == 1) + require.Equal(t, types.OptionYes, vote.SubVotes[0].Option) // Test second vote - require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.OptionNoWithVeto)) + require.NoError(t, app.GovKeeper.AddVote(ctx, proposalID, addrs[1], types.SubVotes{types.NewSubVote(types.OptionNoWithVeto, 1)})) vote, found = app.GovKeeper.GetVote(ctx, proposalID, addrs[1]) require.True(t, found) require.Equal(t, addrs[1].String(), vote.Voter) require.Equal(t, proposalID, vote.ProposalId) - require.Equal(t, types.OptionNoWithVeto, vote.Option) + require.True(t, len(vote.SubVotes) == 1) + require.Equal(t, types.OptionNoWithVeto, vote.SubVotes[0].Option) // Test vote iterator // NOTE order of deposits is determined by the addresses @@ -63,8 +66,10 @@ func TestVotes(t *testing.T) { require.Equal(t, votes, app.GovKeeper.GetVotes(ctx, proposalID)) require.Equal(t, addrs[0].String(), votes[0].Voter) require.Equal(t, proposalID, votes[0].ProposalId) - require.Equal(t, types.OptionYes, votes[0].Option) + require.True(t, len(votes[0].SubVotes) == 1) + require.Equal(t, types.OptionYes, votes[0].SubVotes[0].Option) require.Equal(t, addrs[1].String(), votes[1].Voter) require.Equal(t, proposalID, votes[1].ProposalId) - require.Equal(t, types.OptionNoWithVeto, votes[1].Option) + require.True(t, len(votes[1].SubVotes) == 1) + require.Equal(t, types.OptionNoWithVeto, votes[1].SubVotes[0].Option) } diff --git a/x/gov/legacy/v040/migrate.go b/x/gov/legacy/v040/migrate.go index 522bbd54ca..bafd933229 100644 --- a/x/gov/legacy/v040/migrate.go +++ b/x/gov/legacy/v040/migrate.go @@ -118,7 +118,7 @@ func Migrate(oldGovState v036gov.GenesisState) *v040gov.GenesisState { newVotes[i] = v040gov.Vote{ ProposalId: oldVote.ProposalID, Voter: oldVote.Voter.String(), - SubVotes: []v040gov.SubVote{v040gov.NewSubVote(migrateVoteOption(oldVote.Option), 1)}, + SubVotes: v040gov.SubVotes{v040gov.NewSubVote(migrateVoteOption(oldVote.Option), 1)}, } } diff --git a/x/gov/simulation/decoder_test.go b/x/gov/simulation/decoder_test.go index 7a5b0fc1bc..4a17cb9a57 100644 --- a/x/gov/simulation/decoder_test.go +++ b/x/gov/simulation/decoder_test.go @@ -34,7 +34,7 @@ func TestDecodeStore(t *testing.T) { proposalIDBz := make([]byte, 8) binary.LittleEndian.PutUint64(proposalIDBz, 1) deposit := types.NewDeposit(1, delAddr1, sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.OneInt()))) - vote := types.NewVote(1, delAddr1, types.OptionYes) + vote := types.NewVote(1, delAddr1, types.SubVotes{types.NewSubVote(types.OptionYes, 1)}) proposalBz, err := cdc.MarshalBinaryBare(&proposal) require.NoError(t, err) diff --git a/x/gov/simulation/operations.go b/x/gov/simulation/operations.go index 0dedf64888..c7c7b6aa62 100644 --- a/x/gov/simulation/operations.go +++ b/x/gov/simulation/operations.go @@ -281,7 +281,7 @@ func operationSimulateMsgVote(ak types.AccountKeeper, bk types.BankKeeper, k kee } option := randomVotingOption(r) - msg := types.NewMsgVote(simAccount.Address, proposalID, option) + msg := types.NewMsgVote(simAccount.Address, proposalID, types.SubVotes{types.NewSubVote(option, 1)}) account := ak.GetAccount(ctx, simAccount.Address) spendable := bk.SpendableCoins(ctx, account.GetAddress()) diff --git a/x/gov/simulation/operations_test.go b/x/gov/simulation/operations_test.go index 9c6e8306f8..5273de46ac 100644 --- a/x/gov/simulation/operations_test.go +++ b/x/gov/simulation/operations_test.go @@ -202,7 +202,8 @@ func TestSimulateMsgVote(t *testing.T) { require.True(t, operationMsg.OK) require.Equal(t, uint64(1), msg.ProposalId) require.Equal(t, "cosmos1ghekyjucln7y67ntx7cf27m9dpuxxemn4c8g4r", msg.Voter) - require.Equal(t, types.OptionYes, msg.Option) + require.True(t, len(msg.SubVotes) == 1) + require.Equal(t, types.OptionYes, msg.SubVotes[0].Option) require.Equal(t, "gov", msg.Route()) require.Equal(t, types.TypeMsgVote, msg.Type()) diff --git a/x/gov/types/events.go b/x/gov/types/events.go index 19f8857f3a..3f3e471cb1 100644 --- a/x/gov/types/events.go +++ b/x/gov/types/events.go @@ -10,6 +10,7 @@ const ( AttributeKeyProposalResult = "proposal_result" AttributeKeyOption = "option" + AttributeKeySubVotes = "sub_votes" AttributeKeyProposalID = "proposal_id" AttributeKeyVotingPeriodStart = "voting_period_start" AttributeValueCategory = "governance" diff --git a/x/gov/types/msgs_test.go b/x/gov/types/msgs_test.go index 9d7d6a3682..9ae733a9dd 100644 --- a/x/gov/types/msgs_test.go +++ b/x/gov/types/msgs_test.go @@ -109,7 +109,7 @@ func TestMsgVote(t *testing.T) { } for i, tc := range tests { - msg := NewMsgVote(tc.voterAddr, tc.proposalID, tc.option) + msg := NewMsgVote(tc.voterAddr, tc.proposalID, SubVotes{NewSubVote(tc.option, 1)}) if tc.expectPass { require.Nil(t, msg.ValidateBasic(), "test: %v", i) } else { diff --git a/x/gov/types/tally.go b/x/gov/types/tally.go index a4e9ee9086..294de078d2 100644 --- a/x/gov/types/tally.go +++ b/x/gov/types/tally.go @@ -12,19 +12,19 @@ type ValidatorGovInfo struct { BondedTokens sdk.Int // Power of a Validator DelegatorShares sdk.Dec // Total outstanding delegator shares DelegatorDeductions sdk.Dec // Delegator deductions from validator's delegators voting independently - Vote VoteOption // Vote of the validator + Vote SubVotes // Vote of the validator } // NewValidatorGovInfo creates a ValidatorGovInfo instance func NewValidatorGovInfo(address sdk.ValAddress, bondedTokens sdk.Int, delegatorShares, - delegatorDeductions sdk.Dec, vote VoteOption) ValidatorGovInfo { + delegatorDeductions sdk.Dec, subvotes SubVotes) ValidatorGovInfo { return ValidatorGovInfo{ Address: address, BondedTokens: bondedTokens, DelegatorShares: delegatorShares, DelegatorDeductions: delegatorDeductions, - Vote: vote, + Vote: subvotes, } } diff --git a/x/gov/types/vote.go b/x/gov/types/vote.go index fbeb86606f..eb721f1d6f 100644 --- a/x/gov/types/vote.go +++ b/x/gov/types/vote.go @@ -65,6 +65,14 @@ func (v SubVote) String() string { return string(out) } +// SubVotes describes array of SubVote +type SubVotes []SubVote + +func (v SubVotes) String() string { + out, _ := json.Marshal(v) + return string(out) +} + // ValidSubVote returns true if the sub vote is valid and false otherwise. func ValidSubVote(subvote SubVote) bool { if !subvote.Rate.IsPositive() {