摘要
以下文档指定了 group
模块。
该模块允许创建和管理链上的多签账户,并根据可配置的决策策略启用对消息执行的投票。
目录
概念
群组
一个组仅仅是具有相关权重的账户的聚合。它不是一个账户,并且没有余额。它本身没有任何投票或决策权重。它确实有一个“管理员”,该管理员有能力添加、删除和更新组内的成员。请注意,组策略账户可以是组的管理员,并且管理员不一定是组的成员。
群组策略
组策略是与一个组和一个决策策略关联的账户。组策略与组分离,因为一个组可能有多个不同类型操作的决策策略。将组成员管理与决策策略分开,可以减少开销,并保持不同策略下的成员一致性。推荐的模式是为给定的组创建一个单一的主组策略,然后创建具有不同决策策略的独立组策略,并使用 x/authz
模块将所需的权限从主账户委派到这些“子账户”。
决策策略
决策策略是组成员对提案进行投票的机制,以及根据投票结果决定提案是否通过的规则。
所有决策策略通常都有一个最小执行期和一个最大投票窗口。最小执行期是提案提交后必须经过的最短时间,才能使提案有可能被执行,且可设置为 0。最大投票窗口是提案提交后,允许投票的最长时间,超出后将进行计票。
链开发者还定义了一个应用级的最大执行期,即在提案投票期结束后的最大时间,用户在此期间可以执行提案。
当前的 group
模块内置了两种决策策略:threshold
和 percentage
。任何链开发者都可以在这两种策略的基础上进行扩展,创建自定义决策策略,只要它们遵循 DecisionPolicy
接口:
Copy https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/x/group/types.go#L27-L45
阈值(Threshold) 决策策略
Threshold
决策策略定义了必须达到的“同意”投票门槛(基于选民权重的计票结果),以使提案通过。对于该决策策略,弃权和否决投票都视为“否”。
该决策策略还包括一个 VotingPeriod
窗口和一个 MinExecutionPeriod
窗口。前者定义了提案提交后,成员可以投票的持续时间,之后将进行计票。后者指定了提案提交后,提案可以执行的最短时间。如果设置为 0,则提案在提交时可以立即执行(使用 TRY_EXEC
选项)。显然,MinExecutionPeriod
不能大于 VotingPeriod
+ MaxExecutionPeriod
(其中 MaxExecutionPeriod
是应用定义的时长,指定投票结束后提案可以执行的时间窗口)。
百分比(Percentage) 决策策略
Percentage
决策策略与 Threshold
决策策略类似,不同之处在于门槛不是定义为固定权重,而是作为一个百分比。这种策略更适合于成员权重可以更新的组,因为百分比门槛保持不变,不依赖于成员权重的更新方式。
与 Threshold
决策策略相同,Percentage
决策策略也具有两个参数:VotingPeriod
和 MinExecutionPeriod
。
提案
任何组成员都可以提交一个提案,由组策略账户进行决策。提案由一组消息组成,如果提案通过,这些消息将被执行,并且包括与提案相关的任何元数据。
投票
投票时有四个选项可供选择——同意、不同意、弃权和否决。并非所有决策策略都会考虑这四个选项。投票可以包含一些可选的元数据。在当前的实现中,投票窗口从提案提交开始,结束时间由组策略的决策策略定义。
撤回提案
提案可以在投票期结束之前任何时间被撤回,撤回者可以是组策略的管理员或提案人之一。一旦撤回,提案将被标记为 PROPOSAL_STATUS_WITHDRAWN
,并且不再允许投票或执行。
中止提案
如果在提案的投票期间更新了组策略,则该提案将被标记为 PROPOSAL_STATUS_ABORTED
,并且不再允许投票或执行。这是因为组策略定义了提案投票和执行的规则,如果这些规则在提案生命周期中发生变化,则该提案应该被标记为过时。
计票
计票是对提案的所有投票进行统计的过程。在提案的生命周期中,计票只会发生一次,并由以下两个条件之一触发(以先发生者为准):
有人尝试执行该提案(见下一节)。这可以通过 Msg/Exec
交易,或者 Msg/{SubmitProposal,Vote}
交易并设置 Exec
字段来触发。当尝试执行提案时,系统会先进行计票,以确保提案通过。
在 EndBlock
阶段,当提案的投票期刚刚结束时自动触发。
如果计票结果符合决策策略的规则,则提案将被标记为 PROPOSAL_STATUS_ACCEPTED
;否则,将被标记为 PROPOSAL_STATUS_REJECTED
。无论结果如何,计票后不再允许投票,最终的计票结果将存储在提案的 FinalTallyResult
状态中。
执行提案
提案仅在计票完成且组账户的决策策略允许通过时才能执行,这些提案的状态为 PROPOSAL_STATUS_ACCEPTED
。执行必须在每个提案投票期结束后的 MaxExecutionPeriod
(由链开发者设置)时间范围内完成。
在当前设计中,链不会自动执行提案,而是要求用户提交 Msg/Exec
交易来尝试基于当前投票结果和决策策略执行提案。任何用户(不仅限于组成员)都可以执行已接受的提案,并且执行费用由执行者承担。
此外,可以在创建提案或新增投票时,使用 Msg/SubmitProposal
和 Msg/Vote
请求的 Exec
字段来尝试立即执行提案。在前一种情况下,提案人的签名将被视为“同意”投票。如果提案无法执行(即未通过决策策略的规则),它仍然会保持开放状态,允许继续投票,并可在稍后进行计票和执行。
成功执行的提案,其 ExecutorResult
将被标记为 PROPOSAL_EXECUTOR_RESULT_SUCCESS
,并在执行后自动删除。
如果执行失败,提案的 ExecutorResult
将被标记为 PROPOSAL_EXECUTOR_RESULT_FAILURE
。这种提案可以被多次重新执行,直到其在投票期结束后的 MaxExecutionPeriod
过期。
清理
为了避免状态膨胀,提案和投票都会被自动清理。
投票的清理条件 (以先发生者为准):
在成功计票后,即计票结果符合决策策略的规则(可由 Msg/Exec
或 Msg/{SubmitProposal,Vote}
交易并设置 Exec
字段触发)。
在 EndBlock
阶段,当提案的投票期结束时。此规则同样适用于状态为 aborted
或 withdrawn
的提案。
提案的清理条件 (以先发生者为准):
在 EndBlock
阶段,如果提案在计票前已被撤回(withdrawn
)或中止(aborted
),则会被清理。
在 EndBlock
阶段,当 voting_period_end + max_execution_period
(由应用全局配置定义)时间到期时,提案会被清理。
状态
group
模块使用 orm
包,该包提供了支持主键和二级索引的表存储功能。orm
还定义了 Sequence
,它是一个基于计数器的持久唯一键生成器,可与 Tables
结合使用。
以下是 group
模块中存储的表及其关联的序列和索引列表。
Group Table
groupTable
存储 GroupInfo
:
0x0 | BigEndian(GroupId)
-> ProtocolBuffer(GroupInfo)
groupSeq
groupSeq
的值在创建新组时递增,并对应于新的 GroupId
:
0x1 | 0x1
-> BigEndian
。
第二个 0x1
对应于 ORM sequenceStorageKey
。
groupByAdminIndex
groupByAdminIndex
允许通过管理员地址检索组:
0x2 | len([]byte(group.Admin)) | []byte(group.Admin) | BigEndian(GroupId)
-> []byte()
。
Group Member Table
groupMemberTable
存储 GroupMembers
:
0x10 | BigEndian(GroupId) | []byte(member.Address)
-> ProtocolBuffer(GroupMember)
。
groupMemberTable
是一个主键表,其主键由 BigEndian(GroupId) | []byte(member.Address)
组成,并由以下索引使用:
groupMemberByGroupIndex
groupMemberByGroupIndex
允许按组 ID 检索组成员:
0x11 | BigEndian(GroupId) | PrimaryKey
-> []byte()
。
groupMemberByMemberIndex
groupMemberByMemberIndex
允许按成员地址检索组成员:
0x12 | len([]byte(member.Address)) | []byte(member.Address) | PrimaryKey
-> []byte()
。
Group Policy Table
groupPolicyTable
存储 GroupPolicyInfo
:
0x20 | len([]byte(Address)) | []byte(Address)
-> ProtocolBuffer(GroupPolicyInfo)
。
groupPolicyTable
是一个主键表,其主键由 len([]byte(Address)) | []byte(Address)
组成,并由以下索引使用:
groupPolicySeq
groupPolicySeq
的值在创建新组策略时递增,并用于生成新的组策略账户地址:
0x21 | 0x1
-> BigEndian
。
第二个 0x1
对应于 ORM sequenceStorageKey
。
groupPolicyByGroupIndex
groupPolicyByGroupIndex
允许按组 ID 检索组策略:
0x22 | BigEndian(GroupId) | PrimaryKey
-> []byte()
。
groupPolicyByAdminIndex
groupPolicyByAdminIndex
允许按管理员地址检索组策略:
0x23 | len([]byte(Address)) | []byte(Address) | PrimaryKey
-> []byte()
。
Proposal Table
proposalTable
存储 Proposals
:
0x30 | BigEndian(ProposalId)
-> ProtocolBuffer(Proposal)
。
proposalSeq
proposalSeq
的值在创建新提案时递增,并对应于新的 ProposalId
:
0x31 | 0x1
-> BigEndian
。
第二个 0x1
对应于 ORM sequenceStorageKey
。
proposalByGroupPolicyIndex
proposalByGroupPolicyIndex
允许按组策略账户地址检索提案:
0x32 | len([]byte(account.Address)) | []byte(account.Address) | BigEndian(ProposalId)
-> []byte()
。
ProposalsByVotingPeriodEndIndex
proposalsByVotingPeriodEndIndex
允许按投票期结束时间排序检索提案:
0x33 | sdk.FormatTimeBytes(proposal.VotingPeriodEnd) | BigEndian(ProposalId)
-> []byte()
。
此索引用于在投票期结束时计票提案投票,并用于在 VotingPeriodEnd + MaxExecutionPeriod
时清理提案。
Vote Table
voteTable
存储 Vote
:0x40 | BigEndian(ProposalId) | []byte(voter.Address) -> ProtocolBuffer(Vote)
。
voteTable
是一个主键表,其 PrimaryKey
由 BigEndian(ProposalId) | []byte(voter.Address)
组成,并被以下索引使用。
voteByProposalIndex
voteByProposalIndex
允许根据 proposal id
检索投票记录:
0x41 | BigEndian(ProposalId) | PrimaryKey -> []byte()
。
voteByVoterIndex
voteByVoterIndex
允许根据 voter address
检索投票记录:
0x42 | len([]byte(voter.Address)) | []byte(voter.Address) | PrimaryKey -> []byte()
。
消息服务
Msg/CreateGroup
可以使用 MsgCreateGroup
创建新 group
,其中包含 admin address
、成员列表以及可选的 metadata
。
metadata
的最大长度由应用开发者指定,并作为配置传递给 group keeper
。
Copy https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/proto/cosmos/group/v1/tx.proto#L67-L80
如果出现以下情况,预期操作将失败:
metadata
长度超过 MaxMetadataLen
配置值。
成员设置不正确(例如,地址格式错误、存在重复项或权重为 0
)。
Msg/UpdateGroupMembers
可以使用 UpdateGroupMembers
更新 group members
。
Copy https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/proto/cosmos/group/v1/tx.proto#L88-L102
在 MemberUpdates
列表中,可以通过将成员的 weight
设为 0
来移除现有成员。
预期失败情况:
任何相关 group policy
的 decision policy
在 Validate()
方法中未能通过更新后的 group
校验。
Msg/UpdateGroupAdmin
可以使用 UpdateGroupAdmin
更新 group admin
。
Copy https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/proto/cosmos/group/v1/tx.proto#L107-L120
预期失败情况:
可以使用 UpdateGroupMetadata
更新 group metadata
。
Copy https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/proto/cosmos/group/v1/tx.proto#L125-L138
预期失败情况:
新 metadata
长度超过 MaxMetadataLen
配置值。
Msg/CreateGroupPolicy
可以使用 MsgCreateGroupPolicy
创建新的 group policy
,其中包含 admin address
、group id
、decision policy
及可选的 metadata
。
Copy https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/proto/cosmos/group/v1/tx.proto#L147-L165
预期失败情况:
metadata
长度超过 MaxMetadataLen
配置值。
decision policy
的 Validate()
方法未能通过 group
校验。
Msg/CreateGroupWithPolicy
可以使用 MsgCreateGroupWithPolicy
创建新的 group
和 policy
,其中包含 admin address
、成员列表、decision policy
、group_policy_as_admin
字段(可选地将 group
和 group policy
的 admin
设为 group policy address
),以及 group
和 group policy
的可选 metadata
。
Copy https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/proto/cosmos/group/v1/tx.proto#L191-L215
预期失败情况:
与 MsgCreateGroup
和 MsgCreateGroupPolicy
相同的失败原因。
Msg/UpdateGroupPolicyAdmin
可以使用 UpdateGroupPolicyAdmin
更新 group policy admin
。
Copy https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/proto/cosmos/group/v1/tx.proto#L173-L186
预期失败情况:
签名者不是该 group policy
的 admin
。
Msg/UpdateGroupPolicyDecisionPolicy
可以使用 UpdateGroupPolicyDecisionPolicy
更新 decision policy
。
Copy https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/proto/cosmos/group/v1/tx.proto#L226-L241
预期失败情况:
签名者不是该 group policy
的 admin
。
新 decision policy
的 Validate()
方法未能通过 group
校验。
可以使用 UpdateGroupPolicyMetadata
更新 group policy metadata
。
Copy https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/proto/cosmos/group/v1/tx.proto#L246-L259
预期失败情况:
新 metadata
长度超过 MaxMetadataLen
配置值。
Msg/SubmitProposal
可以使用 MsgSubmitProposal
创建新 proposal
,其中包含 group policy account address
、提案者地址列表、提案通过后要执行的消息列表及可选 metadata
。此外,可选 Exec
值可用于在创建提案后立即尝试执行提案,提案者签名在此情况下视为 yes
票。
Copy https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/proto/cosmos/group/v1/tx.proto#L281-L315
预期失败情况:
metadata
、title
或 summary
长度超过 MaxMetadataLen
配置值。
Msg/WithdrawProposal
可以使用 MsgWithdrawProposal
撤回 proposal
,该消息包含一个 address
(可以是提案者或 group policy admin
)以及需要撤回的 proposal_id
。
Copy https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/proto/cosmos/group/v1/tx.proto#L323-L333
预期失败情况:
签名者既不是 group policy admin
,也不是该 proposal
的提案者。
Msg/Vote
可以使用 MsgVote
进行投票,该消息包含 proposal id
、voter address
、投票选项(yes
、no
、veto
或 abstain
)及可选的 metadata
。此外,可选 Exec
值可用于在投票后立即尝试执行 proposal
。
Copy https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/proto/cosmos/group/v1/tx.proto#L338-L358
预期失败情况:
metadata
长度超过 MaxMetadataLen
配置值。
Msg/Exec
可以使用 MsgExec
执行 proposal
。
Copy https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/proto/cosmos/group/v1/tx.proto#L363-L373
以下情况 proposal
中的消息不会被执行:
proposal
未被 group policy
接受。
Msg/LeaveGroup
可以使用 MsgLeaveGroup
让 group member
退出 group
。
Copy https://github.com/cosmos/cosmos-sdk/blob/v0.47.0-rc1/proto/cosmos/group/v1/tx.proto#L381-L391
预期失败情况:
任何相关 group policy
的 decision policy
在 Validate()
方法中未能通过更新后的 group
校验。
事件
group module
触发以下事件:
EventCreateGroup
/cosmos.group.v1.Msg/CreateGroup
cosmos.group.v1.EventCreateGroup
EventUpdateGroup
/cosmos.group.v1.Msg/UpdateGroup{Admin|Metadata|Members}
cosmos.group.v1.EventUpdateGroup
EventCreateGroupPolicy
/cosmos.group.v1.Msg/CreateGroupPolicy
cosmos.group.v1.EventCreateGroupPolicy
EventUpdateGroupPolicy
/cosmos.group.v1.Msg/UpdateGroupPolicy{Admin|Metadata|DecisionPolicy}
cosmos.group.v1.EventUpdateGroupPolicy
EventCreateProposal
/cosmos.group.v1.Msg/CreateProposal
cosmos.group.v1.EventCreateProposal
EventWithdrawProposal
/cosmos.group.v1.Msg/WithdrawProposal
cosmos.group.v1.EventWithdrawProposal
EventVote
/cosmos.group.v1.Msg/Vote
cosmos.group.v1.EventVote
EventExec
/cosmos.group.v1.Msg/Exec
cosmos.group.v1.EventExec
cosmos.group.v1.EventExec
EventLeaveGroup
/cosmos.group.v1.Msg/LeaveGroup
cosmos.group.v1.EventLeaveGroup
cosmos.group.v1.EventLeaveGroup
EventProposalPruned
/cosmos.group.v1.Msg/LeaveGroup
cosmos.group.v1.EventProposalPruned
cosmos.group.v1.EventProposalPruned
cosmos.group.v1.EventProposalPruned
客户端
CLI
用户可以使用 CLI
查询并与 group module
交互。
Query
查询命令允许用户查询 group
状态。
Copy simd query group --help
group-info
group-info
命令允许用户通过给定的 group id
查询 group
信息。
Copy simd query group group-info [id] [flags]
示例:
Copy simd query group group-info 1
示例输出:
Copy admin: cosmos1..
group_id: "1"
metadata: AQ==
total_weight: "3"
version: "1"
group-policy-info
group-policy-info
命令允许用户通过 group policy
的账户地址查询 group policy
信息。
Copy simd query group group-policy-info [group-policy-account] [flags]
示例:
Copy simd query group group-policy-info cosmos1..
示例输出:
Copy address: cosmos1..
admin: cosmos1..
decision_policy:
'@type': /cosmos.group.v1.ThresholdDecisionPolicy
threshold: "1"
windows:
min_execution_period: 0s
voting_period: 432000s
group_id: "1"
metadata: AQ==
version: "1"
group-members
group-members
命令允许用户通过 group id
查询 group members
,并支持分页标志。
Copy simd query group group-members [id] [flags]
示例:
Copy simd query group group-members 1
示例输出:
Copy members:
- group_id: "1"
member:
address: cosmos1..
metadata: AQ==
weight: "2"
- group_id: "1"
member:
address: cosmos1..
metadata: AQ==
weight: "1"
pagination:
next_key: null
total: "2"
groups-by-admin
groups-by-admin
命令允许用户通过 admin account address
查询 groups
,并支持分页标志。
Copy simd query group groups-by-admin [admin] [flags]
示例:
Copy simd query group groups-by-admin cosmos1..
示例输出:
Copy groups:
- admin: cosmos1..
group_id: "1"
metadata: AQ==
total_weight: "3"
version: "1"
- admin: cosmos1..
group_id: "2"
metadata: AQ==
total_weight: "3"
version: "1"
pagination:
next_key: null
total: "2"
group-policies-by-group
group-policies-by-group
命令允许用户通过 group id
查询 group policies
,并支持分页标志。
Copy simd query group group-policies-by-group [group-id] [flags]
示例:
Copy simd query group group-policies-by-group 1
示例输出:
Copy group_policies:
- address: cosmos1..
admin: cosmos1..
decision_policy:
'@type': /cosmos.group.v1.ThresholdDecisionPolicy
threshold: "1"
windows:
min_execution_period: 0s
voting_period: 432000s
group_id: "1"
metadata: AQ==
version: "1"
- address: cosmos1..
admin: cosmos1..
decision_policy:
'@type': /cosmos.group.v1.ThresholdDecisionPolicy
threshold: "1"
windows:
min_execution_period: 0s
voting_period: 432000s
group_id: "1"
metadata: AQ==
version: "1"
pagination:
next_key: null
total: "2"
group-policies-by-admin
group-policies-by-admin
命令允许用户通过 admin account address
查询 group policies
,并支持分页标志。
Copy simd query group group-policies-by-admin [admin] [flags]
示例:
Copy simd query group group-policies-by-admin cosmos1..
示例输出:
Copy group_policies:
- address: cosmos1..
admin: cosmos1..
decision_policy:
'@type': /cosmos.group.v1.ThresholdDecisionPolicy
threshold: "1"
windows:
min_execution_period: 0s
voting_period: 432000s
group_id: "1"
metadata: AQ==
version: "1"
- address: cosmos1..
admin: cosmos1..
decision_policy:
'@type': /cosmos.group.v1.ThresholdDecisionPolicy
threshold: "1"
windows:
min_execution_period: 0s
voting_period: 432000s
group_id: "1"
metadata: AQ==
version: "1"
pagination:
next_key: null
total: "2"
proposal
proposal
命令允许用户通过 id
查询 proposal
。
Copy simd query group proposal [id] [flags]
示例:
Copy simd query group proposal 1
示例输出:
Copy proposal:
address: cosmos1..
executor_result: EXECUTOR_RESULT_NOT_RUN
group_policy_version: "1"
group_version: "1"
metadata: AQ==
msgs:
- '@type': /cosmos.bank.v1beta1.MsgSend
amount:
- amount: "100000000"
denom: stake
from_address: cosmos1..
to_address: cosmos1..
proposal_id: "1"
proposers:
- cosmos1..
result: RESULT_UNFINALIZED
status: STATUS_SUBMITTED
submitted_at: "2021-12-17T07:06:26.310638964Z"
windows:
min_execution_period: 0s
voting_period: 432000s
vote_state:
abstain_count: "0"
no_count: "0"
veto_count: "0"
yes_count: "0"
summary: "Summary"
title: "Title"
proposals-by-group-policy
proposals-by-group-policy
命令允许用户通过 group policy
的账户地址查询 proposals
,并支持分页标志。
Copy simd query group proposals-by-group-policy [group-policy-account] [flags]
示例:
Copy simd query group proposals-by-group-policy cosmos1..
示例输出:
Copy pagination:
next_key: null
total: "1"
proposals:
- address: cosmos1..
executor_result: EXECUTOR_RESULT_NOT_RUN
group_policy_version: "1"
group_version: "1"
metadata: AQ==
msgs:
- '@type': /cosmos.bank.v1beta1.MsgSend
amount:
- amount: "100000000"
denom: stake
from_address: cosmos1..
to_address: cosmos1..
proposal_id: "1"
proposers:
- cosmos1..
result: RESULT_UNFINALIZED
status: STATUS_SUBMITTED
submitted_at: "2021-12-17T07:06:26.310638964Z"
windows:
min_execution_period: 0s
voting_period: 432000s
vote_state:
abstain_count: "0"
no_count: "0"
veto_count: "0"
yes_count: "0"
summary: "Summary"
title: "Title"
vote
vote
命令允许用户通过 proposal id
和 voter account address
查询 vote
。
Copy simd query group vote [proposal-id] [voter] [flags]
示例:
Copy simd query group vote 1 cosmos1..
示例输出:
Copy vote:
choice: CHOICE_YES
metadata: AQ==
proposal_id: "1"
submitted_at: "2021-12-17T08:05:02.490164009Z"
voter: cosmos1..
votes-by-proposal
votes-by-proposal
命令允许用户通过 proposal id
查询 votes
,并支持分页标志。
Copy simd query group votes-by-proposal [proposal-id] [flags]
示例:
Copy simd query group votes-by-proposal 1
示例输出:
Copy pagination:
next_key: null
total: "1"
votes:
- choice: CHOICE_YES
metadata: AQ==
proposal_id: "1"
submitted_at: "2021-12-17T08:05:02.490164009Z"
voter: cosmos1..
votes-by-voter
votes-by-voter
命令允许用户通过 voter account address
查询 votes
,并支持分页标志。
Copy simd query group votes-by-voter [voter] [flags]
示例:
Copy simd query group votes-by-voter cosmos1..
示例输出:
Copy pagination:
next_key: null
total: "1"
votes:
- choice: CHOICE_YES
metadata: AQ==
proposal_id: "1"
submitted_at: "2021-12-17T08:05:02.490164009Z"
voter: cosmos1..
Transactions
tx
命令允许用户与 group module
进行交互。
create-group
create-group
命令允许用户创建一个 group
,该 group
是由成员账户、关联的权重和一个管理员账户组成的聚合体。
Copy simd tx group create-group [admin] [metadata] [members-json-file]
示例:
Copy simd tx group create-group cosmos1.. "AQ==" members.json
update-group-admin
update-group-admin
命令允许用户更新 group
的管理员。
Copy simd tx group update-group-admin [admin] [group-id] [new-admin] [flags]
示例:
Copy simd tx group update-group-admin cosmos1.. 1 cosmos1..
update-group-members
update-group-members
命令允许用户更新 group
的成员。
Copy simd tx group update-group-members [admin] [group-id] [members-json-file] [flags]
示例:
Copy simd tx group update-group-members cosmos1.. 1 members.json
update-group-metadata
命令允许用户更新 group
的元数据。
Copy simd tx group update-group-metadata [admin] [group-id] [metadata] [flags]
示例:
Copy simd tx group update-group-metadata cosmos1.. 1 "AQ=="
create-group-policy
create-group-policy
命令允许用户创建一个 group policy
,该 group policy
是与 group
和 decision policy
关联的账户。
Copy simd tx group create-group-policy [admin] [group-id] [metadata] [decision-policy] [flags]
示例:
Copy simd tx group create-group-policy cosmos1.. 1 "AQ==" '{"@type":"/cosmos.group.v1.ThresholdDecisionPolicy", "threshold":"1", "windows": {"voting_period": "120h", "min_execution_period": "0s"}}'
create-group-with-policy
create-group-with-policy
命令允许用户创建一个 group
,该 group
是由成员账户、关联的权重和一个管理员账户以及决策政策组成的聚合体。如果 --group-policy-as-admin
标志设置为 true
,则 group policy address
将成为 group
和 group policy
的管理员。
Copy simd tx group create-group-with-policy [admin] [group-metadata] [group-policy-metadata] [members-json-file] [decision-policy] [flags]
示例:
Copy simd tx group create-group-with-policy cosmos1.. "AQ==" "AQ==" members.json '{"@type":"/cosmos.group.v1.ThresholdDecisionPolicy", "threshold":"1", "windows": {"voting_period": "120h", "min_execution_period": "0s"}}'
update-group-policy-admin
update-group-policy-admin
命令允许用户更新 group policy
的管理员。
Copy simd tx group update-group-policy-admin [admin] [group-policy-account] [new-admin] [flags]
示例:
Copy simd tx group update-group-policy-admin cosmos1.. cosmos1.. cosmos1..
update-group-policy-metadata
命令允许用户更新一个组策略元数据。
Copy simd tx group update-group-policy-metadata [admin] [group-policy-account] [new-metadata] [flags]
示例:
Copy simd tx group update-group-policy-metadata cosmos1.. cosmos1.. "AQ=="
update-group-policy-decision-policy
update-group-policy-decision-policy
命令允许用户更新一个组策略的决策策略。
Copy simd tx group update-group-policy-decision-policy [admin] [group-policy-account] [decision-policy] [flags]
示例:
Copy simd tx group update-group-policy-decision-policy cosmos1.. cosmos1.. '{"@type":"/cosmos.group.v1.ThresholdDecisionPolicy", "threshold":"2", "windows": {"voting_period": "120h", "min_execution_period": "0s"}}'
submit-proposal
submit-proposal
命令允许用户提交一个新提案。
Copy simd tx group submit-proposal [group-policy-account] [proposer[,proposer]*] [msg_tx_json_file] [metadata] [flags]
示例:
Copy simd tx group submit-proposal cosmos1.. cosmos1.. msg_tx.json "AQ=="
withdraw-proposal
withdraw-proposal
命令允许用户撤回一个提案。
Copy simd tx group withdraw-proposal [proposal-id] [group-policy-admin-or-proposer]
示例:
Copy simd tx group withdraw-proposal 1 cosmos1..
vote
vote
命令允许用户对一个提案进行投票。
Copy simd tx group vote proposal-id] [voter] [choice] [metadata] [flags]
示例:
Copy simd tx group vote 1 cosmos1.. CHOICE_YES "AQ=="
exec
exec
命令允许用户执行一个提案。
Copy simd tx group exec [proposal-id] [flags]
示例:
leave-group
leave-group
命令允许组成员离开该组。
Copy simd tx group leave-group [member-address] [group-id]
示例:
Copy simd tx group leave-group cosmos1... 1
gRPC
用户可以使用 gRPC 端点查询组模块。
GroupInfo
The GroupInfo
端点允许用户通过给定的组 ID 查询组信息。
Copy cosmos.group.v1.Query/GroupInfo
示例:
Copy grpcurl -plaintext \
-d '{"group_id":1}' localhost:9090 cosmos.group.v1.Query/GroupInfo
示例输出:
Copy {
"info": {
"groupId": "1",
"admin": "cosmos1..",
"metadata": "AQ==",
"version": "1",
"totalWeight": "3"
}
}
GroupPolicyInfo
GroupPolicyInfo
端点允许用户通过组策略的账户地址查询组策略信息。
Copy cosmos.group.v1.Query/GroupPolicyInfo
示例:
Copy grpcurl -plaintext \
-d '{"address":"cosmos1.."}' localhost:9090 cosmos.group.v1.Query/GroupPolicyInfo
示例输出:
Copy {
"info": {
"address": "cosmos1..",
"groupId": "1",
"admin": "cosmos1..",
"version": "1",
"decisionPolicy": {"@type":"/cosmos.group.v1.ThresholdDecisionPolicy","threshold":"1","windows": {"voting_period": "120h", "min_execution_period": "0s"}},
}
}
GroupMembers
GroupMembers
端点允许用户通过组 ID 和分页标志查询组成员。
Copy cosmos.group.v1.Query/GroupMembers
示例:
Copy grpcurl -plaintext \
-d '{"group_id":"1"}' localhost:9090 cosmos.group.v1.Query/GroupMembers
示例输出:
Copy {
"members": [
{
"groupId": "1",
"member": {
"address": "cosmos1..",
"weight": "1"
}
},
{
"groupId": "1",
"member": {
"address": "cosmos1..",
"weight": "2"
}
}
],
"pagination": {
"total": "2"
}
}
GroupsByAdmin
GroupsByAdmin
端点允许用户通过管理员账户地址和分页标志查询组。
Copy cosmos.group.v1.Query/GroupsByAdmin
示例:
Copy grpcurl -plaintext \
-d '{"admin":"cosmos1.."}' localhost:9090 cosmos.group.v1.Query/GroupsByAdmin
示例输出:
Copy {
"groups": [
{
"groupId": "1",
"admin": "cosmos1..",
"metadata": "AQ==",
"version": "1",
"totalWeight": "3"
},
{
"groupId": "2",
"admin": "cosmos1..",
"metadata": "AQ==",
"version": "1",
"totalWeight": "3"
}
],
"pagination": {
"total": "2"
}
}
GroupPoliciesByGroup
GroupPoliciesByGroup
端点允许用户通过组 ID 和分页标志查询组策略。
Copy cosmos.group.v1.Query/GroupPoliciesByGroup
示例:
Copy grpcurl -plaintext \
-d '{"group_id":"1"}' localhost:9090 cosmos.group.v1.Query/GroupPoliciesByGroup
示例输出:
Copy {
"GroupPolicies": [
{
"address": "cosmos1..",
"groupId": "1",
"admin": "cosmos1..",
"version": "1",
"decisionPolicy": {"@type":"/cosmos.group.v1.ThresholdDecisionPolicy","threshold":"1","windows":{"voting_period": "120h", "min_execution_period": "0s"}},
},
{
"address": "cosmos1..",
"groupId": "1",
"admin": "cosmos1..",
"version": "1",
"decisionPolicy": {"@type":"/cosmos.group.v1.ThresholdDecisionPolicy","threshold":"1","windows":{"voting_period": "120h", "min_execution_period": "0s"}},
}
],
"pagination": {
"total": "2"
}
}
GroupPoliciesByAdmin
GroupPoliciesByAdmin
端点允许用户通过管理员账户地址和分页标志查询组策略。
Copy cosmos.group.v1.Query/GroupPoliciesByAdmin
示例:
Copy grpcurl -plaintext \
-d '{"admin":"cosmos1.."}' localhost:9090 cosmos.group.v1.Query/GroupPoliciesByAdmin
示例输出:
Copy {
"GroupPolicies": [
{
"address": "cosmos1..",
"groupId": "1",
"admin": "cosmos1..",
"version": "1",
"decisionPolicy": {"@type":"/cosmos.group.v1.ThresholdDecisionPolicy","threshold":"1","windows":{"voting_period": "120h", "min_execution_period": "0s"}},
},
{
"address": "cosmos1..",
"groupId": "1",
"admin": "cosmos1..",
"version": "1",
"decisionPolicy": {"@type":"/cosmos.group.v1.ThresholdDecisionPolicy","threshold":"1","windows":{"voting_period": "120h", "min_execution_period": "0s"}},
}
],
"pagination": {
"total": "2"
}
}
Proposal
Proposal
端点允许用户通过 ID 查询提案。
Copy cosmos.group.v1.Query/Proposal
示例:
Copy grpcurl -plaintext \
-d '{"proposal_id":"1"}' localhost:9090 cosmos.group.v1.Query/Proposal
示例输出:
Copy {
"proposal": {
"proposalId": "1",
"address": "cosmos1..",
"proposers": [
"cosmos1.."
],
"submittedAt": "2021-12-17T07:06:26.310638964Z",
"groupVersion": "1",
"GroupPolicyVersion": "1",
"status": "STATUS_SUBMITTED",
"result": "RESULT_UNFINALIZED",
"voteState": {
"yesCount": "0",
"noCount": "0",
"abstainCount": "0",
"vetoCount": "0"
},
"windows": {
"min_execution_period": "0s",
"voting_period": "432000s"
},
"executorResult": "EXECUTOR_RESULT_NOT_RUN",
"messages": [
{"@type":"/cosmos.bank.v1beta1.MsgSend","amount":[{"denom":"stake","amount":"100000000"}],"fromAddress":"cosmos1..","toAddress":"cosmos1.."}
],
"title": "Title",
"summary": "Summary",
}
}
ProposalsByGroupPolicy
ProposalsByGroupPolicy
端点允许用户通过组策略的账户地址和分页标志查询提案。
Copy cosmos.group.v1.Query/ProposalsByGroupPolicy
示例:
Copy grpcurl -plaintext \
-d '{"address":"cosmos1.."}' localhost:9090 cosmos.group.v1.Query/ProposalsByGroupPolicy
示例输出:
Copy {
"proposals": [
{
"proposalId": "1",
"address": "cosmos1..",
"proposers": [
"cosmos1.."
],
"submittedAt": "2021-12-17T08:03:27.099649352Z",
"groupVersion": "1",
"GroupPolicyVersion": "1",
"status": "STATUS_CLOSED",
"result": "RESULT_ACCEPTED",
"voteState": {
"yesCount": "1",
"noCount": "0",
"abstainCount": "0",
"vetoCount": "0"
},
"windows": {
"min_execution_period": "0s",
"voting_period": "432000s"
},
"executorResult": "EXECUTOR_RESULT_NOT_RUN",
"messages": [
{"@type":"/cosmos.bank.v1beta1.MsgSend","amount":[{"denom":"stake","amount":"100000000"}],"fromAddress":"cosmos1..","toAddress":"cosmos1.."}
],
"title": "Title",
"summary": "Summary",
}
],
"pagination": {
"total": "1"
}
}
VoteByProposalVoter
VoteByProposalVoter
端点允许用户通过提案 ID 和投票者账户地址查询投票。
Copy cosmos.group.v1.Query/VoteByProposalVoter
示例:
Copy grpcurl -plaintext \
-d '{"proposal_id":"1","voter":"cosmos1.."}' localhost:9090 cosmos.group.v1.Query/VoteByProposalVoter
示例输出:
Copy {
"vote": {
"proposalId": "1",
"voter": "cosmos1..",
"choice": "CHOICE_YES",
"submittedAt": "2021-12-17T08:05:02.490164009Z"
}
}
VotesByProposal
VotesByProposal
端点允许用户通过提案 ID 和分页标志查询投票。
Copy cosmos.group.v1.Query/VotesByProposal
示例:
Copy grpcurl -plaintext \
-d '{"proposal_id":"1"}' localhost:9090 cosmos.group.v1.Query/VotesByProposal
示例输出:
Copy {
"votes": [
{
"proposalId": "1",
"voter": "cosmos1..",
"choice": "CHOICE_YES",
"submittedAt": "2021-12-17T08:05:02.490164009Z"
}
],
"pagination": {
"total": "1"
}
}
VotesByVoter
VotesByVoter
端点允许用户通过投票者账户地址和分页标志查询投票。
Copy cosmos.group.v1.Query/VotesByVoter
示例:
Copy grpcurl -plaintext \
-d '{"voter":"cosmos1.."}' localhost:9090 cosmos.group.v1.Query/VotesByVoter
示例输出:
Copy {
"votes": [
{
"proposalId": "1",
"voter": "cosmos1..",
"choice": "CHOICE_YES",
"submittedAt": "2021-12-17T08:05:02.490164009Z"
}
],
"pagination": {
"total": "1"
}
}
REST
用户可以使用 REST 端点查询组模块。
GroupInfo
GroupInfo
端点允许用户通过给定的组 ID 查询组信息。
Copy /cosmos/group/v1/group_info/{group_id}
示例:
Copy curl localhost:1317/cosmos/group/v1/group_info/1
示例输出:
Copy {
"info": {
"id": "1",
"admin": "cosmos1..",
"metadata": "AQ==",
"version": "1",
"total_weight": "3"
}
}
GroupPolicyInfo
GroupPolicyInfo
端点允许用户通过组策略的账户地址查询组策略信息。
Copy /cosmos/group/v1/group_policy_info/{address}
示例:
Copy curl localhost:1317/cosmos/group/v1/group_policy_info/cosmos1..
示例输出:
Copy {
"info": {
"address": "cosmos1..",
"group_id": "1",
"admin": "cosmos1..",
"metadata": "AQ==",
"version": "1",
"decision_policy": {
"@type": "/cosmos.group.v1.ThresholdDecisionPolicy",
"threshold": "1",
"windows": {
"voting_period": "120h",
"min_execution_period": "0s"
}
},
}
}
GroupMembers
GroupMembers
端点允许用户通过组 ID 和分页标志查询组成员。
Copy /cosmos/group/v1/group_members/{group_id}
示例:
Copy curl localhost:1317/cosmos/group/v1/group_members/1
示例输出:
Copy {
"members": [
{
"group_id": "1",
"member": {
"address": "cosmos1..",
"weight": "1",
"metadata": "AQ=="
}
},
{
"group_id": "1",
"member": {
"address": "cosmos1..",
"weight": "2",
"metadata": "AQ=="
}
],
"pagination": {
"next_key": null,
"total": "2"
}
}
GroupsByAdmin
GroupsByAdmin
端点允许用户通过管理员账户地址和分页标志查询组。
Copy /cosmos/group/v1/groups_by_admin/{admin}
示例:
Copy curl localhost:1317/cosmos/group/v1/groups_by_admin/cosmos1..
示例输出:
Copy {
"groups": [
{
"id": "1",
"admin": "cosmos1..",
"metadata": "AQ==",
"version": "1",
"total_weight": "3"
},
{
"id": "2",
"admin": "cosmos1..",
"metadata": "AQ==",
"version": "1",
"total_weight": "3"
}
],
"pagination": {
"next_key": null,
"total": "2"
}
}
GroupPoliciesByGroup
GroupPoliciesByGroup
端点允许用户通过组 ID 和分页标志查询组策略。
Copy /cosmos/group/v1/group_policies_by_group/{group_id}
示例:
Copy curl localhost:1317/cosmos/group/v1/group_policies_by_group/1
示例输出:
Copy {
"group_policies": [
{
"address": "cosmos1..",
"group_id": "1",
"admin": "cosmos1..",
"metadata": "AQ==",
"version": "1",
"decision_policy": {
"@type": "/cosmos.group.v1.ThresholdDecisionPolicy",
"threshold": "1",
"windows": {
"voting_period": "120h",
"min_execution_period": "0s"
}
},
},
{
"address": "cosmos1..",
"group_id": "1",
"admin": "cosmos1..",
"metadata": "AQ==",
"version": "1",
"decision_policy": {
"@type": "/cosmos.group.v1.ThresholdDecisionPolicy",
"threshold": "1",
"windows": {
"voting_period": "120h",
"min_execution_period": "0s"
}
},
}
],
"pagination": {
"next_key": null,
"total": "2"
}
}
GroupPoliciesByAdmin
GroupPoliciesByAdmin
端点允许用户通过管理员账户地址和分页标志查询组策略。
Copy /cosmos/group/v1/group_policies_by_admin/{admin}
示例:
Copy curl localhost:1317/cosmos/group/v1/group_policies_by_admin/cosmos1..
示例输出:
Copy {
"group_policies": [
{
"address": "cosmos1..",
"group_id": "1",
"admin": "cosmos1..",
"metadata": "AQ==",
"version": "1",
"decision_policy": {
"@type": "/cosmos.group.v1.ThresholdDecisionPolicy",
"threshold": "1",
"windows": {
"voting_period": "120h",
"min_execution_period": "0s"
}
},
},
{
"address": "cosmos1..",
"group_id": "1",
"admin": "cosmos1..",
"metadata": "AQ==",
"version": "1",
"decision_policy": {
"@type": "/cosmos.group.v1.ThresholdDecisionPolicy",
"threshold": "1",
"windows": {
"voting_period": "120h",
"min_execution_period": "0s"
}
},
}
],
"pagination": {
"next_key": null,
"total": "2"
}
Proposal
Proposal
端点允许用户通过 ID 查询提案。
Copy /cosmos/group/v1/proposal/{proposal_id}
示例:
Copy curl localhost:1317/cosmos/group/v1/proposal/1
示例输出:
Copy {
"proposal": {
"proposal_id": "1",
"address": "cosmos1..",
"metadata": "AQ==",
"proposers": [
"cosmos1.."
],
"submitted_at": "2021-12-17T07:06:26.310638964Z",
"group_version": "1",
"group_policy_version": "1",
"status": "STATUS_SUBMITTED",
"result": "RESULT_UNFINALIZED",
"vote_state": {
"yes_count": "0",
"no_count": "0",
"abstain_count": "0",
"veto_count": "0"
},
"windows": {
"min_execution_period": "0s",
"voting_period": "432000s"
},
"executor_result": "EXECUTOR_RESULT_NOT_RUN",
"messages": [
{
"@type": "/cosmos.bank.v1beta1.MsgSend",
"from_address": "cosmos1..",
"to_address": "cosmos1..",
"amount": [
{
"denom": "stake",
"amount": "100000000"
}
]
}
],
"title": "Title",
"summary": "Summary",
}
}
ProposalsByGroupPolicy
ProposalsByGroupPolicy
端点允许用户通过组策略的账户地址和分页标志查询提案。
Copy /cosmos/group/v1/proposals_by_group_policy/{address}
示例:
Copy curl localhost:1317/cosmos/group/v1/proposals_by_group_policy/cosmos1..
示例输出:
Copy {
"proposals": [
{
"id": "1",
"group_policy_address": "cosmos1..",
"metadata": "AQ==",
"proposers": [
"cosmos1.."
],
"submit_time": "2021-12-17T08:03:27.099649352Z",
"group_version": "1",
"group_policy_version": "1",
"status": "STATUS_CLOSED",
"result": "RESULT_ACCEPTED",
"vote_state": {
"yes_count": "1",
"no_count": "0",
"abstain_count": "0",
"veto_count": "0"
},
"windows": {
"min_execution_period": "0s",
"voting_period": "432000s"
},
"executor_result": "EXECUTOR_RESULT_NOT_RUN",
"messages": [
{
"@type": "/cosmos.bank.v1beta1.MsgSend",
"from_address": "cosmos1..",
"to_address": "cosmos1..",
"amount": [
{
"denom": "stake",
"amount": "100000000"
}
]
}
]
}
],
"pagination": {
"next_key": null,
"total": "1"
}
}
VoteByProposalVoter
VoteByProposalVoter
端点允许用户通过提案 ID 和投票者账户地址查询投票。
Copy /cosmos/group/v1/vote_by_proposal_voter/{proposal_id}/{voter}
示例:
Copy curl localhost:1317/cosmos/group/v1beta1/vote_by_proposal_voter/1/cosmos1..
示例输出:
Copy {
"vote": {
"proposal_id": "1",
"voter": "cosmos1..",
"choice": "CHOICE_YES",
"metadata": "AQ==",
"submitted_at": "2021-12-17T08:05:02.490164009Z"
}
}
VotesByProposal
VotesByProposal
端点允许用户通过提案 ID 和分页标志查询投票。
Copy /cosmos/group/v1/votes_by_proposal/{proposal_id}
示例:
Copy curl localhost:1317/cosmos/group/v1/votes_by_proposal/1
示例输出:
Copy {
"votes": [
{
"proposal_id": "1",
"voter": "cosmos1..",
"option": "CHOICE_YES",
"metadata": "AQ==",
"submit_time": "2021-12-17T08:05:02.490164009Z"
}
],
"pagination": {
"next_key": null,
"total": "1"
}
}
VotesByVoter
VotesByVoter
端点允许用户通过投票者账户地址和分页标志查询投票。
Copy /cosmos/group/v1/votes_by_voter/{voter}
示例:
Copy curl localhost:1317/cosmos/group/v1/votes_by_voter/cosmos1..
示例输出:
Copy {
"votes": [
{
"proposal_id": "1",
"voter": "cosmos1..",
"choice": "CHOICE_YES",
"metadata": "AQ==",
"submitted_at": "2021-12-17T08:05:02.490164009Z"
}
],
"pagination": {
"next_key": null,
"total": "1"
}
}
元数据
组模块有四个位置用于元数据,用户可以在这些位置提供更多关于他们所采取的链上操作的上下文。默认情况下,所有元数据字段的长度为 255 个字符,可以以 JSON 格式存储元数据,具体是链上存储还是链下存储,取决于所需的数据量。我们在此提供 JSON 结构的建议,以及数据应存储的位置。在做出这些建议时,有两个重要因素。首先,组模块和治理模块之间需要保持一致性,需要注意的是,所有组提出的提案数量可能非常庞大。其次,客户端应用程序,如区块浏览器和治理界面,需要对跨链的元数据结构的一致性有信心。
Proposal
Copy {
"title": "",
"authors": [""],
"summary": "",
"details": "",
"proposal_forum_url": "",
"vote_option_context": "",
}
:::note authors
字段是一个字符串数组,用于允许在元数据中列出多个作者。在 v0.46 版本中,authors
字段是一个逗号分隔的字符串。前端应用程序建议支持这两种格式,以保持向后兼容性。 :::
Vote
Copy {
"justification": "",
}
Group
位置:链下作为存储在 IPFS 上的 JSON 对象。
Copy {
"name": "",
"description": "",
"group_website_url": "",
"group_forum_url": "",
}
Decision policy
位置:链上作为 JSON 存储在 255 字符限制内。
Copy {
"name": "",
"description": "",
}