Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(gov): add proposal types and spam votes #18532

Merged
merged 26 commits into from
Dec 11, 2023
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
62ef693
feat(gov): add proposal types and spam votes
julienrbrt Nov 21, 2023
2a536e8
updates
julienrbrt Nov 21, 2023
e8da7ac
wip
julienrbrt Nov 21, 2023
fb281bf
fix tests
julienrbrt Nov 22, 2023
a568dc9
updates
julienrbrt Nov 22, 2023
50f1015
updates
julienrbrt Nov 22, 2023
c9dc8c8
validate previous options
julienrbrt Nov 22, 2023
9013310
Merge branch 'main' into julien/gov-spam-proposal-type
julienrbrt Nov 22, 2023
7eed169
updates
julienrbrt Nov 22, 2023
411378e
proto lint
julienrbrt Nov 22, 2023
f0464f5
nits
julienrbrt Nov 24, 2023
2e62db1
remove duplicate tests
julienrbrt Nov 24, 2023
2bdf2bc
nits
julienrbrt Nov 24, 2023
74c7f77
Merge branch 'main' into julien/gov-spam-proposal-type
julienrbrt Nov 25, 2023
aaf6d2f
Merge branch 'main' into julien/gov-spam-proposal-type
julienrbrt Nov 30, 2023
84a2e4b
Merge branch 'main' into julien/gov-spam-proposal-type
julienrbrt Dec 1, 2023
b000ac0
feedback
julienrbrt Dec 1, 2023
4aa5df7
Merge branch 'main' into julien/gov-spam-proposal-type
julienrbrt Dec 4, 2023
96cb2d9
Merge branch 'main' into julien/gov-spam-proposal-type
julienrbrt Dec 6, 2023
2d105ee
updates
julienrbrt Dec 6, 2023
715d5f1
Merge branch 'main' into julien/gov-spam-proposal-type
julienrbrt Dec 6, 2023
ebd6ab8
updates
julienrbrt Dec 6, 2023
4d28273
typo
julienrbrt Dec 6, 2023
ba7649f
Merge branch 'main' into julien/gov-spam-proposal-type
julienrbrt Dec 11, 2023
59654b6
Merge branch 'main' into julien/gov-spam-proposal-type
julienrbrt Dec 11, 2023
f08d2f5
updates
julienrbrt Dec 11, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,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 {
tac0turtle marked this conversation as resolved.
Show resolved Hide resolved
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;
tac0turtle marked this conversation as resolved.
Show resolved Hide resolved
// 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;
tac0turtle marked this conversation as resolved.
Show resolved Hide resolved
// 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 {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo investigate how to be minimally breaking for client if possible.

// 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 @@ -386,7 +386,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
194 changes: 0 additions & 194 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,48 +33,6 @@ func TestLegacyGRPCQueryTally(t *testing.T) {
expPass bool
expErrMsg string
julienrbrt marked this conversation as resolved.
Show resolved Hide resolved
}{
{
"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)
assert.NilError(t, err)
assert.Assert(t, proposal.String() != "")

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

tallyResult := v1beta1.EmptyTallyResult()
expRes = &v1beta1.QueryTallyResultResponse{
Tally: tallyResult,
}
},
true,
"",
},
{
"request tally after few votes",
func() {
Expand All @@ -221,23 +57,6 @@ func TestLegacyGRPCQueryTally(t *testing.T) {
true,
"",
},
julienrbrt marked this conversation as resolved.
Show resolved Hide resolved
{
"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 +75,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
Loading