Skip to content

Commit

Permalink
feat: custom proposal-based voting periods (#1)
Browse files Browse the repository at this point in the history
  • Loading branch information
johnletey authored Jun 15, 2022
1 parent a2761bd commit 379239e
Show file tree
Hide file tree
Showing 12 changed files with 508 additions and 106 deletions.
21 changes: 20 additions & 1 deletion docs/core/proto-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@
- [Deposit](#cosmos.gov.v1beta1.Deposit)
- [DepositParams](#cosmos.gov.v1beta1.DepositParams)
- [Proposal](#cosmos.gov.v1beta1.Proposal)
- [ProposalVotingPeriod](#cosmos.gov.v1beta1.ProposalVotingPeriod)
- [TallyParams](#cosmos.gov.v1beta1.TallyParams)
- [TallyResult](#cosmos.gov.v1beta1.TallyResult)
- [TextProposal](#cosmos.gov.v1beta1.TextProposal)
Expand Down Expand Up @@ -5115,6 +5116,23 @@ Proposal defines the core field members of a governance proposal.



<a name="cosmos.gov.v1beta1.ProposalVotingPeriod"></a>

### ProposalVotingPeriod
ProposalVotingPeriod defines custom voting periods for a unique governance
proposal type.


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `proposal_type` | [string](#string) | | e.g. "cosmos.params.v1beta1.ParameterChangeProposal" |
| `voting_period` | [google.protobuf.Duration](#google.protobuf.Duration) | | |






<a name="cosmos.gov.v1beta1.TallyParams"></a>

### TallyParams
Expand Down Expand Up @@ -5194,7 +5212,8 @@ VotingParams defines the params for voting on governance proposals.

| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `voting_period` | [google.protobuf.Duration](#google.protobuf.Duration) | | Length of the voting period. |
| `voting_period` | [google.protobuf.Duration](#google.protobuf.Duration) | | voting_period defines the length of the voting period. |
| `proposal_voting_periods` | [ProposalVotingPeriod](#cosmos.gov.v1beta1.ProposalVotingPeriod) | repeated | proposal_voting_periods defines custom voting periods for proposal types. |



Expand Down
17 changes: 16 additions & 1 deletion proto/cosmos/gov/v1beta1/gov.proto
Original file line number Diff line number Diff line change
Expand Up @@ -163,13 +163,16 @@ message DepositParams {

// VotingParams defines the params for voting on governance proposals.
message VotingParams {
// Length of the voting period.
// voting_period defines the length of the voting period.
google.protobuf.Duration voting_period = 1 [
(gogoproto.nullable) = false,
(gogoproto.stdduration) = true,
(gogoproto.jsontag) = "voting_period,omitempty",
(gogoproto.moretags) = "yaml:\"voting_period\""
];

// proposal_voting_periods defines custom voting periods for proposal types.
repeated ProposalVotingPeriod proposal_voting_periods = 2 [(gogoproto.nullable) = false];
}

// TallyParams defines the params for tallying votes on governance proposals.
Expand Down Expand Up @@ -198,3 +201,15 @@ message TallyParams {
(gogoproto.moretags) = "yaml:\"veto_threshold\""
];
}

// ProposalVotingPeriod defines custom voting periods for a unique governance
// proposal type.
message ProposalVotingPeriod {
string proposal_type = 1; // e.g. "cosmos.params.v1beta1.ParameterChangeProposal"
google.protobuf.Duration voting_period = 2 [
(gogoproto.nullable) = false,
(gogoproto.stdduration) = true,
(gogoproto.jsontag) = "voting_period,omitempty",
(gogoproto.moretags) = "yaml:\"voting_period\""
];
}
3 changes: 2 additions & 1 deletion x/gov/client/testutil/cli_test.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//go:build norace
// +build norace

package testutil
Expand All @@ -21,7 +22,7 @@ func TestIntegrationTestSuite(t *testing.T) {

genesisState := types.DefaultGenesisState()
genesisState.DepositParams = types.NewDepositParams(sdk.NewCoins(sdk.NewCoin(cfg.BondDenom, types.DefaultMinDepositTokens)), time.Duration(15)*time.Second)
genesisState.VotingParams = types.NewVotingParams(time.Duration(5) * time.Second)
genesisState.VotingParams = types.NewVotingParams(time.Duration(5)*time.Second, []types.ProposalVotingPeriod{})
bz, err := cfg.Codec.MarshalJSON(genesisState)
require.NoError(t, err)
cfg.GenesisState["gov"] = bz
Expand Down
5 changes: 3 additions & 2 deletions x/gov/client/testutil/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func (s *IntegrationTestSuite) TestCmdParams() {
{
"json output",
[]string{fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
`{"voting_params":{"voting_period":"172800000000000"},"tally_params":{"quorum":"0.334000000000000000","threshold":"0.500000000000000000","veto_threshold":"0.334000000000000000"},"deposit_params":{"min_deposit":[{"denom":"stake","amount":"10000000"}],"max_deposit_period":"172800000000000"}}`,
`{"voting_params":{"voting_period":"172800000000000","proposal_voting_periods":null},"tally_params":{"quorum":"0.334000000000000000","threshold":"0.500000000000000000","veto_threshold":"0.334000000000000000"},"deposit_params":{"min_deposit":[{"denom":"stake","amount":"10000000"}],"max_deposit_period":"172800000000000"}}`,
},
{
"text output",
Expand All @@ -104,6 +104,7 @@ tally_params:
threshold: "0.500000000000000000"
veto_threshold: "0.334000000000000000"
voting_params:
proposal_voting_periods: null
voting_period: "172800000000000"
`,
},
Expand Down Expand Up @@ -137,7 +138,7 @@ func (s *IntegrationTestSuite) TestCmdParam() {
"voting",
fmt.Sprintf("--%s=json", tmcli.OutputFlag),
},
`{"voting_period":"172800000000000"}`,
`{"voting_period":"172800000000000","proposal_voting_periods":null}`,
},
{
"tally params",
Expand Down
2 changes: 1 addition & 1 deletion x/gov/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -505,7 +505,7 @@ func (suite *KeeperTestSuite) TestGRPCQueryParams() {
if testCase.expPass {
suite.Require().NoError(err)
suite.Require().Equal(expRes.GetDepositParams(), params.GetDepositParams())
suite.Require().Equal(expRes.GetVotingParams(), params.GetVotingParams())
suite.Require().True(expRes.GetVotingParams().Equal(params.GetVotingParams()))
suite.Require().Equal(expRes.GetTallyParams(), params.GetTallyParams())
} else {
suite.Require().Error(err)
Expand Down
5 changes: 5 additions & 0 deletions x/gov/keeper/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ func (keeper Keeper) GetDepositParams(ctx sdk.Context) types.DepositParams {
func (keeper Keeper) GetVotingParams(ctx sdk.Context) types.VotingParams {
var votingParams types.VotingParams
keeper.paramSpace.Get(ctx, types.ParamStoreKeyVotingParams, &votingParams)

if votingParams.ProposalVotingPeriods == nil {
votingParams.ProposalVotingPeriods = []types.ProposalVotingPeriod{}
}

return votingParams
}

Expand Down
32 changes: 30 additions & 2 deletions x/gov/keeper/proposal.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ package keeper

import (
"fmt"
"github.com/gogo/protobuf/proto"
"strings"
"time"

"github.com/cosmos/cosmos-sdk/client"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -183,17 +186,42 @@ func (keeper Keeper) SetProposalID(ctx sdk.Context, proposalID uint64) {
store.Set(types.ProposalIDKey, types.GetProposalIDBytes(proposalID))
}

// ActivateVotingPeriod moves the governance proposal from the deposit stage to
// the voting stage, given that enough deposits have been submitted. It is
// removed from the inactive proposal queue and moved into the active queue.
// Note, if the proposal's contents has a custom voting period registered, that
// voting period is used instead of the base voting period.
func (keeper Keeper) ActivateVotingPeriod(ctx sdk.Context, proposal types.Proposal) {
proposal.VotingStartTime = ctx.BlockHeader().Time
votingPeriod := keeper.GetVotingParams(ctx).VotingPeriod
proposal.VotingEndTime = proposal.VotingStartTime.Add(votingPeriod)
proposal.Status = types.StatusVotingPeriod

votingPeriod := keeper.GetVotingPeriod(ctx, proposal.GetContent())
proposal.VotingEndTime = proposal.VotingStartTime.Add(votingPeriod)

keeper.SetProposal(ctx, proposal)

keeper.RemoveFromInactiveProposalQueue(ctx, proposal.ProposalId, proposal.DepositEndTime)
keeper.InsertActiveProposalQueue(ctx, proposal.ProposalId, proposal.VotingEndTime)
}

// GetVotingPeriod returns the voting period for the given proposal Content. If
// the proposal type has a custom voting period registered, we return that.
// Otherwise, we use the default voting period.
func (keeper Keeper) GetVotingPeriod(ctx sdk.Context, content types.Content) time.Duration {
vpParams := keeper.GetVotingParams(ctx)

// Check if there exists a registered custom voting period for the proposal
// type.
for _, pvp := range vpParams.ProposalVotingPeriods {
contentProto, ok := content.(proto.Message)
if ok && strings.EqualFold(pvp.ProposalType, proto.MessageName(contentProto)) {
return pvp.VotingPeriod
}
}

return vpParams.VotingPeriod
}

func (keeper Keeper) MarshalProposal(proposal types.Proposal) ([]byte, error) {
bz, err := keeper.cdc.Marshal(&proposal)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions x/gov/legacy/v040/migrate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ func TestMigrate(t *testing.T) {
},
"votes": [],
"voting_params": {
"proposal_voting_periods": [],
"voting_period": "0s"
}
}`
Expand Down
1 change: 1 addition & 0 deletions x/gov/legacy/v043/json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ func TestMigrateJSON(t *testing.T) {
}
],
"voting_params": {
"proposal_voting_periods": [],
"voting_period": "0s"
}
}`
Expand Down
17 changes: 16 additions & 1 deletion x/gov/simulation/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,25 @@ func RandomizedGenState(simState *module.SimulationState) {
func(r *rand.Rand) { veto = GenTallyParamsVeto(r) },
)

proposalVotingPeriods := []types.ProposalVotingPeriod{
{
ProposalType: "cosmos.params.v1beta1.ParameterChangeProposal",
},
}
for _, pvp := range proposalVotingPeriods {
var pvpDuration time.Duration
simState.AppParams.GetOrGenerate(
simState.Cdc, VotingParamsVotingPeriod, &pvpDuration, simState.Rand,
func(r *rand.Rand) { pvpDuration = GenVotingParamsVotingPeriod(r) },
)

pvp.VotingPeriod = pvpDuration
}

govGenesis := types.NewGenesisState(
startingProposalID,
types.NewDepositParams(minDeposit, depositPeriod),
types.NewVotingParams(votingPeriod),
types.NewVotingParams(votingPeriod, proposalVotingPeriods),
types.NewTallyParams(quorum, threshold, veto),
)

Expand Down
Loading

0 comments on commit 379239e

Please sign in to comment.