Skip to content

Commit

Permalink
feat(gov): add proposal types and spam votes (#18532)
Browse files Browse the repository at this point in the history
  • Loading branch information
julienrbrt authored Dec 11, 2023
1 parent 1f741d4 commit 8b894f7
Show file tree
Hide file tree
Showing 47 changed files with 1,690 additions and 1,109 deletions.
1 change: 0 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,6 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (types) [#17348](https://github.com/cosmos/cosmos-sdk/pull/17348) Remove the `WrapServiceResult` function.
* The `*sdk.Result` returned by the msg server router will not contain the `.Data` field.
* (x/staking) [#17335](https://github.com/cosmos/cosmos-sdk/pull/17335) Remove usage of `"cosmossdk.io/x/staking/types".Infraction_*` in favour of `"cosmossdk.io/api/cosmos/staking/v1beta1".Infraction_` in order to remove dependency between modules on staking
* (x/gov) [#17496](https://github.com/cosmos/cosmos-sdk/pull/17469) in `x/gov/types/v1beta1/vote.go` `NewVote` was removed, constructing the struct is required for this type
* (types) [#17426](https://github.com/cosmos/cosmos-sdk/pull/17426) `NewContext` does not take a `cmtproto.Header{}` any longer.
* `WithChainID` / `WithBlockHeight` / `WithBlockHeader` must be used to set values on the context
* (x/bank) [#17569](https://github.com/cosmos/cosmos-sdk/pull/17569) `BurnCoins` takes an address instead of a module name
Expand Down
627 changes: 437 additions & 190 deletions api/cosmos/gov/v1/gov.pulsar.go

Large diffs are not rendered by default.

437 changes: 255 additions & 182 deletions api/cosmos/gov/v1/tx.pulsar.go

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions proto/buf.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ lint:
- SERVICE_SUFFIX
- PACKAGE_VERSION_SUFFIX
- RPC_REQUEST_STANDARD_NAME
- ENUM_NO_ALLOW_ALIAS
ignore:
- tendermint
53 changes: 44 additions & 9 deletions proto/cosmos/gov/v1/gov.proto
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,45 @@ import "amino/amino.proto";

option go_package = "cosmossdk.io/x/gov/types/v1";

// ProposalType enumerates the valid proposal types.
// All proposal types are v1.Proposal which have different voting periods or tallying logic.
enum ProposalType {
// PROPOSAL_TYPE_UNSPECIFIED defines no proposal type, which fallback to PROPOSAL_TYPE_STANDARD.
PROPOSAL_TYPE_UNSPECIFIED = 0;
// PROPOSAL_TYPE_STANDARD defines the type for a standard proposal.
PROPOSAL_TYPE_STANDARD = 1;
// PROPOSAL_TYPE_MULTIPLE_CHOICE defines the type for a multiple choice proposal.
PROPOSAL_TYPE_MULTIPLE_CHOICE = 2;
// PROPOSAL_TYPE_OPTIMISTIC defines the type for an optimistic proposal.
PROPOSAL_TYPE_OPTIMISTIC = 3;
// PROPOSAL_TYPE_EXPEDITED defines the type for an expedited proposal.
PROPOSAL_TYPE_EXPEDITED = 4;
}

// VoteOption enumerates the valid vote options for a given governance proposal.
enum VoteOption {
option allow_alias = true;

// VOTE_OPTION_UNSPECIFIED defines a no-op vote option.
VOTE_OPTION_UNSPECIFIED = 0;
// VOTE_OPTION_YES defines a yes vote option.
// VOTE_OPTION_ONE defines the first proposal vote option.
VOTE_OPTION_ONE = 1;
// VOTE_OPTION_YES defines the yes proposal vote option.
VOTE_OPTION_YES = 1;
// VOTE_OPTION_ABSTAIN defines an abstain vote option.
// VOTE_OPTION_TWO defines the second proposal vote option.
VOTE_OPTION_TWO = 2;
// VOTE_OPTION_ABSTAIN defines the abstain proposal vote option.
VOTE_OPTION_ABSTAIN = 2;
// VOTE_OPTION_NO defines a no vote option.
// VOTE_OPTION_THREE defines the third proposal vote option.
VOTE_OPTION_THREE = 3;
// VOTE_OPTION_NO defines the no proposal vote option.
VOTE_OPTION_NO = 3;
// VOTE_OPTION_NO_WITH_VETO defines a no with veto vote option.
// VOTE_OPTION_FOUR defines the fourth proposal vote option.
VOTE_OPTION_FOUR = 4;
// VOTE_OPTION_NO_WITH_VETO defines the no with veto proposal vote option.
VOTE_OPTION_NO_WITH_VETO = 4;
// VOTE_OPTION_SPAM defines the spam proposal vote option.
VOTE_OPTION_SPAM = 5;
}

// WeightedVoteOption defines a unit of vote for vote split.
Expand Down Expand Up @@ -102,12 +129,18 @@ message Proposal {
// expedited defines if the proposal is expedited
//
// Since: cosmos-sdk 0.50
bool expedited = 14;
// Deprecated: Use ProposalType instead.
bool expedited = 14 [deprecated = true];

// failed_reason defines the reason why the proposal failed
//
// Since: cosmos-sdk 0.50
string failed_reason = 15;

// proposal_type defines the type of the proposal
//
// Since: cosmos-sdk 0.51
ProposalType proposal_type = 16;
}

// ProposalStatus enumerates the valid statuses of a proposal.
Expand All @@ -134,13 +167,15 @@ enum ProposalStatus {
// TallyResult defines a standard tally for a governance proposal.
message TallyResult {
// yes_count is the number of yes votes on a proposal.
string yes_count = 1 [(cosmos_proto.scalar) = "cosmos.Int"];
string yes_count = 1 [(cosmos_proto.scalar) = "cosmos.Int"]; // option 1
// abstain_count is the number of abstain votes on a proposal.
string abstain_count = 2 [(cosmos_proto.scalar) = "cosmos.Int"];
string abstain_count = 2 [(cosmos_proto.scalar) = "cosmos.Int"]; // option 2
// no_count is the number of no votes on a proposal.
string no_count = 3 [(cosmos_proto.scalar) = "cosmos.Int"];
string no_count = 3 [(cosmos_proto.scalar) = "cosmos.Int"]; // option 3
// no_with_veto_count is the number of no with veto votes on a proposal.
string no_with_veto_count = 4 [(cosmos_proto.scalar) = "cosmos.Int"];
string no_with_veto_count = 4 [(cosmos_proto.scalar) = "cosmos.Int"]; // option 4
// spam_count is the number of spam votes on a proposal.
string spam_count = 5 [(cosmos_proto.scalar) = "cosmos.Int"];
}

// Vote defines a vote on a governance proposal.
Expand Down
11 changes: 10 additions & 1 deletion proto/cosmos/gov/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,16 @@ message MsgSubmitProposal {
// expedited defines if the proposal is expedited or not
//
// Since: cosmos-sdk 0.50
bool expedited = 7;
// Deprecated: Use the PROPOSAL_TYPE_EXPEDITED proposal type instead.
// When this field is set and no proposal_type is set, the proposal_type
// will be set to PROPOSAL_TYPE_EXPEDITED for backwards compatibility.
bool expedited = 7 [deprecated = true];

// proposal_type defines the type of proposal
// When not set defaults to PROPOSAL_TYPE_STANDARD
//
// Since: cosmos-sdk 0.51
ProposalType proposal_type = 8;
}

// MsgSubmitProposalResponse defines the Msg/SubmitProposal response type.
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/bank/app_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ func TestMsgSetSendEnabled(t *testing.T) {
"set default send enabled to true",
"Change send enabled",
"Modify send enabled and set to true",
false,
govv1.ProposalType_PROPOSAL_TYPE_STANDARD,
)
require.NoError(t, err, "making goodGovProp")

Expand Down
4 changes: 2 additions & 2 deletions tests/integration/gov/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,11 @@ func TestImportExportQueues(t *testing.T) {

ctx = s1.app.BaseApp.NewContext(false)
// Create two proposals, put the second into the voting period
proposal1, err := s1.GovKeeper.SubmitProposal(ctx, []sdk.Msg{mkTestLegacyContent(t)}, "", "test", "description", addrs[0], false)
proposal1, err := s1.GovKeeper.SubmitProposal(ctx, []sdk.Msg{mkTestLegacyContent(t)}, "", "test", "description", addrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD)
assert.NilError(t, err)
proposalID1 := proposal1.Id

proposal2, err := s1.GovKeeper.SubmitProposal(ctx, []sdk.Msg{mkTestLegacyContent(t)}, "", "test", "description", addrs[0], false)
proposal2, err := s1.GovKeeper.SubmitProposal(ctx, []sdk.Msg{mkTestLegacyContent(t)}, "", "test", "description", addrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD)
assert.NilError(t, err)
proposalID2 := proposal2.Id

Expand Down
178 changes: 1 addition & 177 deletions tests/integration/gov/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,128 +12,6 @@ import (
"cosmossdk.io/x/gov/types/v1beta1"
)

func TestGRPCQueryTally(t *testing.T) {
t.Parallel()
f := initFixture(t)

ctx, queryClient := f.ctx, f.queryClient

addrs, _ := createValidators(t, f, []int64{5, 5, 5})

var (
req *v1.QueryTallyResultRequest
expRes *v1.QueryTallyResultResponse
proposal v1.Proposal
)

testCases := []struct {
msg string
malleate func()
expPass bool
expErrMsg string
}{
{
"empty request",
func() {
req = &v1.QueryTallyResultRequest{}
},
false,
"proposal id can not be 0",
},
{
"zero proposal id request",
func() {
req = &v1.QueryTallyResultRequest{ProposalId: 0}
},
false,
"proposal id can not be 0",
},
{
"query non existed proposal",
func() {
req = &v1.QueryTallyResultRequest{ProposalId: 1}
},
false,
"proposal 1 doesn't exist",
},
{
"create a proposal and get tally",
func() {
var err error
proposal, err = f.govKeeper.SubmitProposal(ctx, TestProposal, "", "test", "description", addrs[0], false)
assert.NilError(t, err)
assert.Assert(t, proposal.String() != "")

req = &v1.QueryTallyResultRequest{ProposalId: proposal.Id}

tallyResult := v1.EmptyTallyResult()
expRes = &v1.QueryTallyResultResponse{
Tally: &tallyResult,
}
},
true,
"",
},
{
"request tally after few votes",
func() {
proposal.Status = v1.StatusVotingPeriod
err := f.govKeeper.SetProposal(ctx, proposal)
assert.NilError(t, err)
assert.NilError(t, f.govKeeper.AddVote(ctx, proposal.Id, addrs[0], v1.NewNonSplitVoteOption(v1.OptionYes), ""))
assert.NilError(t, f.govKeeper.AddVote(ctx, proposal.Id, addrs[1], v1.NewNonSplitVoteOption(v1.OptionYes), ""))
assert.NilError(t, f.govKeeper.AddVote(ctx, proposal.Id, addrs[2], v1.NewNonSplitVoteOption(v1.OptionYes), ""))

req = &v1.QueryTallyResultRequest{ProposalId: proposal.Id}

expRes = &v1.QueryTallyResultResponse{
Tally: &v1.TallyResult{
YesCount: math.NewInt(3 * 5 * 1000000).String(),
NoCount: "0",
AbstainCount: "0",
NoWithVetoCount: "0",
},
}
},
true,
"",
},
{
"request final tally after status changed",
func() {
proposal.Status = v1.StatusPassed
err := f.govKeeper.SetProposal(ctx, proposal)
assert.NilError(t, err)
proposal, _ = f.govKeeper.Proposals.Get(ctx, proposal.Id)

req = &v1.QueryTallyResultRequest{ProposalId: proposal.Id}

expRes = &v1.QueryTallyResultResponse{
Tally: proposal.FinalTallyResult,
}
},
true,
"",
},
}

for _, testCase := range testCases {
t.Run(fmt.Sprintf("Case %s", testCase.msg), func(t *testing.T) {
testCase.malleate()

tally, err := queryClient.TallyResult(gocontext.Background(), req)

if testCase.expPass {
assert.NilError(t, err)
assert.Equal(t, expRes.String(), tally.String())
} else {
assert.ErrorContains(t, err, testCase.expErrMsg)
assert.Assert(t, tally == nil)
}
})
}
}

func TestLegacyGRPCQueryTally(t *testing.T) {
t.Parallel()

Expand All @@ -155,35 +33,11 @@ func TestLegacyGRPCQueryTally(t *testing.T) {
expPass bool
expErrMsg string
}{
{
"empty request",
func() {
req = &v1beta1.QueryTallyResultRequest{}
},
false,
"proposal id can not be 0",
},
{
"zero proposal id request",
func() {
req = &v1beta1.QueryTallyResultRequest{ProposalId: 0}
},
false,
"proposal id can not be 0",
},
{
"query non existed proposal",
func() {
req = &v1beta1.QueryTallyResultRequest{ProposalId: 1}
},
false,
"proposal 1 doesn't exist",
},
{
"create a proposal and get tally",
func() {
var err error
proposal, err = f.govKeeper.SubmitProposal(ctx, TestProposal, "", "test", "description", addrs[0], false)
proposal, err = f.govKeeper.SubmitProposal(ctx, TestProposal, "", "test", "description", addrs[0], v1.ProposalType_PROPOSAL_TYPE_STANDARD)
assert.NilError(t, err)
assert.Assert(t, proposal.String() != "")

Expand Down Expand Up @@ -221,23 +75,6 @@ func TestLegacyGRPCQueryTally(t *testing.T) {
true,
"",
},
{
"request final tally after status changed",
func() {
proposal.Status = v1.StatusPassed
err := f.govKeeper.SetProposal(ctx, proposal)
assert.NilError(t, err)
proposal, _ = f.govKeeper.Proposals.Get(ctx, proposal.Id)

req = &v1beta1.QueryTallyResultRequest{ProposalId: proposal.Id}

expRes = &v1beta1.QueryTallyResultResponse{
Tally: v1TallyToV1Beta1Tally(*proposal.FinalTallyResult),
}
},
true,
"",
},
}

for _, testCase := range testCases {
Expand All @@ -256,16 +93,3 @@ func TestLegacyGRPCQueryTally(t *testing.T) {
})
}
}

func v1TallyToV1Beta1Tally(t v1.TallyResult) v1beta1.TallyResult {
yes, _ := math.NewIntFromString(t.YesCount)
no, _ := math.NewIntFromString(t.NoCount)
noWithVeto, _ := math.NewIntFromString(t.NoWithVetoCount)
abstain, _ := math.NewIntFromString(t.AbstainCount)
return v1beta1.TallyResult{
Yes: yes,
No: no,
NoWithVeto: noWithVeto,
Abstain: abstain,
}
}
Loading

0 comments on commit 8b894f7

Please sign in to comment.