From 02633ab91173d2d56481a387881a142c18e43bb9 Mon Sep 17 00:00:00 2001 From: blushi Date: Fri, 9 Apr 2021 11:49:06 +0200 Subject: [PATCH 01/27] Add ADR-042 --- docs/architecture/adr-042-group-module.md | 375 ++++++++++++++++++++++ 1 file changed, 375 insertions(+) create mode 100644 docs/architecture/adr-042-group-module.md diff --git a/docs/architecture/adr-042-group-module.md b/docs/architecture/adr-042-group-module.md new file mode 100644 index 000000000000..43e60c520ebe --- /dev/null +++ b/docs/architecture/adr-042-group-module.md @@ -0,0 +1,375 @@ +# ADR 042: Group Module + +## Changelog + +- 2020/04/09: Initial Draft + +## Status + +Draft + +## Abstract + +This ADR defines the `x/group` module which allows the creation and management of on-chain multi-signature accounts and enables voting for message execution based on configurable decision policies. + +## Context + +The current multi-signature mechanism of the Cosmos SDK has certain limitations: +- Key rotation is not possible, although this can be solved with [account rekeying](adr-034-account-rekeying.md). +- Thresholds can't be changed. +- UX is not straightforward for non-technical users (#5661). +- It requires `legacy_amino` sign mode (#8141). + +While the group module is not meant to be a total replacement for the current multi-signature accounts, it provides a solution to the limitations described above, with a more flexible key management system where keys can be added, updated or removed, as well as configurable thresholds. +It's meant to be used with other key management modules such as [`x/feegrant`](./adr-029-fee-grant-module.md) ans [`x/authz`](adr-030-authz-module.md) to simplify key management for individuals and organizations. + +The current implementation of the group module can be found in https://github.com/regen-network/regen-ledger/tree/master/proto/regen/group/v1alpha1 and https://github.com/regen-network/regen-ledger/tree/master/x/group + +## Decision + +We propose merging the `x/group` module with its supporting [ORM/Table Store package](https://github.com/regen-network/regen-ledger/tree/master/orm) (#7098) into the Cosmos SDK and continuing development here. There will be a dedicated ADR for the ORM package. + +### Group + +A group is an aggregation of accounts with associated weights. It is not +an account and doesn't have a balance. It doesn't in and of itself have any +sort of voting or decision weight. It has an `admin` account which can manage members in the group. + +Groups are stored in state as part of an ORM-based `groupTable` using the `GroupInfo` type. The `group_id` is an auto-increment integer. + +```proto +message GroupInfo { + + // group_id is the unique ID of the group. + uint64 group_id = 1; + + // admin is the account address of the group's admin. + string admin = 2; + + // metadata is any arbitrary metadata to attached to the group. + bytes metadata = 3; + + // version is used to track changes to a group's membership structure that + // would break existing proposals. Whenever any members weight is changed, + // or any member is added or removed this version is incremented and will + // cause proposals based on older versions of this group to fail + uint64 version = 4; + + // total_weight is the sum of the group members' weights. + string total_weight = 5; +} +``` + +Group members are stored in a `groupMemberTable` using the `GroupMember` type: + +```proto +message GroupMember { + + // group_id is the unique ID of the group. + uint64 group_id = 1; + + // member is the member data. + Member member = 2; +} + +// Member represents a group member with an account address, +// non-zero weight and metadata. +message Member { + + // address is the member's account address. + string address = 1; + + // weight is the member's voting weight that should be greater than 0. + string weight = 2; + + // metadata is any arbitrary metadata to attached to the member. + bytes metadata = 3; +} +``` + +### Group Account + +A group account is an account associated with a group and a decision policy. +A group account does have a balance. + +Group accounts are abstracted from groups because a single group may have +multiple decision policies for different types of actions. Managing group +membership separately from decision policies results in the least overhead +and keeps membership consistent across different policies. The pattern that +is recommended is to have a single master group account for a given group, +and then to create separate group accounts with different decision policies +and delegate the desired permissions from the master account to +those "sub-accounts" using the [`x/authz` module](adr-030-authz-module.md). + +Group accounts are stored as part of the `groupAccountTable` and modeled by `GroupAccountInfo`. + +```proto +message GroupAccountInfo { + + // address is the group account address. + string address = 1; + + // group_id is the unique ID of the group. + uint64 group_id = 2; + + // admin is the account address of the group admin. + string admin = 3; + + // metadata is any arbitrary metadata to attached to the group account. + bytes metadata = 4; + + // version is used to track changes to a group's GroupAccountInfo structure that + // would create a different result on a running proposal. + uint64 version = 5; + + // decision_policy specifies the group account's decision policy. + google.protobuf.Any decision_policy = 6 [(cosmos_proto.accepts_interface) = "DecisionPolicy"]; +} +``` + +The group account address is generated based on an auto-increment integer which is used to derive the group `RootModuleKey` into a `DerivedModuleKey`, as stated in [ADR-033](adr-033-protobuf-inter-module-comm.md#modulekeys-and-moduleids). The group account is added as a new `ModuleAccount` through `x/auth`. + +### Decision Policy + +A decision policy is the mechanism by which members of a group can vote on +proposals. + +All decision policies generally would have a minimum and maximum voting window. +The minimum voting window is the minimum amount of time that must pass in order +for a proposal to potentially pass, and it may be set to 0. The maximum voting +window is the maximum time that a proposal may be voted on before it is closed. +Both of these values must be less than a chain-wide max voting window parameter. + +We define the `DecisionPolicy` interface that all decision policies must implement: + +```go +type DecisionPolicy interface { + codec.ProtoMarshaler + + ValidateBasic() error + GetTimeout() types.Duration + Allow(tally Tally, totalPower string, votingDuration time.Duration) (DecisionPolicyResult, error) + Validate(g GroupInfo) error +} + +type DecisionPolicyResult struct { + Allow bool + Final bool +} +``` + +#### Threshold decision policy + +A threshold decision policy defines a threshold of yes votes (based on a tally +of voter weights) that must be achieved in order for a proposal to pass. For +this decision policy, abstain and veto are simply treated as no's. + +```proto +message ThresholdDecisionPolicy { + + // threshold is the minimum weighted sum of yes votes that must be met or exceeded for a proposal to succeed. + string threshold = 1; + + // timeout is the duration from submission of a proposal to the end of voting period + // Within this times votes and exec messages can be submitted. + google.protobuf.Duration timeout = 2 [(gogoproto.nullable) = false]; +} +``` + +### Proposal + +Any member of a group can submit a proposal for a group account to decide upon. +A proposal consists of a set of `sdk.Msg`s that will be executed if the proposal +passes as well as any metadata associated with the proposal. + +Proposals are stored as part of the `proposalTable` using the `Proposal` type. The `proposal_id` is an auto-increment integer. + +```proto +message Proposal { + + // proposal_id is the unique id of the proposal. + uint64 proposal_id = 1; + + // address is the group account address. + string address = 2; + + // metadata is any arbitrary metadata to attached to the proposal. + bytes metadata = 3; + + // proposers are the account addresses of the proposers. + repeated string proposers = 4; + + // submitted_at is a timestamp specifying when a proposal was submitted. + google.protobuf.Timestamp submitted_at = 5 [(gogoproto.nullable) = false]; + + // group_version tracks the version of the group that this proposal corresponds to. + // When group membership is changed, existing proposals from previous group versions will become invalid. + uint64 group_version = 6; + + // group_account_version tracks the version of the group account that this proposal corresponds to. + // When a decision policy is changed, existing proposals from previous policy versions will become invalid. + uint64 group_account_version = 7; + + // Status defines proposal statuses. + enum Status { + option (gogoproto.goproto_enum_prefix) = false; + + // An empty value is invalid and not allowed. + STATUS_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "ProposalStatusInvalid"]; + + // Initial status of a proposal when persisted. + STATUS_SUBMITTED = 1 [(gogoproto.enumvalue_customname) = "ProposalStatusSubmitted"]; + + // Final status of a proposal when the final tally was executed. + STATUS_CLOSED = 2 [(gogoproto.enumvalue_customname) = "ProposalStatusClosed"]; + + // Final status of a proposal when the group was modified before the final tally. + STATUS_ABORTED = 3 [(gogoproto.enumvalue_customname) = "ProposalStatusAborted"]; + } + + // Status represents the high level position in the life cycle of the proposal. Initial value is Submitted. + Status status = 8; + + // Result defines types of proposal results. + enum Result { + option (gogoproto.goproto_enum_prefix) = false; + + // An empty value is invalid and not allowed + RESULT_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "ProposalResultInvalid"]; + + // Until a final tally has happened the status is unfinalized + RESULT_UNFINALIZED = 1 [(gogoproto.enumvalue_customname) = "ProposalResultUnfinalized"]; + + // Final result of the tally + RESULT_ACCEPTED = 2 [(gogoproto.enumvalue_customname) = "ProposalResultAccepted"]; + + // Final result of the tally + RESULT_REJECTED = 3 [(gogoproto.enumvalue_customname) = "ProposalResultRejected"]; + } + + // result is the final result based on the votes and election rule. Initial value is unfinalized. + // The result is persisted so that clients can always rely on this state and not have to replicate the logic. + Result result = 9; + + // vote_state contains the sums of all weighted votes for this proposal. + Tally vote_state = 10 [(gogoproto.nullable) = false]; + + // timeout is the timestamp of the block where the proposal execution times out. Header times of the votes and execution messages + // must be before this end time to be included in the election. After the timeout timestamp the proposal can not be + // executed anymore and should be considered pending delete. + google.protobuf.Timestamp timeout = 11 [(gogoproto.nullable) = false]; + + // ExecutorResult defines types of proposal executor results. + enum ExecutorResult { + option (gogoproto.goproto_enum_prefix) = false; + + // An empty value is not allowed. + EXECUTOR_RESULT_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "ProposalExecutorResultInvalid"]; + + // We have not yet run the executor. + EXECUTOR_RESULT_NOT_RUN = 1 [(gogoproto.enumvalue_customname) = "ProposalExecutorResultNotRun"]; + + // The executor was successful and proposed action updated state. + EXECUTOR_RESULT_SUCCESS = 2 [(gogoproto.enumvalue_customname) = "ProposalExecutorResultSuccess"]; + + // The executor returned an error and proposed action didn't update state. + EXECUTOR_RESULT_FAILURE = 3 [(gogoproto.enumvalue_customname) = "ProposalExecutorResultFailure"]; + } + + // executor_result is the final result based on the votes and election rule. Initial value is NotRun. + ExecutorResult executor_result = 12; + + // msgs is a list of Msgs that will be executed if the proposal passes. + repeated google.protobuf.Any msgs = 13; +} + +// Tally represents the sum of weighted votes. +message Tally { + option (gogoproto.goproto_getters) = false; + + // yes_count is the weighted sum of yes votes. + string yes_count = 1; + + // no_count is the weighted sum of no votes. + string no_count = 2; + + // abstain_count is the weighted sum of abstainers. + string abstain_count = 3; + + // veto_count is the weighted sum of vetoes. + string veto_count = 4; +} +``` + +### Voting + +There are four choices to choose while voting - yes, no, abstain and veto. Not +all decision policies will support them. Votes can contain some optional metadata. +During the voting window, accounts that have already voted may change their vote. +In the current implementation, the voting window begins as soon as a proposal +is submitted. + +Votes are stored in the `voteTable`. + +```proto +message Vote { + + // proposal is the unique ID of the proposal. + uint64 proposal_id = 1; + + // voter is the account address of the voter. + string voter = 2; + + // choice is the voter's choice on the proposal. + Choice choice = 3; + + // metadata is any arbitrary metadata to attached to the vote. + bytes metadata = 4; + + // submitted_at is the timestamp when the vote was submitted. + google.protobuf.Timestamp submitted_at = 5 [(gogoproto.nullable) = false]; +} +``` + +Voting internally updates the proposal `Status` and `Result`. + +### Executing Proposals + +Proposals will not be automatically executed by the chain in this current design, +but rather a user must submit a `Msg/Exec` transaction to attempt to execute the +proposal based on the current votes and decision policy. A future upgrade could +automate this and have the group account (or a fee granter) pay. + +Inter-module communication introduced by [ADR-033](adr-033-protobuf-inter-module-comm.md) will be used to route a proposal's messages using the `DerivedModuleKey` corresponding to the proposal's group account. It can also temporarily support routing of non `ServiceMsg`s through the `sdk.Router` (see #8864). +For these messages to execute successfully, their signer should be set as the group account. + +#### Changing Group Membership + +In the current implementation, updating a group or a group account after submitting a proposal will make it invalid. It will simply fail if someone calls `Msg/Exec` and will eventually be garbage collected. + +## Consequences + +### Positive + +- Improved UX for multi-signature accounts allowing key rotation and custom decision policies. + +### Negative + +### Neutral + +- It uses ADR 033 so it will need to be implemented within the Cosmos SDK, but this doesn't imply necessarily any large refactoring of existing Cosmos SDK modules. +- It requires the ORM package. + +## Further Discussions + +- Convergence of `/group` and `x/gov` as both support proposals and voting: https://github.com/cosmos/cosmos-sdk/discussions/9066 +- `x/group` possible future improvements: + - Execute proposals on submission (https://github.com/regen-network/regen-ledger/issues/288) + - Withdraw a proposal (https://github.com/regen-network/cosmos-modules/issues/41) + +## References + +- Initial specification: + - https://gist.github.com/aaronc/b60628017352df5983791cad30babe56#group-module + - #5236 +- Proposal to add `x/group` into the SDK: #7633 From 2ccc70147a451350891cd82b2a62d46866a10ed4 Mon Sep 17 00:00:00 2001 From: blushi Date: Fri, 9 Apr 2021 12:01:28 +0200 Subject: [PATCH 02/27] Fix link --- docs/architecture/adr-042-group-module.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/architecture/adr-042-group-module.md b/docs/architecture/adr-042-group-module.md index 43e60c520ebe..d5a4f56a8c7c 100644 --- a/docs/architecture/adr-042-group-module.md +++ b/docs/architecture/adr-042-group-module.md @@ -17,8 +17,8 @@ This ADR defines the `x/group` module which allows the creation and management o The current multi-signature mechanism of the Cosmos SDK has certain limitations: - Key rotation is not possible, although this can be solved with [account rekeying](adr-034-account-rekeying.md). - Thresholds can't be changed. -- UX is not straightforward for non-technical users (#5661). -- It requires `legacy_amino` sign mode (#8141). +- UX is not straightforward for non-technical users ([#5661](https://github.com/cosmos/cosmos-sdk/issues/5661)). +- It requires `legacy_amino` sign mode ([#8141](https://github.com/cosmos/cosmos-sdk/issues/8141)). While the group module is not meant to be a total replacement for the current multi-signature accounts, it provides a solution to the limitations described above, with a more flexible key management system where keys can be added, updated or removed, as well as configurable thresholds. It's meant to be used with other key management modules such as [`x/feegrant`](./adr-029-fee-grant-module.md) ans [`x/authz`](adr-030-authz-module.md) to simplify key management for individuals and organizations. @@ -27,7 +27,7 @@ The current implementation of the group module can be found in https://github.co ## Decision -We propose merging the `x/group` module with its supporting [ORM/Table Store package](https://github.com/regen-network/regen-ledger/tree/master/orm) (#7098) into the Cosmos SDK and continuing development here. There will be a dedicated ADR for the ORM package. +We propose merging the `x/group` module with its supporting [ORM/Table Store package](https://github.com/regen-network/regen-ledger/tree/master/orm) ([#7098](https://github.com/cosmos/cosmos-sdk/issues/7098)) into the Cosmos SDK and continuing development here. There will be a dedicated ADR for the ORM package. ### Group @@ -340,7 +340,7 @@ but rather a user must submit a `Msg/Exec` transaction to attempt to execute the proposal based on the current votes and decision policy. A future upgrade could automate this and have the group account (or a fee granter) pay. -Inter-module communication introduced by [ADR-033](adr-033-protobuf-inter-module-comm.md) will be used to route a proposal's messages using the `DerivedModuleKey` corresponding to the proposal's group account. It can also temporarily support routing of non `ServiceMsg`s through the `sdk.Router` (see #8864). +Inter-module communication introduced by [ADR-033](adr-033-protobuf-inter-module-comm.md) will be used to route a proposal's messages using the `DerivedModuleKey` corresponding to the proposal's group account. It can also temporarily support routing of non `ServiceMsg`s through the `sdk.Router` (see [#8864](https://github.com/cosmos/cosmos-sdk/issues/8864)). For these messages to execute successfully, their signer should be set as the group account. #### Changing Group Membership From 217ca1627a9d6fa36ab1be3e1d98c79f7644ae62 Mon Sep 17 00:00:00 2001 From: blushi Date: Fri, 9 Apr 2021 12:18:02 +0200 Subject: [PATCH 03/27] Small improvements --- docs/architecture/adr-042-group-module.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/architecture/adr-042-group-module.md b/docs/architecture/adr-042-group-module.md index d5a4f56a8c7c..c0a6d508695c 100644 --- a/docs/architecture/adr-042-group-module.md +++ b/docs/architecture/adr-042-group-module.md @@ -23,7 +23,7 @@ The current multi-signature mechanism of the Cosmos SDK has certain limitations: While the group module is not meant to be a total replacement for the current multi-signature accounts, it provides a solution to the limitations described above, with a more flexible key management system where keys can be added, updated or removed, as well as configurable thresholds. It's meant to be used with other key management modules such as [`x/feegrant`](./adr-029-fee-grant-module.md) ans [`x/authz`](adr-030-authz-module.md) to simplify key management for individuals and organizations. -The current implementation of the group module can be found in https://github.com/regen-network/regen-ledger/tree/master/proto/regen/group/v1alpha1 and https://github.com/regen-network/regen-ledger/tree/master/x/group +The current implementation of the group module can be found in https://github.com/regen-network/regen-ledger/tree/master/proto/regen/group/v1alpha1 and https://github.com/regen-network/regen-ledger/tree/master/x/group. ## Decision @@ -127,7 +127,7 @@ message GroupAccountInfo { } ``` -The group account address is generated based on an auto-increment integer which is used to derive the group `RootModuleKey` into a `DerivedModuleKey`, as stated in [ADR-033](adr-033-protobuf-inter-module-comm.md#modulekeys-and-moduleids). The group account is added as a new `ModuleAccount` through `x/auth`. +The group account address is generated based on an auto-increment integer which is used to derive the group module `RootModuleKey` into a `DerivedModuleKey`, as stated in [ADR-033](adr-033-protobuf-inter-module-comm.md#modulekeys-and-moduleids). The group account is added as a new `ModuleAccount` through `x/auth`. ### Decision Policy @@ -331,7 +331,7 @@ message Vote { } ``` -Voting internally updates the proposal `Status` and `Result`. +Voting internally updates the proposal `Status` and `Result` if needed. ### Executing Proposals @@ -372,4 +372,4 @@ In the current implementation, updating a group or a group account after submitt - Initial specification: - https://gist.github.com/aaronc/b60628017352df5983791cad30babe56#group-module - #5236 -- Proposal to add `x/group` into the SDK: #7633 +- Proposal to add `x/group` into the SDK: [#7633](https://github.com/cosmos/cosmos-sdk/issues/7633) From 64f87bc88200353fec7fd84adde9b3f7e94c0dc7 Mon Sep 17 00:00:00 2001 From: blushi Date: Fri, 9 Apr 2021 12:19:31 +0200 Subject: [PATCH 04/27] Update link --- docs/architecture/adr-042-group-module.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/adr-042-group-module.md b/docs/architecture/adr-042-group-module.md index c0a6d508695c..865fcad71ea8 100644 --- a/docs/architecture/adr-042-group-module.md +++ b/docs/architecture/adr-042-group-module.md @@ -371,5 +371,5 @@ In the current implementation, updating a group or a group account after submitt - Initial specification: - https://gist.github.com/aaronc/b60628017352df5983791cad30babe56#group-module - - #5236 + - [#5236](https://github.com/cosmos/cosmos-sdk/pull/5236) - Proposal to add `x/group` into the SDK: [#7633](https://github.com/cosmos/cosmos-sdk/issues/7633) From 432b93f645878e437f4662562282e5f8d95ad0bb Mon Sep 17 00:00:00 2001 From: Marie Gauthier Date: Wed, 14 Apr 2021 13:03:06 +0200 Subject: [PATCH 05/27] Update docs/architecture/adr-042-group-module.md Co-authored-by: Robert Zaremba --- docs/architecture/adr-042-group-module.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/adr-042-group-module.md b/docs/architecture/adr-042-group-module.md index 865fcad71ea8..96ad0dbdfd3a 100644 --- a/docs/architecture/adr-042-group-module.md +++ b/docs/architecture/adr-042-group-module.md @@ -14,7 +14,7 @@ This ADR defines the `x/group` module which allows the creation and management o ## Context -The current multi-signature mechanism of the Cosmos SDK has certain limitations: +The legacy amino multi-signature mechanism of the Cosmos SDK has certain limitations: - Key rotation is not possible, although this can be solved with [account rekeying](adr-034-account-rekeying.md). - Thresholds can't be changed. - UX is not straightforward for non-technical users ([#5661](https://github.com/cosmos/cosmos-sdk/issues/5661)). From abe6245c5cadf753175a12dc9f474fee17a86dc6 Mon Sep 17 00:00:00 2001 From: Marie Gauthier Date: Thu, 15 Apr 2021 11:19:15 +0200 Subject: [PATCH 06/27] Update docs/architecture/adr-042-group-module.md --- docs/architecture/adr-042-group-module.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/adr-042-group-module.md b/docs/architecture/adr-042-group-module.md index 96ad0dbdfd3a..84ba19bc126e 100644 --- a/docs/architecture/adr-042-group-module.md +++ b/docs/architecture/adr-042-group-module.md @@ -23,7 +23,7 @@ The legacy amino multi-signature mechanism of the Cosmos SDK has certain limitat While the group module is not meant to be a total replacement for the current multi-signature accounts, it provides a solution to the limitations described above, with a more flexible key management system where keys can be added, updated or removed, as well as configurable thresholds. It's meant to be used with other key management modules such as [`x/feegrant`](./adr-029-fee-grant-module.md) ans [`x/authz`](adr-030-authz-module.md) to simplify key management for individuals and organizations. -The current implementation of the group module can be found in https://github.com/regen-network/regen-ledger/tree/master/proto/regen/group/v1alpha1 and https://github.com/regen-network/regen-ledger/tree/master/x/group. +The proof of concept of the group module can be found in https://github.com/regen-network/regen-ledger/tree/master/proto/regen/group/v1alpha1 and https://github.com/regen-network/regen-ledger/tree/master/x/group. ## Decision From 08dcd47a66b69107f85d8eb4c72fee3cad96209e Mon Sep 17 00:00:00 2001 From: Marie Gauthier Date: Thu, 15 Apr 2021 13:58:40 +0200 Subject: [PATCH 07/27] Update docs/architecture/adr-042-group-module.md --- docs/architecture/adr-042-group-module.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/adr-042-group-module.md b/docs/architecture/adr-042-group-module.md index 84ba19bc126e..fbc96738baea 100644 --- a/docs/architecture/adr-042-group-module.md +++ b/docs/architecture/adr-042-group-module.md @@ -17,7 +17,7 @@ This ADR defines the `x/group` module which allows the creation and management o The legacy amino multi-signature mechanism of the Cosmos SDK has certain limitations: - Key rotation is not possible, although this can be solved with [account rekeying](adr-034-account-rekeying.md). - Thresholds can't be changed. -- UX is not straightforward for non-technical users ([#5661](https://github.com/cosmos/cosmos-sdk/issues/5661)). +- UX is cumbersome for non-technical users ([#5661](https://github.com/cosmos/cosmos-sdk/issues/5661)). - It requires `legacy_amino` sign mode ([#8141](https://github.com/cosmos/cosmos-sdk/issues/8141)). While the group module is not meant to be a total replacement for the current multi-signature accounts, it provides a solution to the limitations described above, with a more flexible key management system where keys can be added, updated or removed, as well as configurable thresholds. From 16578bef19d78c2ff3b67554819cbf3082090eb8 Mon Sep 17 00:00:00 2001 From: Marie Gauthier Date: Thu, 15 Apr 2021 13:59:17 +0200 Subject: [PATCH 08/27] Update docs/architecture/adr-042-group-module.md Co-authored-by: Robert Zaremba --- docs/architecture/adr-042-group-module.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/adr-042-group-module.md b/docs/architecture/adr-042-group-module.md index fbc96738baea..4d7746a6b95d 100644 --- a/docs/architecture/adr-042-group-module.md +++ b/docs/architecture/adr-042-group-module.md @@ -31,7 +31,7 @@ We propose merging the `x/group` module with its supporting [ORM/Table Store pac ### Group -A group is an aggregation of accounts with associated weights. It is not +A group is a composition of accounts with associated weights. It is not an account and doesn't have a balance. It doesn't in and of itself have any sort of voting or decision weight. It has an `admin` account which can manage members in the group. From 180eb50695e76102e16bde88443f988062b6d999 Mon Sep 17 00:00:00 2001 From: Marie Gauthier Date: Thu, 15 Apr 2021 14:12:21 +0200 Subject: [PATCH 09/27] Update docs/architecture/adr-042-group-module.md Co-authored-by: Robert Zaremba --- docs/architecture/adr-042-group-module.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/adr-042-group-module.md b/docs/architecture/adr-042-group-module.md index 4d7746a6b95d..33c4629a68b4 100644 --- a/docs/architecture/adr-042-group-module.md +++ b/docs/architecture/adr-042-group-module.md @@ -167,7 +167,7 @@ this decision policy, abstain and veto are simply treated as no's. ```proto message ThresholdDecisionPolicy { - // threshold is the minimum weighted sum of yes votes that must be met or exceeded for a proposal to succeed. + // threshold is the minimum weighted sum of support votes for a proposal to succeed. string threshold = 1; // timeout is the duration from submission of a proposal to the end of voting period From ce4510ba8df14a28fe80b9e6381143aa29c3b5a1 Mon Sep 17 00:00:00 2001 From: Marie Gauthier Date: Thu, 15 Apr 2021 14:16:37 +0200 Subject: [PATCH 10/27] Update docs/architecture/adr-042-group-module.md Co-authored-by: Robert Zaremba --- docs/architecture/adr-042-group-module.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/architecture/adr-042-group-module.md b/docs/architecture/adr-042-group-module.md index 33c4629a68b4..d56e961b676c 100644 --- a/docs/architecture/adr-042-group-module.md +++ b/docs/architecture/adr-042-group-module.md @@ -50,9 +50,9 @@ message GroupInfo { bytes metadata = 3; // version is used to track changes to a group's membership structure that - // would break existing proposals. Whenever any members weight is changed, - // or any member is added or removed this version is incremented and will - // cause proposals based on older versions of this group to fail + // would break existing proposals. Whenever a member weight has changed, + // or any member is added or removed, the version is incremented and will + // invalidate all proposals from older versions. uint64 version = 4; // total_weight is the sum of the group members' weights. From 8031db1201b6eb28e623e6b88d7b673c7987847a Mon Sep 17 00:00:00 2001 From: Marie Gauthier Date: Thu, 15 Apr 2021 14:18:19 +0200 Subject: [PATCH 11/27] Update docs/architecture/adr-042-group-module.md Co-authored-by: Robert Zaremba --- docs/architecture/adr-042-group-module.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/architecture/adr-042-group-module.md b/docs/architecture/adr-042-group-module.md index d56e961b676c..2d04025e2538 100644 --- a/docs/architecture/adr-042-group-module.md +++ b/docs/architecture/adr-042-group-module.md @@ -254,9 +254,7 @@ message Proposal { // vote_state contains the sums of all weighted votes for this proposal. Tally vote_state = 10 [(gogoproto.nullable) = false]; - // timeout is the timestamp of the block where the proposal execution times out. Header times of the votes and execution messages - // must be before this end time to be included in the election. After the timeout timestamp the proposal can not be - // executed anymore and should be considered pending delete. + // timeout is the block timestamp deadline for the proposal. All votes and execution messages must be processed before the timeout. After the timeout, the proposal can not be executed anymore and should be considered pending delete. google.protobuf.Timestamp timeout = 11 [(gogoproto.nullable) = false]; // ExecutorResult defines types of proposal executor results. From 90dd35d53edd2efde4a08d6ce7b8a2fb8be8f303 Mon Sep 17 00:00:00 2001 From: Marie Gauthier Date: Fri, 16 Apr 2021 12:24:25 +0200 Subject: [PATCH 12/27] Update docs/architecture/adr-042-group-module.md --- docs/architecture/adr-042-group-module.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/adr-042-group-module.md b/docs/architecture/adr-042-group-module.md index 2d04025e2538..37d7844d4fb6 100644 --- a/docs/architecture/adr-042-group-module.md +++ b/docs/architecture/adr-042-group-module.md @@ -356,7 +356,7 @@ In the current implementation, updating a group or a group account after submitt ### Neutral - It uses ADR 033 so it will need to be implemented within the Cosmos SDK, but this doesn't imply necessarily any large refactoring of existing Cosmos SDK modules. -- It requires the ORM package. +- The current implementation of the group module uses the ORM package. ## Further Discussions From 9969a6f9d428456119f4854c15b250266a6b00a5 Mon Sep 17 00:00:00 2001 From: Marie Gauthier Date: Fri, 16 Apr 2021 12:26:04 +0200 Subject: [PATCH 13/27] Update docs/architecture/adr-042-group-module.md --- docs/architecture/adr-042-group-module.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/adr-042-group-module.md b/docs/architecture/adr-042-group-module.md index 37d7844d4fb6..4e25f2951e04 100644 --- a/docs/architecture/adr-042-group-module.md +++ b/docs/architecture/adr-042-group-module.md @@ -21,7 +21,7 @@ The legacy amino multi-signature mechanism of the Cosmos SDK has certain limitat - It requires `legacy_amino` sign mode ([#8141](https://github.com/cosmos/cosmos-sdk/issues/8141)). While the group module is not meant to be a total replacement for the current multi-signature accounts, it provides a solution to the limitations described above, with a more flexible key management system where keys can be added, updated or removed, as well as configurable thresholds. -It's meant to be used with other key management modules such as [`x/feegrant`](./adr-029-fee-grant-module.md) ans [`x/authz`](adr-030-authz-module.md) to simplify key management for individuals and organizations. +It's meant to be used with other access control modules such as [`x/feegrant`](./adr-029-fee-grant-module.md) ans [`x/authz`](adr-030-authz-module.md) to simplify key management for individuals and organizations. The proof of concept of the group module can be found in https://github.com/regen-network/regen-ledger/tree/master/proto/regen/group/v1alpha1 and https://github.com/regen-network/regen-ledger/tree/master/x/group. From bc20dccd828f955f5a221d2735fb4ff6fe3d245d Mon Sep 17 00:00:00 2001 From: Marie Gauthier Date: Fri, 16 Apr 2021 12:36:10 +0200 Subject: [PATCH 14/27] Update docs/architecture/adr-042-group-module.md Co-authored-by: Robert Zaremba --- docs/architecture/adr-042-group-module.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/adr-042-group-module.md b/docs/architecture/adr-042-group-module.md index 4e25f2951e04..21bd55bc0677 100644 --- a/docs/architecture/adr-042-group-module.md +++ b/docs/architecture/adr-042-group-module.md @@ -101,7 +101,7 @@ and then to create separate group accounts with different decision policies and delegate the desired permissions from the master account to those "sub-accounts" using the [`x/authz` module](adr-030-authz-module.md). -Group accounts are stored as part of the `groupAccountTable` and modeled by `GroupAccountInfo`. +Group accounts are stored as part of the `groupAccountTable` and defined by `GroupAccountInfo`. ```proto message GroupAccountInfo { From d2be7ff1790d7def1bd64e481840a712e1eca81d Mon Sep 17 00:00:00 2001 From: Marie Gauthier Date: Fri, 16 Apr 2021 12:41:35 +0200 Subject: [PATCH 15/27] Update docs/architecture/adr-042-group-module.md Co-authored-by: Robert Zaremba --- docs/architecture/adr-042-group-module.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/adr-042-group-module.md b/docs/architecture/adr-042-group-module.md index 21bd55bc0677..262042769d3d 100644 --- a/docs/architecture/adr-042-group-module.md +++ b/docs/architecture/adr-042-group-module.md @@ -40,7 +40,7 @@ Groups are stored in state as part of an ORM-based `groupTable` using the `Group ```proto message GroupInfo { - // group_id is the unique ID of the group. + // group_id is the unique ID of this group. uint64 group_id = 1; // admin is the account address of the group's admin. From f13b3433542bb23ca315df7ec0ab1d84e7183b4d Mon Sep 17 00:00:00 2001 From: Marie Gauthier Date: Fri, 16 Apr 2021 12:43:34 +0200 Subject: [PATCH 16/27] Update docs/architecture/adr-042-group-module.md Co-authored-by: Robert Zaremba --- docs/architecture/adr-042-group-module.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/adr-042-group-module.md b/docs/architecture/adr-042-group-module.md index 262042769d3d..c36420928554 100644 --- a/docs/architecture/adr-042-group-module.md +++ b/docs/architecture/adr-042-group-module.md @@ -109,7 +109,7 @@ message GroupAccountInfo { // address is the group account address. string address = 1; - // group_id is the unique ID of the group. + // group_id is the ID of the Group the GroupAccount belongs to. uint64 group_id = 2; // admin is the account address of the group admin. From 146ea4631792a759d906291cee6d651996f17d99 Mon Sep 17 00:00:00 2001 From: Marie Gauthier Date: Fri, 16 Apr 2021 12:52:56 +0200 Subject: [PATCH 17/27] Update docs/architecture/adr-042-group-module.md Co-authored-by: Robert Zaremba --- docs/architecture/adr-042-group-module.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/adr-042-group-module.md b/docs/architecture/adr-042-group-module.md index c36420928554..f31060e1a1aa 100644 --- a/docs/architecture/adr-042-group-module.md +++ b/docs/architecture/adr-042-group-module.md @@ -119,7 +119,7 @@ message GroupAccountInfo { bytes metadata = 4; // version is used to track changes to a group's GroupAccountInfo structure that - // would create a different result on a running proposal. + // invalidates active proposal from old versions. uint64 version = 5; // decision_policy specifies the group account's decision policy. From ee0567f3444fde59f5bc5dfd61f0200b212d81c8 Mon Sep 17 00:00:00 2001 From: Marie Gauthier Date: Fri, 16 Apr 2021 12:54:02 +0200 Subject: [PATCH 18/27] Update docs/architecture/adr-042-group-module.md Co-authored-by: Robert Zaremba --- docs/architecture/adr-042-group-module.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/adr-042-group-module.md b/docs/architecture/adr-042-group-module.md index f31060e1a1aa..5582e83a5c03 100644 --- a/docs/architecture/adr-042-group-module.md +++ b/docs/architecture/adr-042-group-module.md @@ -115,7 +115,7 @@ message GroupAccountInfo { // admin is the account address of the group admin. string admin = 3; - // metadata is any arbitrary metadata to attached to the group account. + // metadata is any arbitrary metadata of this group account. bytes metadata = 4; // version is used to track changes to a group's GroupAccountInfo structure that From 9897020b71800a1c5d96293309976d6a2881902b Mon Sep 17 00:00:00 2001 From: Marie Gauthier Date: Fri, 16 Apr 2021 13:06:48 +0200 Subject: [PATCH 19/27] Update docs/architecture/adr-042-group-module.md Co-authored-by: Robert Zaremba --- docs/architecture/adr-042-group-module.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/architecture/adr-042-group-module.md b/docs/architecture/adr-042-group-module.md index 5582e83a5c03..fe5c7275147e 100644 --- a/docs/architecture/adr-042-group-module.md +++ b/docs/architecture/adr-042-group-module.md @@ -160,9 +160,9 @@ type DecisionPolicyResult struct { #### Threshold decision policy -A threshold decision policy defines a threshold of yes votes (based on a tally -of voter weights) that must be achieved in order for a proposal to pass. For -this decision policy, abstain and veto are simply treated as no's. +A threshold decision policy defines a minimum support votes (_yes_), based on a tally +of voter weights, for a proposal to pass. For +this decision policy, abstain and veto are treated as no support (_no_). ```proto message ThresholdDecisionPolicy { From d6a0654af3a2db8c8ba1c10b6482e1a12453e55f Mon Sep 17 00:00:00 2001 From: Marie Gauthier Date: Fri, 16 Apr 2021 13:08:55 +0200 Subject: [PATCH 20/27] Update docs/architecture/adr-042-group-module.md Co-authored-by: Robert Zaremba --- docs/architecture/adr-042-group-module.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture/adr-042-group-module.md b/docs/architecture/adr-042-group-module.md index fe5c7275147e..dc119a9070fb 100644 --- a/docs/architecture/adr-042-group-module.md +++ b/docs/architecture/adr-042-group-module.md @@ -134,7 +134,7 @@ The group account address is generated based on an auto-increment integer which A decision policy is the mechanism by which members of a group can vote on proposals. -All decision policies generally would have a minimum and maximum voting window. +All decision policies should have a minimum and maximum voting window. The minimum voting window is the minimum amount of time that must pass in order for a proposal to potentially pass, and it may be set to 0. The maximum voting window is the maximum time that a proposal may be voted on before it is closed. From b74b534a772bb631ba9258a63c59b20eead9296b Mon Sep 17 00:00:00 2001 From: blushi Date: Fri, 16 Apr 2021 14:00:41 +0200 Subject: [PATCH 21/27] Move orm to specific section --- docs/architecture/adr-042-group-module.md | 28 +++++++++++++++-------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/docs/architecture/adr-042-group-module.md b/docs/architecture/adr-042-group-module.md index dc119a9070fb..69cad6ca2b26 100644 --- a/docs/architecture/adr-042-group-module.md +++ b/docs/architecture/adr-042-group-module.md @@ -29,13 +29,17 @@ The proof of concept of the group module can be found in https://github.com/rege We propose merging the `x/group` module with its supporting [ORM/Table Store package](https://github.com/regen-network/regen-ledger/tree/master/orm) ([#7098](https://github.com/cosmos/cosmos-sdk/issues/7098)) into the Cosmos SDK and continuing development here. There will be a dedicated ADR for the ORM package. +A group define a set of accounts that can create proposals and vote on them +through group accounts using different decision policies. + ### Group A group is a composition of accounts with associated weights. It is not an account and doesn't have a balance. It doesn't in and of itself have any -sort of voting or decision weight. It has an `admin` account which can manage members in the group. +sort of voting or decision weight. -Groups are stored in state as part of an ORM-based `groupTable` using the `GroupInfo` type. The `group_id` is an auto-increment integer. +It has an `admin` account which can manage members in the group, update the group +metadata and set a new admin. ```proto message GroupInfo { @@ -60,8 +64,6 @@ message GroupInfo { } ``` -Group members are stored in a `groupMemberTable` using the `GroupMember` type: - ```proto message GroupMember { @@ -101,8 +103,6 @@ and then to create separate group accounts with different decision policies and delegate the desired permissions from the master account to those "sub-accounts" using the [`x/authz` module](adr-030-authz-module.md). -Group accounts are stored as part of the `groupAccountTable` and defined by `GroupAccountInfo`. - ```proto message GroupAccountInfo { @@ -127,7 +127,6 @@ message GroupAccountInfo { } ``` -The group account address is generated based on an auto-increment integer which is used to derive the group module `RootModuleKey` into a `DerivedModuleKey`, as stated in [ADR-033](adr-033-protobuf-inter-module-comm.md#modulekeys-and-moduleids). The group account is added as a new `ModuleAccount` through `x/auth`. ### Decision Policy @@ -182,8 +181,6 @@ Any member of a group can submit a proposal for a group account to decide upon. A proposal consists of a set of `sdk.Msg`s that will be executed if the proposal passes as well as any metadata associated with the proposal. -Proposals are stored as part of the `proposalTable` using the `Proposal` type. The `proposal_id` is an auto-increment integer. - ```proto message Proposal { @@ -307,7 +304,6 @@ During the voting window, accounts that have already voted may change their vote In the current implementation, the voting window begins as soon as a proposal is submitted. -Votes are stored in the `voteTable`. ```proto message Vote { @@ -345,6 +341,18 @@ For these messages to execute successfully, their signer should be set as the gr In the current implementation, updating a group or a group account after submitting a proposal will make it invalid. It will simply fail if someone calls `Msg/Exec` and will eventually be garbage collected. +### Implementation using ORM + +The ORM package defines tables, sequences and secondary indexes which are used in the proof of concept of `x/group`. + +Groups are stored in state as part of a `groupTable`, the `group_id` being an auto-increment integer. Group members are stored in a `groupMemberTable`. + +Group accounts are stored in a `groupAccountTable`. The group account address is generated based on an auto-increment integer which is used to derive the group module `RootModuleKey` into a `DerivedModuleKey`, as stated in [ADR-033](adr-033-protobuf-inter-module-comm.md#modulekeys-and-moduleids). The group account is added as a new `ModuleAccount` through `x/auth`. + +Proposals are stored as part of the `proposalTable` using the `Proposal` type. The `proposal_id` is an auto-increment integer. + +Votes are stored in the `voteTable`. The primary key is based on the vote's `proposal_id` and `voter` account address. + ## Consequences ### Positive From 783d51d6bba11ba12a5a62e392c5b9df0e24185e Mon Sep 17 00:00:00 2001 From: Marie Gauthier Date: Fri, 16 Apr 2021 14:01:33 +0200 Subject: [PATCH 22/27] Update docs/architecture/adr-042-group-module.md --- docs/architecture/adr-042-group-module.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/architecture/adr-042-group-module.md b/docs/architecture/adr-042-group-module.md index 69cad6ca2b26..1587d8aea67e 100644 --- a/docs/architecture/adr-042-group-module.md +++ b/docs/architecture/adr-042-group-module.md @@ -134,9 +134,10 @@ A decision policy is the mechanism by which members of a group can vote on proposals. All decision policies should have a minimum and maximum voting window. -The minimum voting window is the minimum amount of time that must pass in order +The minimum voting window is the minimum duration that must pass in order for a proposal to potentially pass, and it may be set to 0. The maximum voting -window is the maximum time that a proposal may be voted on before it is closed. +window is the maximum time that a proposal may be voted on and executed if +it reached enough support before it is closed. Both of these values must be less than a chain-wide max voting window parameter. We define the `DecisionPolicy` interface that all decision policies must implement: From 9afc938222b79a9bf7361b58d619c1abbecc9991 Mon Sep 17 00:00:00 2001 From: blushi Date: Fri, 16 Apr 2021 14:04:54 +0200 Subject: [PATCH 23/27] Update naming --- docs/architecture/adr-042-group-module.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/architecture/adr-042-group-module.md b/docs/architecture/adr-042-group-module.md index 1587d8aea67e..9f2cc3942341 100644 --- a/docs/architecture/adr-042-group-module.md +++ b/docs/architecture/adr-042-group-module.md @@ -170,9 +170,9 @@ message ThresholdDecisionPolicy { // threshold is the minimum weighted sum of support votes for a proposal to succeed. string threshold = 1; - // timeout is the duration from submission of a proposal to the end of voting period - // Within this times votes and exec messages can be submitted. - google.protobuf.Duration timeout = 2 [(gogoproto.nullable) = false]; + // voting_period is the duration from submission of a proposal to the end of voting period + // Within this period, votes and exec messages can be submitted. + google.protobuf.Duration voting_period = 2 [(gogoproto.nullable) = false]; } ``` From ce103bfa93456e90185b38ef804404a1c0d6e7c6 Mon Sep 17 00:00:00 2001 From: blushi Date: Thu, 22 Apr 2021 09:59:11 +0200 Subject: [PATCH 24/27] Add concrete use cases --- docs/architecture/adr-042-group-module.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/architecture/adr-042-group-module.md b/docs/architecture/adr-042-group-module.md index 9f2cc3942341..5d3928ffc81d 100644 --- a/docs/architecture/adr-042-group-module.md +++ b/docs/architecture/adr-042-group-module.md @@ -29,14 +29,12 @@ The proof of concept of the group module can be found in https://github.com/rege We propose merging the `x/group` module with its supporting [ORM/Table Store package](https://github.com/regen-network/regen-ledger/tree/master/orm) ([#7098](https://github.com/cosmos/cosmos-sdk/issues/7098)) into the Cosmos SDK and continuing development here. There will be a dedicated ADR for the ORM package. -A group define a set of accounts that can create proposals and vote on them -through group accounts using different decision policies. - ### Group A group is a composition of accounts with associated weights. It is not an account and doesn't have a balance. It doesn't in and of itself have any sort of voting or decision weight. +Group members can create proposals and vote on them through group accounts using different decision policies. It has an `admin` account which can manage members in the group, update the group metadata and set a new admin. @@ -127,6 +125,10 @@ message GroupAccountInfo { } ``` +Similarly to a group admin, a group account admin can update its metadata, decision policy or set a new group account admin. + +A group account can also be an admin or a member of a group. +For instance, a group admin could be another group account which could "elects" the members or it could be the same group that elects itself. ### Decision Policy From 1afa664ddfb82f940d1314b37de5b2d6bc38af64 Mon Sep 17 00:00:00 2001 From: blushi Date: Thu, 22 Apr 2021 10:42:06 +0200 Subject: [PATCH 25/27] Rework ### Proposal --- docs/architecture/adr-042-group-module.md | 107 ++-------------------- 1 file changed, 8 insertions(+), 99 deletions(-) diff --git a/docs/architecture/adr-042-group-module.md b/docs/architecture/adr-042-group-module.md index 5d3928ffc81d..ad364e11c2e0 100644 --- a/docs/architecture/adr-042-group-module.md +++ b/docs/architecture/adr-042-group-module.md @@ -182,105 +182,14 @@ message ThresholdDecisionPolicy { Any member of a group can submit a proposal for a group account to decide upon. A proposal consists of a set of `sdk.Msg`s that will be executed if the proposal -passes as well as any metadata associated with the proposal. +passes as well as any metadata associated with the proposal. These `sdk.Msg`s get validated as part of the `Msg/CreateProposal` request validation. -```proto -message Proposal { - - // proposal_id is the unique id of the proposal. - uint64 proposal_id = 1; - - // address is the group account address. - string address = 2; - - // metadata is any arbitrary metadata to attached to the proposal. - bytes metadata = 3; - - // proposers are the account addresses of the proposers. - repeated string proposers = 4; - - // submitted_at is a timestamp specifying when a proposal was submitted. - google.protobuf.Timestamp submitted_at = 5 [(gogoproto.nullable) = false]; - - // group_version tracks the version of the group that this proposal corresponds to. - // When group membership is changed, existing proposals from previous group versions will become invalid. - uint64 group_version = 6; - - // group_account_version tracks the version of the group account that this proposal corresponds to. - // When a decision policy is changed, existing proposals from previous policy versions will become invalid. - uint64 group_account_version = 7; - - // Status defines proposal statuses. - enum Status { - option (gogoproto.goproto_enum_prefix) = false; - - // An empty value is invalid and not allowed. - STATUS_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "ProposalStatusInvalid"]; - - // Initial status of a proposal when persisted. - STATUS_SUBMITTED = 1 [(gogoproto.enumvalue_customname) = "ProposalStatusSubmitted"]; - - // Final status of a proposal when the final tally was executed. - STATUS_CLOSED = 2 [(gogoproto.enumvalue_customname) = "ProposalStatusClosed"]; - - // Final status of a proposal when the group was modified before the final tally. - STATUS_ABORTED = 3 [(gogoproto.enumvalue_customname) = "ProposalStatusAborted"]; - } - - // Status represents the high level position in the life cycle of the proposal. Initial value is Submitted. - Status status = 8; - - // Result defines types of proposal results. - enum Result { - option (gogoproto.goproto_enum_prefix) = false; - - // An empty value is invalid and not allowed - RESULT_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "ProposalResultInvalid"]; - - // Until a final tally has happened the status is unfinalized - RESULT_UNFINALIZED = 1 [(gogoproto.enumvalue_customname) = "ProposalResultUnfinalized"]; - - // Final result of the tally - RESULT_ACCEPTED = 2 [(gogoproto.enumvalue_customname) = "ProposalResultAccepted"]; - - // Final result of the tally - RESULT_REJECTED = 3 [(gogoproto.enumvalue_customname) = "ProposalResultRejected"]; - } - - // result is the final result based on the votes and election rule. Initial value is unfinalized. - // The result is persisted so that clients can always rely on this state and not have to replicate the logic. - Result result = 9; - - // vote_state contains the sums of all weighted votes for this proposal. - Tally vote_state = 10 [(gogoproto.nullable) = false]; - - // timeout is the block timestamp deadline for the proposal. All votes and execution messages must be processed before the timeout. After the timeout, the proposal can not be executed anymore and should be considered pending delete. - google.protobuf.Timestamp timeout = 11 [(gogoproto.nullable) = false]; - - // ExecutorResult defines types of proposal executor results. - enum ExecutorResult { - option (gogoproto.goproto_enum_prefix) = false; - - // An empty value is not allowed. - EXECUTOR_RESULT_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "ProposalExecutorResultInvalid"]; - - // We have not yet run the executor. - EXECUTOR_RESULT_NOT_RUN = 1 [(gogoproto.enumvalue_customname) = "ProposalExecutorResultNotRun"]; - - // The executor was successful and proposed action updated state. - EXECUTOR_RESULT_SUCCESS = 2 [(gogoproto.enumvalue_customname) = "ProposalExecutorResultSuccess"]; - - // The executor returned an error and proposed action didn't update state. - EXECUTOR_RESULT_FAILURE = 3 [(gogoproto.enumvalue_customname) = "ProposalExecutorResultFailure"]; - } - - // executor_result is the final result based on the votes and election rule. Initial value is NotRun. - ExecutorResult executor_result = 12; - - // msgs is a list of Msgs that will be executed if the proposal passes. - repeated google.protobuf.Any msgs = 13; -} +Internally, a proposal also tracks: +- its current status: submitted, closed or aborted +- its result: unfinalized, accepted or rejected +- its vote state in the form of a `Tally`, which is calculated on new votes and when executing the proposal. +```proto // Tally represents the sum of weighted votes. message Tally { option (gogoproto.goproto_getters) = false; @@ -307,7 +216,6 @@ During the voting window, accounts that have already voted may change their vote In the current implementation, the voting window begins as soon as a proposal is submitted. - ```proto message Vote { @@ -374,7 +282,8 @@ Votes are stored in the `voteTable`. The primary key is based on the vote's `pro - Convergence of `/group` and `x/gov` as both support proposals and voting: https://github.com/cosmos/cosmos-sdk/discussions/9066 - `x/group` possible future improvements: - Execute proposals on submission (https://github.com/regen-network/regen-ledger/issues/288) - - Withdraw a proposal (https://github.com/regen-network/cosmos-modules/issues/41) + - Withdraw a proposal (https://github.com/regen-network/cosmos-modules/issues/41) + - Make `Tally` more flexible and support non-binary choices ## References From 5d609c6730cb1adcbfad4e83a13841e19f2ffc5b Mon Sep 17 00:00:00 2001 From: blushi Date: Thu, 22 Apr 2021 11:10:21 +0200 Subject: [PATCH 26/27] Rework Vote, Exec and implementation sections --- docs/architecture/adr-042-group-module.md | 47 ++++++++--------------- 1 file changed, 16 insertions(+), 31 deletions(-) diff --git a/docs/architecture/adr-042-group-module.md b/docs/architecture/adr-042-group-module.md index ad364e11c2e0..a4c6043af5ef 100644 --- a/docs/architecture/adr-042-group-module.md +++ b/docs/architecture/adr-042-group-module.md @@ -182,12 +182,12 @@ message ThresholdDecisionPolicy { Any member of a group can submit a proposal for a group account to decide upon. A proposal consists of a set of `sdk.Msg`s that will be executed if the proposal -passes as well as any metadata associated with the proposal. These `sdk.Msg`s get validated as part of the `Msg/CreateProposal` request validation. +passes as well as any metadata associated with the proposal. These `sdk.Msg`s get validated as part of the `Msg/CreateProposal` request validation. They should also have their signer set as the group account. Internally, a proposal also tracks: -- its current status: submitted, closed or aborted -- its result: unfinalized, accepted or rejected -- its vote state in the form of a `Tally`, which is calculated on new votes and when executing the proposal. +- its current `Status`: submitted, closed or aborted +- its `Result`: unfinalized, accepted or rejected +- its `VoteState` in the form of a `Tally`, which is calculated on new votes and when executing the proposal. ```proto // Tally represents the sum of weighted votes. @@ -210,33 +210,13 @@ message Tally { ### Voting -There are four choices to choose while voting - yes, no, abstain and veto. Not +Members of a group can vote on proposals. There are four choices to choose while voting - yes, no, abstain and veto. Not all decision policies will support them. Votes can contain some optional metadata. During the voting window, accounts that have already voted may change their vote. In the current implementation, the voting window begins as soon as a proposal is submitted. -```proto -message Vote { - - // proposal is the unique ID of the proposal. - uint64 proposal_id = 1; - - // voter is the account address of the voter. - string voter = 2; - - // choice is the voter's choice on the proposal. - Choice choice = 3; - - // metadata is any arbitrary metadata to attached to the vote. - bytes metadata = 4; - - // submitted_at is the timestamp when the vote was submitted. - google.protobuf.Timestamp submitted_at = 5 [(gogoproto.nullable) = false]; -} -``` - -Voting internally updates the proposal `Status` and `Result` if needed. +Voting internally updates the proposal `VoteState` as well as `Status` and `Result` if needed. ### Executing Proposals @@ -245,16 +225,17 @@ but rather a user must submit a `Msg/Exec` transaction to attempt to execute the proposal based on the current votes and decision policy. A future upgrade could automate this and have the group account (or a fee granter) pay. -Inter-module communication introduced by [ADR-033](adr-033-protobuf-inter-module-comm.md) will be used to route a proposal's messages using the `DerivedModuleKey` corresponding to the proposal's group account. It can also temporarily support routing of non `ServiceMsg`s through the `sdk.Router` (see [#8864](https://github.com/cosmos/cosmos-sdk/issues/8864)). -For these messages to execute successfully, their signer should be set as the group account. - #### Changing Group Membership In the current implementation, updating a group or a group account after submitting a proposal will make it invalid. It will simply fail if someone calls `Msg/Exec` and will eventually be garbage collected. -### Implementation using ORM +### Notes on current implementation + +This section outlines the current implementation used in the proof of concept of the group module but this could be subject to changes and iterated on. -The ORM package defines tables, sequences and secondary indexes which are used in the proof of concept of `x/group`. +#### ORM + +The [ORM package](https://github.com/cosmos/cosmos-sdk/discussions/9156) defines tables, sequences and secondary indexes which are used in the group module. Groups are stored in state as part of a `groupTable`, the `group_id` being an auto-increment integer. Group members are stored in a `groupMemberTable`. @@ -264,6 +245,10 @@ Proposals are stored as part of the `proposalTable` using the `Proposal` type. T Votes are stored in the `voteTable`. The primary key is based on the vote's `proposal_id` and `voter` account address. +#### ADR-033 to route proposal messages + +Inter-module communication introduced by [ADR-033](adr-033-protobuf-inter-module-comm.md) can be used to route a proposal's messages using the `DerivedModuleKey` corresponding to the proposal's group account. It can also temporarily support routing of non `ServiceMsg`s through the `sdk.Router` (see [#8864](https://github.com/cosmos/cosmos-sdk/issues/8864)). + ## Consequences ### Positive From e9c39b199e773560a93364178517ef4755421a72 Mon Sep 17 00:00:00 2001 From: blushi Date: Wed, 5 May 2021 09:50:55 +0200 Subject: [PATCH 27/27] Update to account for removal of ServiceMsg --- docs/architecture/adr-042-group-module.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/architecture/adr-042-group-module.md b/docs/architecture/adr-042-group-module.md index a4c6043af5ef..dcca987bcd1e 100644 --- a/docs/architecture/adr-042-group-module.md +++ b/docs/architecture/adr-042-group-module.md @@ -212,7 +212,6 @@ message Tally { Members of a group can vote on proposals. There are four choices to choose while voting - yes, no, abstain and veto. Not all decision policies will support them. Votes can contain some optional metadata. -During the voting window, accounts that have already voted may change their vote. In the current implementation, the voting window begins as soon as a proposal is submitted. @@ -247,7 +246,7 @@ Votes are stored in the `voteTable`. The primary key is based on the vote's `pro #### ADR-033 to route proposal messages -Inter-module communication introduced by [ADR-033](adr-033-protobuf-inter-module-comm.md) can be used to route a proposal's messages using the `DerivedModuleKey` corresponding to the proposal's group account. It can also temporarily support routing of non `ServiceMsg`s through the `sdk.Router` (see [#8864](https://github.com/cosmos/cosmos-sdk/issues/8864)). +Inter-module communication introduced by [ADR-033](adr-033-protobuf-inter-module-comm.md) can be used to route a proposal's messages using the `DerivedModuleKey` corresponding to the proposal's group account. ## Consequences