Skip to content

Commit

Permalink
feat: custom gov (#5)
Browse files Browse the repository at this point in the history
* feat: custom proposal-based voting periods (#1)

h/t osmosis-labs#239

* feat: expedited proposals (#2)

* feat: expedited proposals

h/t osmosis-labs#240

* fix: correctly generate random threshold params

* fix: update randomised genesis state tests

* feat: allow protocol stakers and delegators to vote (#3)

* feat: expedited deposits (#4)

h/t osmosis-labs#254

* fix: still include custom voting periods

* fix: fallback to custom voting periods
  • Loading branch information
johnletey authored Jun 27, 2022
1 parent a2761bd commit b295ae1
Show file tree
Hide file tree
Showing 59 changed files with 1,873 additions and 522 deletions.
26 changes: 25 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 @@ -5086,6 +5087,7 @@ DepositParams defines the params for deposits on governance proposals.
| ----- | ---- | ----- | ----------- |
| `min_deposit` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | Minimum deposit for a proposal to enter voting period. |
| `max_deposit_period` | [google.protobuf.Duration](#google.protobuf.Duration) | | Maximum period for Atom holders to deposit on a proposal. Initial value: 2 months. |
| `min_expedited_deposit` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | Minimum expedited deposit for a proposal to enter voting period. |



Expand All @@ -5109,6 +5111,24 @@ Proposal defines the core field members of a governance proposal.
| `total_deposit` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | |
| `voting_start_time` | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | |
| `voting_end_time` | [google.protobuf.Timestamp](#google.protobuf.Timestamp) | | |
| `is_expedited` | [bool](#bool) | | |






<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) | | |



Expand All @@ -5126,6 +5146,7 @@ TallyParams defines the params for tallying votes on governance proposals.
| `quorum` | [bytes](#bytes) | | Minimum percentage of total stake needed to vote for a result to be considered valid. |
| `threshold` | [bytes](#bytes) | | Minimum proportion of Yes votes for proposal to pass. Default value: 0.5. |
| `veto_threshold` | [bytes](#bytes) | | Minimum value of Veto votes to Total votes ratio for proposal to be vetoed. Default value: 1/3. |
| `expedited_threshold` | [bytes](#bytes) | | Minimum proportion of Yes votes for an expedited proposal to pass. Default value: 0.67. |



Expand Down Expand Up @@ -5194,7 +5215,9 @@ 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. |
| `expedited_voting_period` | [google.protobuf.Duration](#google.protobuf.Duration) | | expedited_voting_period defines the length of the expedited voting period. |



Expand Down Expand Up @@ -5628,6 +5651,7 @@ proposal Content.
| `content` | [google.protobuf.Any](#google.protobuf.Any) | | |
| `initial_deposit` | [cosmos.base.v1beta1.Coin](#cosmos.base.v1beta1.Coin) | repeated | |
| `proposer` | [string](#string) | | |
| `is_expedited` | [bool](#bool) | | |



Expand Down
41 changes: 40 additions & 1 deletion proto/cosmos/gov/v1beta1/gov.proto
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ message Proposal {
[(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"voting_start_time\""];
google.protobuf.Timestamp voting_end_time = 9
[(gogoproto.stdtime) = true, (gogoproto.nullable) = false, (gogoproto.moretags) = "yaml:\"voting_end_time\""];
bool is_expedited = 10;
}

// ProposalStatus enumerates the valid statuses of a proposal.
Expand Down Expand Up @@ -159,17 +160,36 @@ message DepositParams {
(gogoproto.jsontag) = "max_deposit_period,omitempty",
(gogoproto.moretags) = "yaml:\"max_deposit_period\""
];

// Minimum expedited deposit for a proposal to enter voting period.
repeated cosmos.base.v1beta1.Coin min_expedited_deposit = 3 [
(gogoproto.nullable) = false,
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins",
(gogoproto.moretags) = "yaml:\"min_expedited_deposit\"",
(gogoproto.jsontag) = "min_expedited_deposit,omitempty"
];
}

// 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];

// expedited_voting_period defines the length of the expedited voting period.
google.protobuf.Duration expedited_voting_period = 3 [
(gogoproto.nullable) = false,
(gogoproto.stdduration) = true,
(gogoproto.jsontag) = "expedited_voting_period,omitempty",
(gogoproto.moretags) = "yaml:\"expedited_voting_period\""
];
}

// TallyParams defines the params for tallying votes on governance proposals.
Expand Down Expand Up @@ -197,4 +217,23 @@ message TallyParams {
(gogoproto.jsontag) = "veto_threshold,omitempty",
(gogoproto.moretags) = "yaml:\"veto_threshold\""
];

// Minimum proportion of Yes votes for an expedited proposal to pass. Default value: 0.67.
bytes expedited_threshold = 4 [
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false,
(gogoproto.jsontag) = "expedited_threshold,omitempty"
];
}

// 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 proto/cosmos/gov/v1beta1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ message MsgSubmitProposal {
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.Coins",
(gogoproto.moretags) = "yaml:\"initial_deposit\""
];
string proposer = 3;
string proposer = 3;
bool is_expedited = 4;
}

// MsgSubmitProposalResponse defines the Msg/SubmitProposal response type.
Expand Down
2 changes: 1 addition & 1 deletion simapp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ func NewSimApp(
AddRoute(upgradetypes.RouterKey, upgrade.NewSoftwareUpgradeProposalHandler(app.UpgradeKeeper))
govKeeper := govkeeper.NewKeeper(
appCodec, keys[govtypes.StoreKey], app.GetSubspace(govtypes.ModuleName), app.AccountKeeper, app.BankKeeper,
&stakingKeeper, govRouter,
&stakingKeeper, nil, govRouter,
)

app.GovKeeper = *govKeeper.SetHooks(
Expand Down
12 changes: 10 additions & 2 deletions x/distribution/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
var (
FlagCommission = "commission"
FlagMaxMessagesPerTx = "max-msgs"
FlagIsExpedited = "is-expedited"
)

const (
Expand Down Expand Up @@ -279,7 +280,7 @@ func GetCmdSubmitProposal() *cobra.Command {
The proposal details must be supplied via a JSON file.
Example:
$ %s tx gov submit-proposal community-pool-spend <path/to/proposal.json> --from=<key_or_address>
$ %s tx gov submit-proposal community-pool-spend <path/to/proposal.json> --from=<key_or_address> --is-expedited=false
Where proposal.json contains:
Expand Down Expand Up @@ -321,7 +322,12 @@ Where proposal.json contains:
}
content := types.NewCommunityPoolSpendProposal(proposal.Title, proposal.Description, recpAddr, amount)

msg, err := govtypes.NewMsgSubmitProposal(content, deposit, from)
isExpedited, err := cmd.Flags().GetBool(FlagIsExpedited)
if err != nil {
return err
}

msg, err := govtypes.NewMsgSubmitProposal(content, deposit, from, isExpedited)
if err != nil {
return err
}
Expand All @@ -330,5 +336,7 @@ Where proposal.json contains:
},
}

cmd.Flags().Bool(FlagIsExpedited, false, "If true, makes the proposal an expedited one")

return cmd
}
2 changes: 1 addition & 1 deletion x/distribution/client/rest/rest.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func postProposalHandlerFn(clientCtx client.Context) http.HandlerFunc {

content := types.NewCommunityPoolSpendProposal(req.Title, req.Description, req.Recipient, req.Amount)

msg, err := govtypes.NewMsgSubmitProposal(content, req.Deposit, req.Proposer)
msg, err := govtypes.NewMsgSubmitProposal(content, req.Deposit, req.Proposer, req.IsExpedited)
if rest.CheckBadRequestError(w, err) {
return
}
Expand Down
1 change: 1 addition & 0 deletions x/distribution/client/rest/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type (

Title string `json:"title" yaml:"title"`
Description string `json:"description" yaml:"description"`
IsExpedited bool `json:"is_expedited" yaml:"is_expedited"`
Recipient sdk.AccAddress `json:"recipient" yaml:"recipient"`
Amount sdk.Coins `json:"amount" yaml:"amount"`
Proposer sdk.AccAddress `json:"proposer" yaml:"proposer"`
Expand Down
44 changes: 34 additions & 10 deletions x/gov/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ func EndBlocker(ctx sdk.Context, keeper keeper.Keeper) {
logger.Info(
"proposal did not meet minimum deposit; deleted",
"proposal", proposal.ProposalId,
"is_expedited", proposal.IsExpedited,
"title", proposal.GetTitle(),
"min_deposit", keeper.GetDepositParams(ctx).MinDeposit.String(),
"min_deposit", proposal.GetMinDepositFromParams(keeper.GetDepositParams(ctx)).String(),
"total_deposit", proposal.TotalDeposit.String(),
)

Expand All @@ -49,12 +50,20 @@ func EndBlocker(ctx sdk.Context, keeper keeper.Keeper) {

passes, burnDeposits, tallyResults := keeper.Tally(ctx, proposal)

if burnDeposits {
keeper.DeleteDeposits(ctx, proposal.ProposalId)
} else {
keeper.RefundDeposits(ctx, proposal.ProposalId)
// If an expedited proposal fails, we do not want to update
// the deposit at this point since the proposal is converted to regular.
// As a result, the deposits are either deleted or refunded in all cases
// EXCEPT when an expedited proposal fails.
if !(proposal.IsExpedited && !passes) {
if burnDeposits {
keeper.DeleteDeposits(ctx, proposal.ProposalId)
} else {
keeper.RefundDeposits(ctx, proposal.ProposalId)
}
}

keeper.RemoveFromActiveProposalQueue(ctx, proposal.ProposalId, proposal.VotingEndTime)

if passes {
handler := keeper.Router().GetRoute(proposal.ProposalRoute())
cacheCtx, writeCache := ctx.CacheContext()
Expand Down Expand Up @@ -82,15 +91,30 @@ func EndBlocker(ctx sdk.Context, keeper keeper.Keeper) {
logMsg = fmt.Sprintf("passed, but failed on execution: %s", err)
}
} else {
proposal.Status = types.StatusRejected
tagValue = types.AttributeValueProposalRejected
logMsg = "rejected"
if proposal.IsExpedited {
// When expedited proposal fails, it is converted
// to a regular proposal. As a result, the voting period is extended, and,
// once the regular voting period expires again, the tally is repeated
// according to the regular proposal rules.
proposal.IsExpedited = false
votingPeriod := keeper.GetVotingPeriod(ctx, proposal.GetContent(), proposal.IsExpedited)
proposal.VotingEndTime = proposal.VotingStartTime.Add(votingPeriod)

keeper.InsertActiveProposalQueue(ctx, proposal.ProposalId, proposal.VotingEndTime)

tagValue = types.AttributeValueExpeditedProposalRejected
logMsg = "expedited proposal converted to regular"
} else {
// When regular proposal fails, it is rejected and
// the proposal with that id is done forever.
proposal.Status = types.StatusRejected
tagValue = types.AttributeValueProposalRejected
logMsg = "rejected"
}
}

proposal.FinalTallyResult = tallyResults

keeper.SetProposal(ctx, proposal)
keeper.RemoveFromActiveProposalQueue(ctx, proposal.ProposalId, proposal.VotingEndTime)

// when proposal become active
keeper.AfterProposalVotingPeriodEnded(ctx, proposal.ProposalId)
Expand Down
Loading

0 comments on commit b295ae1

Please sign in to comment.