diff --git a/x/committee/spec/01_concepts.md b/x/committee/spec/01_concepts.md new file mode 100644 index 00000000..d19d6ae5 --- /dev/null +++ b/x/committee/spec/01_concepts.md @@ -0,0 +1,5 @@ +# Concepts + +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`. diff --git a/x/committee/spec/02_state.md b/x/committee/spec/02_state.md new file mode 100644 index 00000000..362fb2bc --- /dev/null +++ b/x/committee/spec/02_state.md @@ -0,0 +1,19 @@ +# State + +## Genesis state + +`GenesisState` defines the state that must be persisted when the blockchain stops/restarts in order for normal function of the committee module to resume. + +```go +// GenesisState is state that must be provided at chain genesis. + type GenesisState struct { + NextProposalID uint64 `json:"next_proposal_id" yaml:"next_proposal_id"` + Committees []Committee `json:"committees" yaml:"committees"` + Proposals []Proposal `json:"proposals" yaml:"proposals"` + Votes []Vote `json:"votes" yaml:"votes"` + } +``` + +## 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. diff --git a/x/committee/spec/03_messages.md b/x/committee/spec/03_messages.md new file mode 100644 index 00000000..2db9cf5a --- /dev/null +++ b/x/committee/spec/03_messages.md @@ -0,0 +1,34 @@ +# Messages + +Committee members submit proposals using a `MsgSubmitProposal` + +```go +// MsgSubmitProposal is used by committee members to create a new proposal that they can vote on. +type MsgSubmitProposal struct { + PubProposal PubProposal `json:"pub_proposal" yaml:"pub_proposal"` + Proposer sdk.AccAddress `json:"proposer" yaml:"proposer"` + CommitteeID uint64 `json:"committee_id" yaml:"committee_id"` +} +``` + +## State Modifications + +* Generate new `ProposalID` +* Create new `Proposal` with deadline equal to the time that the proposal will expire. + +Committee members vote 'yes' on a proposal using a `MsgVote` + +```go +// MsgVote is submitted by committee members to vote on proposals. +type MsgVote struct { + ProposalID uint64 `json:"proposal_id" yaml:"proposal_id"` + Voter sdk.AccAddress `json:"voter" yaml:"voter"` +} +``` + +## State Modifications + +* Create a new `Vote` +* If the proposal is over the threshold: + * Enact the proposal (proposals may cause state modifications) + * Delete the proposal and associated votes \ No newline at end of file diff --git a/x/committee/spec/04_events.md b/x/committee/spec/04_events.md new file mode 100644 index 00000000..0e31e71d --- /dev/null +++ b/x/committee/spec/04_events.md @@ -0,0 +1,33 @@ +# Events + +The `x/committee` module emits the following events: + +## MsgSubmitProposal + +| Type | Attribute Key | Attribute Value | +|----------------------|---------------------|--------------------| +| proposal_submit | committee_id | {committee ID} | +| proposal_submit | proposal_id | {proposal ID} | +| message | module | committee | +| message | sender | {sender address} | + +## MsgVote + +| Type | Attribute Key | Attribute Value | +|----------------------|---------------------|--------------------| +| proposal_vote | committee_id | {committee ID} | +| proposal_vote | proposal_id | {proposal ID} | +| proposal_vote | voter | {voter address} | +| proposal_close | committee_id | {committee ID} | +| proposal_close | proposal_id | {proposal ID} | +| proposal_close | status | {outcome} | +| message | module | committee | +| message | sender | {sender address} | + +## BeginBlock + +| Type | Attribute Key | Attribute Value | +|----------------------|---------------------|--------------------| +| proposal_close | committee_id | {committee ID} | +| proposal_close | proposal_id | {proposal ID} | +| proposal_close | status | proposal_timeout | diff --git a/x/committee/spec/05_params.md b/x/committee/spec/05_params.md new file mode 100644 index 00000000..9785d7f9 --- /dev/null +++ b/x/committee/spec/05_params.md @@ -0,0 +1,3 @@ +# Parameters + +The committee module has no parameters. Committees are created using the `x/gov` module and and inherit the parameters controlling governance proposals from `x/gov`. diff --git a/x/committee/spec/06_begin_block.md b/x/committee/spec/06_begin_block.md new file mode 100644 index 00000000..4e4e602d --- /dev/null +++ b/x/committee/spec/06_begin_block.md @@ -0,0 +1,10 @@ +# Begin Block + +At the start of each block, expired proposals are deleted. The logic is as follows: + +```go +// BeginBlocker runs at the start of every block. +func BeginBlocker(ctx sdk.Context, _ abci.RequestBeginBlock, k Keeper) { + k.CloseExpiredProposals(ctx) +} +``` diff --git a/x/committee/spec/README.md b/x/committee/spec/README.md index bcde3f69..fa9b3dff 100644 --- a/x/committee/spec/README.md +++ b/x/committee/spec/README.md @@ -3,17 +3,25 @@ ## Table of Contents + +1. **[Concepts](01_concepts.md)** +2. **[State](02_state.md)** +3. **[Messages](03_messages.md)** +4. **[Events](04_events.md)** +5. **[Params](05_params.md)** +6. **[BeginBlock](06_begin_block.md)** + ## Overview -The `x/committee` module is an additional governance module to `cosmos-sdk/x/gov`. +The `x/committee` module is Cosmos-SDK module that acts as an additional governance module to `cosmos-sdk/x/gov`. It allows groups of accounts to vote on and enact proposals without a full chain governance vote. Certain proposal types can then be decided on quickly in emergency situations, or low risk parameter updates can be delegated to a smaller group of individuals. Committees work with "proposals", using the same type from the `gov` module so they are compatible with all existing proposal types such as param changes, or community pool spend, or text proposals. -Committees have members and permissions. +Committees have members and permissions. Committees are 'elected' via traditional `gov` proposals - ie. all coin-holders vote on the creation, deletion, and updating of committees. -Members vote on proposals, with just simple one vote per member, no deposits or slashing. More sophisticated voting could be added. +Members of committees vote on proposals, with one vote per member and no deposits or slashing. Only a member of a committee can submit a proposal for that committee. More sophisticated voting could be added, as well as the ability for committees to edit themselves or other committees. A proposal passes when the number of votes is over the threshold for that committee. Vote thresholds are set per committee. Committee members vote yes by casting a vote and vote no by abstaining from voting and letting the proposal expire. Permissions scope the allowed set of proposals a committee can enact. For example: @@ -21,6 +29,4 @@ Permissions scope the allowed set of proposals a committee can enact. For exampl - allow the committee to change auction bid increments, but only within the range [0, 0.1] - allow the committee to only disable cdp msg types, but not staking or gov -A permission acts as a filter for incoming gov proposals, rejecting them if they do not pass. A permission can be any type with a method `Allows(p Proposal) bool`. They reject all proposals that they don't explicitly allow. - -This allows permissions to be parameterized to allow fine grained control specified at runtime. For example a generic parameter permission type can allow a committee to only change a particular param, or only change params within a certain percentage. +A permission acts as a filter for incoming gov proposals, rejecting them at the handler if they do not have the required permissions. A permission can be any type with a method `Allows(p Proposal) bool`. The handler will reject all proposals that are not explicitly allowed. This allows permissions to be parameterized to allow fine grained control specified at runtime. For example a generic parameter permission type can allow a committee to only change a particular param, or only change params within a certain range.