Update committee spec (#981)

* concepts

* messages

* events

* begin block

* address revisions

Co-authored-by: karzak <kjydavis3@gmail.com>
This commit is contained in:
Denali Marsh 2021-08-10 15:46:49 +02:00 committed by GitHub
parent 69cd624e97
commit b72815387a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 90 additions and 30 deletions

View File

@ -6,4 +6,6 @@ order: 1
For a general introduction to governance using the Comsos-SDK, see [x/gov](https://github.com/cosmos/cosmos-sdk/blob/v0.38.3/x/gov/spec/01_concepts.md). For a general introduction to governance using the Comsos-SDK, see [x/gov](https://github.com/cosmos/cosmos-sdk/blob/v0.38.3/x/gov/spec/01_concepts.md).
This module provides companion governance functionality to `x/gov` by allowing the creation of committees, or groups of addresses that can vote on proposals for which they have permission and which bypass the usual on-chain governance structures. Permissions scope the types of proposals that committees can submit and vote on. This allows for committees with unlimited breadth (ie, a committee can have permission to perform any governance action), or narrowly scoped abilities (ie, a committee can only change a single parameter of a single module within a specified range). Further, vote tallying is "first-past-the-post", so proposals can be enacted more rapidly and with greater flexibility than permitted by `x/gov`. This module provides companion governance functionality to `x/gov` by allowing the creation of committees, or groups of addresses that can vote on proposals for which they have permission and which bypass the usual on-chain governance structures. Permissions scope the types of proposals that committees can submit and vote on. This allows for committees with unlimited breadth (ie, a committee can have permission to perform any governance action), or narrowly scoped abilities (ie, a committee can only change a single parameter of a single module within a specified range).
Committees are either member committees governed by a set of whitelisted addresses or token committees whose votes are weighted by token balance. For example, the [Kava Stability Committee](https://medium.com/kava-labs/kava-improves-governance-enabling-faster-response-to-volatile-markets-2d0fff6e5fa9) is a member committee that has the ability to protect critical protocol infrastructure by briefly pausing certain functionality; while the Hard Token Committee allows HARD token holders to participate in governance related to HARD protocol on the Kava blockchain. Further, committees can tally votes by either the "first-past-the-post" or "deadline" tallying procedure. Committees with "first-past-the-post" vote tallying enact proposals immediately once they pass, allowing greater flexibility than permitted by `x/gov`. Committees with "deadline" vote tallying evaluate proposals at their deadline, allowing time for all stakeholders to vote before a proposal is enacted or rejected.

View File

@ -18,6 +18,61 @@ order: 2
} }
``` ```
## Committees
Each committee conforms to the `Committee` interface and is defined as either a `MemberCommittee` or a `TokenCommittee`:
```go
// Committee is an interface for handling common actions on committees
type Committee interface {
GetID() uint64
GetType() string
GetDescription() string
GetMembers() []sdk.AccAddress
SetMembers([]sdk.AccAddress) BaseCommittee
HasMember(addr sdk.AccAddress) bool
GetPermissions() []Permission
SetPermissions([]Permission) Committee
HasPermissionsFor(ctx sdk.Context, appCdc *codec.Codec, pk ParamKeeper, proposal PubProposal) bool
GetProposalDuration() time.Duration
SetProposalDuration(time.Duration) BaseCommittee
GetVoteThreshold() sdk.Dec
SetVoteThreshold(sdk.Dec) BaseCommittee
GetTallyOption() TallyOption
Validate() error
}
// BaseCommittee is a common type shared by all Committees
type BaseCommittee struct {
ID uint64 `json:"id" yaml:"id"`
Description string `json:"description" yaml:"description"`
Members []sdk.AccAddress `json:"members" yaml:"members"`
Permissions []Permission `json:"permissions" yaml:"permissions"`
VoteThreshold sdk.Dec `json:"vote_threshold" yaml:"vote_threshold"` // Smallest percentage that must vote for a proposal to pass
ProposalDuration time.Duration `json:"proposal_duration" yaml:"proposal_duration"` // The length of time a proposal remains active for. Proposals will close earlier if they get enough votes.
TallyOption TallyOption `json:"tally_option" yaml:"tally_option"`
}
// MemberCommittee is an alias of BaseCommittee
type MemberCommittee struct {
BaseCommittee `json:"base_committee" yaml:"base_committee"`
}
// TokenCommittee supports voting on proposals by token holders
type TokenCommittee struct {
BaseCommittee `json:"base_committee" yaml:"base_committee"`
Quorum sdk.Dec `json:"quorum" yaml:"quorum"`
TallyDenom string `json:"tally_denom" yaml:"tally_denom"`
}
```
## Store ## Store
For complete implementation details for how items are stored, see [keys.go](../types/keys.go). The committee module store state consists of committees, proposals, and votes. When a proposal expires or passes, the proposal and associated votes are deleted from state. For complete implementation details for how items are stored, see [keys.go](../types/keys.go). The committee module store state consists of committees, proposals, and votes. When a proposal expires or passes, the proposal and associated votes are deleted from state.

View File

@ -17,22 +17,23 @@ type MsgSubmitProposal struct {
## State Modifications ## State Modifications
* Generate new `ProposalID` - Generate new `ProposalID`
* Create new `Proposal` with deadline equal to the time that the proposal will expire. - Create new `Proposal` with deadline equal to the time that the proposal will expire.
Committee members vote 'yes' on a proposal using a `MsgVote` Valid votes include 'yes', 'no', and 'abstain'.
```go ```go
// MsgVote is submitted by committee members to vote on proposals. // MsgVote is submitted by committee members to vote on proposals.
type MsgVote struct { type MsgVote struct {
ProposalID uint64 `json:"proposal_id" yaml:"proposal_id"` ProposalID uint64 `json:"proposal_id" yaml:"proposal_id"`
Voter sdk.AccAddress `json:"voter" yaml:"voter"` Voter sdk.AccAddress `json:"voter" yaml:"voter"`
VoteType VoteType `json:"vote_type" yaml:"vote_type"`
} }
``` ```
## State Modifications ## State Modifications
* Create a new `Vote` - Create a new `Vote`
* If the proposal is over the threshold: - When the proposal is evaluated:
* Enact the proposal (proposals may cause state modifications) - Enact the proposal (passed proposals may cause state modifications)
* Delete the proposal and associated votes - Delete the proposal and associated votes

View File

@ -8,27 +8,29 @@ The `x/committee` module emits the following events:
## MsgSubmitProposal ## MsgSubmitProposal
| Type | Attribute Key | Attribute Value | | Type | Attribute Key | Attribute Value |
|----------------------|---------------------|--------------------| | --------------- | ------------- | ------------------ |
| proposal_submit | committee_id | {'committee ID}' | | proposal_submit | committee_id | {'committee ID}' |
| proposal_submit | proposal_id | {'proposal ID}' | | proposal_submit | proposal_id | {'proposal ID}' |
| message | module | committee | | message | module | committee |
| message | sender | {'sender address}' | | message | sender | {'sender address}' |
## MsgVote ## MsgVote
| Type | Attribute Key | Attribute Value | | Type | Attribute Key | Attribute Value |
|----------------------|---------------------|--------------------| | ------------- | ------------- | ------------------ |
| proposal_vote | committee_id | {'committee ID}' | | proposal_vote | committee_id | {'committee ID}' |
| proposal_vote | proposal_id | {'proposal ID}' | | proposal_vote | proposal_id | {'proposal ID}' |
| proposal_vote | voter | {'voter address}' | | proposal_vote | voter | {'voter address}' |
| message | module | committee | | proposal_vote | vote | {'vote type}' |
| message | sender | {'sender address}' | | message | module | committee |
| message | sender | {'sender address}' |
## BeginBlock ## BeginBlock
| Type | Attribute Key | Attribute Value | | Type | Attribute Key | Attribute Value |
|----------------------|---------------------|--------------------| | -------------- | ---------------- | ----------------------- |
| proposal_close | committee_id | {'committee ID}' | | proposal_close | committee_id | {'committee ID}' |
| proposal_close | proposal_id | {'proposal ID}' | | proposal_close | proposal_id | {'proposal ID}' |
| proposal_close | status | {'outcome}' | | proposal_close | proposal_tally | {'proposal vote tally}' |
| proposal_close | proposal_outcome | {'proposal result}' |

View File

@ -4,11 +4,11 @@ order: 6
# Begin Block # Begin Block
At the start of each block, expired proposals are deleted. The logic is as follows: At the start of each block, proposals are processed. Active proposals with "first-past-the-post" vote tallying are evaluated and if they meet quorum and voting threshold requirements are enacted, resulting in the deletion of the proposal and any associated votes. If a "first-past-the-post" proposal doesn't meet quorum and voting threshold requirements by its deadline it is not enacted and is deleted. Proposals with "deadline" vote tallying are evaluated at their deadline before being deleted.
```go ```go
// BeginBlocker runs at the start of every block. // BeginBlocker runs at the start of every block.
func BeginBlocker(ctx sdk.Context, _ abci.RequestBeginBlock, k Keeper) { func BeginBlocker(ctx sdk.Context, _ abci.RequestBeginBlock, k Keeper) {
k.CloseExpiredProposals(ctx) k.ProcessProposals(ctx)
} }
``` ```