【cosmos-sdk笔记】x-group module

Page content

链中启用组模块,用户可以创建组提交组提案。
也可以将其视为增强型多重签名或 DAO。

1.组模块的几个概念

组管理员(Group Admin)

创建群组的帐号就是组管理员。组管理员可以添加、删除或更改组成员账户。
不是组的成员也可以做组的管理员。

组策略(Group policy)

组策略是连接 组Group 和 决策DecisionPolicy。
为了对此帐户执行操作,提案必须得到大多数小组成员的批准或按照决策政策中的定义进行批准。为避免疑义,请注意一个组可以有多个组策略。

决策(Decision policy)

定义小组成员如何对提案进行投票以及如何计算投票结果的政策。决策策略与组策略相关联。这意味着一个组可以针对其每个不同的组策略有不同的决策策略。

提议(Proposal)

组提议的工作方式与治理提案GovernanceProposal相同。
小组成员可以向小组发送提案以及投票,包括赞成、反对、否决或弃权。

2.配置启动链

simd 版本是 v0.46.6

./simd config chain-id demo
./simd config keyring-backend test

// 添加用户
./simd keys add alice
./simd keys add bob
./simd keys add carol
./simd keys add dave
./simd keys add emma
./simd keys add payee

// 为了方便写到变量
export ALICE=$(./simd keys show alice --address)
export BOB=$(./simd keys show bob --address)

// 初始化链
./simd init test --chain-id demo
./simd add-genesis-account alice 5000000000stake --keyring-backend test
./simd add-genesis-account bob 5000000000stake --keyring-backend test
./simd gentx alice 1000000stake --chain-id demo
./simd collect-gentxs

// 启动
./simd start

3.组织和成员管理

启动 IPFS

group_metadata.json

{
  "name": "Football Association",
  "description": "Best football association",
  "group_website_url": "https://www.footbal.club",
  "group_forum_url": ""
}
// ipfs 添加 metadata
ipfs add group_metadata.json
ipfs daemon

创建组织成员

创建members.json文件

{
    "members": [
        {
            "address": "cosmos1nxqdcm8tjrnf3c4x4082kjdhmmeafvrhkdk5z0",
            "weight": "1",
            "metadata": "president"
        },
        {
            "address": "cosmos1nvsswjsfwcyplqy73zz485cps54ar7r2we9uea",
            "weight": "1",
            "metadata": "treasurer"
        },
        {
            "address": "cosmos1lt803etucw5sj4hgwwv2mv8snqj435md56m645",
            "weight": "1",
            "metadata": "treasurer"
        }
    ]
}
./simd tx group create-group $ALICE "ipfs://QmP2fMonzQRRuqJDw6NjTk5dME9VamR5CwAVEca9kHPgRE" members.json

执行结果

auth_info:
  fee:
    amount: []
    gas_limit: "200000"
    granter: ""
    payer: ""
  signer_infos: []
  tip: null
body:
  extension_options: []
  memo: ""
  messages:
  - '@type': /cosmos.group.v1.MsgCreateGroup
    admin: cosmos1nxqdcm8tjrnf3c4x4082kjdhmmeafvrhkdk5z0
    members:
    - address: cosmos1nxqdcm8tjrnf3c4x4082kjdhmmeafvrhkdk5z0
      metadata: president
      weight: "1"
    - address: cosmos1nvsswjsfwcyplqy73zz485cps54ar7r2we9uea
      metadata: treasurer
      weight: "1"
    - address: cosmos1lt803etucw5sj4hgwwv2mv8snqj435md56m645
      metadata: treasurer
      weight: "1"
    metadata: ipfs://QmP2fMonzQRRuqJDw6NjTk5dME9VamR5CwAVEca9kHPgRE
  non_critical_extension_options: []
  timeout_height: "0"
signatures: []
confirm transaction before signing and broadcasting [y/N]: y
code: 0
codespace: ""
data: ""
events: []
gas_used: "0"
gas_wanted: "0"
height: "0"
info: ""
logs: []
raw_log: '[]'
timestamp: ""
tx: null
txhash: A178228E3A779BBCD57BF570E3CE00E4956A1DC5EB4E46465C3AF551C3397BFA

查看组信息

./simd query tx A178228E3A779BBCD57BF570E3CE00E4956A1DC5EB4E46465C3AF551C3397BFA --output json | jq ".events" | jq '.[] | select(.type == "cosmos.group.v1.EventCreateGroup") | .attributes'

[
  {
    "key": "Z3JvdXBfaWQ=",
    "value": "IjEi",
    "index": true
  }
]

// GROUP_ID存到变量
export GROUP_ID=$(./simd query tx A178228E3A779BBCD57BF570E3CE00E4956A1DC5EB4E46465C3AF551C3397BFA --output json | jq '.events' | jq -r '.[] | select(.type == "cosmos.group.v1.EventCreateGroup") | .attributes[0].value' | base64 --decode | jq -r '.')

// 查看ALICE 的组信息
./simd query group groups-by-admin $ALICE

// 执行结果
groups:
- admin: cosmos1nxqdcm8tjrnf3c4x4082kjdhmmeafvrhkdk5z0
  created_at: "2023-07-03T02:23:14.550862Z"
  id: "1"
  metadata: ipfs://QmP2fMonzQRRuqJDw6NjTk5dME9VamR5CwAVEca9kHPgRE
  total_weight: "3"
  version: "1"
pagination:
  next_key: null
  total: "1"

// 用 GROUP_ID 查看组信息
./simd query group group-members $GROUP_ID
// 执行结果
members:
- group_id: "1"
  member:
    added_at: "2023-07-03T02:23:14.550862Z"
    address: cosmos1nxqdcm8tjrnf3c4x4082kjdhmmeafvrhkdk5z0
    metadata: president
    weight: "1"
- group_id: "1"
  member:
    added_at: "2023-07-03T02:23:14.550862Z"
    address: cosmos1nvsswjsfwcyplqy73zz485cps54ar7r2we9uea
    metadata: treasurer
    weight: "1"
- group_id: "1"
  member:
    added_at: "2023-07-03T02:23:14.550862Z"
    address: cosmos1lt803etucw5sj4hgwwv2mv8snqj435md56m645
    metadata: treasurer
    weight: "1"
pagination:
  next_key: null
  total: "3"

管理 group 成员

members_update.json

{
    "members": [
        {
            "address": "cosmos1lt803etucw5sj4hgwwv2mv8snqj435md56m645", // $carol
            "weight": "0" // this deletes carol
            // The metadata does not need to be mentioned
        },
        {
            "address": "cosmos1d5pca98k23x6wv56n0w3ks3g0x3vw6xf3zvlcv", //daveaddr
            "weight": "1",
            "metadata": "treasurer"
        },
        {
            "address": "cosmos1yu5fukcjp0rz4vk47xwx9upynrfycwtvft7q80", //emmaaddr
            "weight": "1",
            "metadata": "player"
        }
    ]
}
// 更新组成员
./simd tx group update-group-members $ALICE $GROUP_ID members_update.json

// 执行结果
auth_info:
  fee:
    amount: []
    gas_limit: "200000"
    granter: ""
    payer: ""
  signer_infos: []
  tip: null
body:
  extension_options: []
  memo: ""
  messages:
  - '@type': /cosmos.group.v1.MsgUpdateGroupMembers
    admin: cosmos1nxqdcm8tjrnf3c4x4082kjdhmmeafvrhkdk5z0
    group_id: "1"
    member_updates:
    - address: cosmos1lt803etucw5sj4hgwwv2mv8snqj435md56m645
      metadata: ""
      weight: "0"
    - address: cosmos1d5pca98k23x6wv56n0w3ks3g0x3vw6xf3zvlcv
      metadata: treasurer
      weight: "1"
    - address: cosmos1yu5fukcjp0rz4vk47xwx9upynrfycwtvft7q80
      metadata: player
      weight: "1"
  non_critical_extension_options: []
  timeout_height: "0"
signatures: []
confirm transaction before signing and broadcasting [y/N]: y
code: 0
codespace: ""
data: ""
events: []
gas_used: "0"
gas_wanted: "0"
height: "0"
info: ""
logs: []
raw_log: '[]'
timestamp: ""
tx: null
txhash: E74CDC0FD3395E942E8E692DF162C727E4CC5DD47A4F64D9B25DA8573E168ABB

// 查看更新结果
./simd query group group-members $GROUP_ID

// 执行结果
members:
- group_id: "1"
  member:
    added_at: "2023-07-03T02:27:36.485818Z"
    address: cosmos1yu5fukcjp0rz4vk47xwx9upynrfycwtvft7q80
    metadata: player
    weight: "1"
- group_id: "1"
  member:
    added_at: "2023-07-03T02:27:36.485818Z"
    address: cosmos1d5pca98k23x6wv56n0w3ks3g0x3vw6xf3zvlcv
    metadata: treasurer
    weight: "1"
- group_id: "1"
  member:
    added_at: "2023-07-03T02:23:14.550862Z"
    address: cosmos1nxqdcm8tjrnf3c4x4082kjdhmmeafvrhkdk5z0
    metadata: president
    weight: "1"
- group_id: "1"
  member:
    added_at: "2023-07-03T02:23:14.550862Z"
    address: cosmos1nvsswjsfwcyplqy73zz485cps54ar7r2we9uea
    metadata: treasurer
    weight: "1"
pagination:
  next_key: null
  total: "4"

4.创建group policy

创建组策略内容 json
policy.json

  • 提案的投票时间最长为 10 分钟。
  • 一项提案只需一票即可通过。
{
    "@type": "/cosmos.group.v1.ThresholdDecisionPolicy",
    "threshold": "1",
    "windows": {
        "voting_period": "10m",
        "min_execution_period": "0s"
    }
}
// 创建组策略
./simd tx group create-group-policy $ALICE $GROUP_ID "{\"name\":\"quick turnaround\",\"description\":\"\"}" policy.json

// 执行结果
auth_info:
  fee:
    amount: []
    gas_limit: "200000"
    granter: ""
    payer: ""
  signer_infos: []
  tip: null
body:
  extension_options: []
  memo: ""
  messages:
  - '@type': /cosmos.group.v1.MsgCreateGroupPolicy
    admin: cosmos1nxqdcm8tjrnf3c4x4082kjdhmmeafvrhkdk5z0
    decision_policy:
      '@type': /cosmos.group.v1.ThresholdDecisionPolicy
      threshold: "1"
      windows:
        min_execution_period: 0s
        voting_period: 600s
    group_id: "1"
    metadata: '{"name":"quick turnaround","description":""}'
  non_critical_extension_options: []
  timeout_height: "0"
signatures: []
confirm transaction before signing and broadcasting [y/N]: y
code: 0
codespace: ""
data: ""
events: []
gas_used: "0"
gas_wanted: "0"
height: "0"
info: ""
logs: []
raw_log: '[]'
timestamp: ""
tx: null
txhash: 886652122BC69747F8130FEE50C90D93C277F7645120F19993E216A78F2C8CCE

// 组策略ID 存到变量
export GROUP_POLICY_ADDRESS=$(./simd query tx 886652122BC69747F8130FEE50C90D93C277F7645120F19993E216A78F2C8CCE --output json | jq '.events' | jq -r '.[] | select(.type == "cosmos.group.v1.EventCreateGroupPolicy") | .attributes[0].value' | base64 --decode | jq -r '.')

// 通过 GROUP_ID 查看策略
./simd query group group-policies-by-group $GROUP_ID
// 执行结果
group_policies:
- address: cosmos1afk9zr2hn2jsac63h4hm60vl9z3e5u69gndzf7c99cqge3vzwjzsfwkgpd
  admin: cosmos1nxqdcm8tjrnf3c4x4082kjdhmmeafvrhkdk5z0
  created_at: "2023-07-03T02:29:57.599509Z"
  decision_policy:
    '@type': /cosmos.group.v1.ThresholdDecisionPolicy
    threshold: "1"
    windows:
      min_execution_period: 0s
      voting_period: 600s
  group_id: "1"
  metadata: '{"name":"quick turnaround","description":""}'
  version: "1"
pagination:
  next_key: null
  total: "1"

// 查看策略地址
./simd query group group-policies-by-group $GROUP_ID --output json | jq -r '.group_policies[0].address'

// 执行结果
cosmos1afk9zr2hn2jsac63h4hm60vl9z3e5u69gndzf7c99cqge3vzwjzsfwkgpd

// 给策略发币,要不提案结束后,没有钱给 payee
./simd tx bank send $ALICE $GROUP_POLICY_ADDRESS  5000stake
auth_info:
  fee:
    amount: []
    gas_limit: "200000"
    granter: ""
    payer: ""
  signer_infos: []
  tip: null
body:
  extension_options: []
  memo: ""
  messages:
  - '@type': /cosmos.bank.v1beta1.MsgSend
    amount:
    - amount: "5000"
      denom: stake
    from_address: cosmos1nxqdcm8tjrnf3c4x4082kjdhmmeafvrhkdk5z0
    to_address: cosmos1afk9zr2hn2jsac63h4hm60vl9z3e5u69gndzf7c99cqge3vzwjzsfwkgpd
  non_critical_extension_options: []
  timeout_height: "0"
signatures: []
confirm transaction before signing and broadcasting [y/N]: y
code: 0
codespace: ""
data: ""
events: []
gas_used: "0"
gas_wanted: "0"
height: "0"
info: ""
logs: []
raw_log: '[]'
timestamp: ""
tx: null
txhash: 5C579B918D17FCC51952103BD830F1C921808F1A47B91C0F28C0D43516C3F4AC

5.创建proposal

新建提案 IPFS

proposal_metadata.json

{
  "title": "Pay the utilities bill",
  "authors": "Bob Smith",
  "summary": "Pay the energy bill of the association",
  "details": "",
  "proposal_forum_url": "https://football.club/proposal/nov-utility-bills",
  "vote_option_context": "Yes means pay the energy bill. No means to not pay the energy bill and have no more warm water.",
}
ipfs add proposal_metadata.json
added QmTF5BshCyRqnvfGtvYU3gYjfcXaMjLxnNFxdENmTaw6nX proposal_metadata.json

创建提案信息

proposal.json

{
    "group_policy_address": "cosmos1afk9zr2hn2jsac63h4hm60vl9z3e5u69gndzf7c99cqge3vzwjzsfwkgpd" , // the $GROUP_POLICY_ADDRESS
    // array of proto-JSON-encoded sdk.Msgs
    "messages": [
        {
            "@type": "/cosmos.bank.v1beta1.MsgSend",
            "from_address": "cosmos1afk9zr2hn2jsac63h4hm60vl9z3e5u69gndzf7c99cqge3vzwjzsfwkgpd", // the $GROUP_POLICY_ADDRESS
            "to_address": "cosmos1nyvdmlssz6e9sc7ddp37lvxjgqmrm8cgngg204", // payee
            "amount": [
                {
                    "denom": "stake",
                    "amount": "100"
                }
            ]
        }
    ],
    "metadata": "ipfs://QmTF5BshCyRqnvfGtvYU3gYjfcXaMjLxnNFxdENmTaw6nX",
    "proposers": [ "cosmos1nvsswjsfwcyplqy73zz485cps54ar7r2we9uea" ] // $BOB
}
./simd tx group submit-proposal proposal.json --from bob

// 执行结果
auth_info:
  fee:
    amount: []
    gas_limit: "200000"
    granter: ""
    payer: ""
  signer_infos: []
  tip: null
body:
  extension_options: []
  memo: ""
  messages:
  - '@type': /cosmos.group.v1.MsgSubmitProposal
    exec: EXEC_UNSPECIFIED
    group_policy_address: cosmos1afk9zr2hn2jsac63h4hm60vl9z3e5u69gndzf7c99cqge3vzwjzsfwkgpd
    messages:
    - '@type': /cosmos.bank.v1beta1.MsgSend
      amount:
      - amount: "100"
        denom: stake
      from_address: cosmos1afk9zr2hn2jsac63h4hm60vl9z3e5u69gndzf7c99cqge3vzwjzsfwkgpd
      to_address: cosmos1nyvdmlssz6e9sc7ddp37lvxjgqmrm8cgngg204
    metadata: ipfs://QmTF5BshCyRqnvfGtvYU3gYjfcXaMjLxnNFxdENmTaw6nX
    proposers:
    - cosmos1nvsswjsfwcyplqy73zz485cps54ar7r2we9uea
  non_critical_extension_options: []
  timeout_height: "0"
signatures: []
confirm transaction before signing and broadcasting [y/N]: y
code: 0
codespace: ""
data: ""
events: []
gas_used: "0"
gas_wanted: "0"
height: "0"
info: ""
logs: []
raw_log: '[]'
timestamp: ""
tx: null
txhash: 3C402AA94BE6DBB386D75150B101622991859B33B6CCB8AE1F910DA0D70BF1A9

// 提案 ID 存到变量
export PROPOSAL_ID=$(./simd query tx 3C402AA94BE6DBB386D75150B101622991859B33B6CCB8AE1F910DA0D70BF1A9 --output json | jq '.events' | jq -r '.[] | select(.type == "cosmos.group.v1.EventSubmitProposal") | .attributes[0].value' | base64 --decode | jq -r '.')

// 查看策略
./simd query group proposals-by-group-policy $GROUP_POLICY_ADDRESS --output json | jq '.proposals[0]'

//执行结果
{
  "id": "1",
  "group_policy_address": "cosmos1afk9zr2hn2jsac63h4hm60vl9z3e5u69gndzf7c99cqge3vzwjzsfwkgpd",
  "metadata": "ipfs://QmTF5BshCyRqnvfGtvYU3gYjfcXaMjLxnNFxdENmTaw6nX",
  "proposers": [
    "cosmos1nvsswjsfwcyplqy73zz485cps54ar7r2we9uea"
  ],
  "submit_time": "2023-07-03T02:34:59.883957Z",
  "group_version": "2",
  "group_policy_version": "1",
  "status": "PROPOSAL_STATUS_SUBMITTED",
  "final_tally_result": {
    "yes_count": "0",
    "abstain_count": "0",
    "no_count": "0",
    "no_with_veto_count": "0"
  },
  "voting_period_end": "2023-07-03T02:44:59.883957Z",
  "executor_result": "PROPOSAL_EXECUTOR_RESULT_NOT_RUN",
  "messages": [
    {
      "@type": "/cosmos.bank.v1beta1.MsgSend",
      "from_address": "cosmos1afk9zr2hn2jsac63h4hm60vl9z3e5u69gndzf7c99cqge3vzwjzsfwkgpd",
      "to_address": "cosmos1nyvdmlssz6e9sc7ddp37lvxjgqmrm8cgngg204",
      "amount": [
        {
          "denom": "stake",
          "amount": "100"
        }
      ]
    }
  ]
}
// 查看提案信息
./simd query group proposal $PROPOSAL_ID --output json | jq '.proposal.final_tally_result'

// 执行结果
{
  "yes_count": "0",
  "abstain_count": "0",
  "no_count": "0",
  "no_with_veto_count": "0"
}

提案过程

// 查看策略状态
./simd query group proposals-by-group-policy $GROUP_POLICY_ADDRESS --output json | jq -r '.proposals[0].status'
// PROPOSAL_STATUS_SUBMITTED

// alice 同意
./simd tx group vote $PROPOSAL_ID $ALICE VOTE_OPTION_YES "agree"

// 执行结果
auth_info:
  fee:
    amount: []
    gas_limit: "200000"
    granter: ""
    payer: ""
  signer_infos: []
  tip: null
body:
  extension_options: []
  memo: ""
  messages:
  - '@type': /cosmos.group.v1.MsgVote
    exec: EXEC_UNSPECIFIED
    metadata: agree
    option: VOTE_OPTION_YES
    proposal_id: "1"
    voter: cosmos1nxqdcm8tjrnf3c4x4082kjdhmmeafvrhkdk5z0
  non_critical_extension_options: []
  timeout_height: "0"
signatures: []
confirm transaction before signing and broadcasting [y/N]: y
code: 0
codespace: ""
data: ""
events: []
gas_used: "0"
gas_wanted: "0"
height: "0"
info: ""
logs: []
raw_log: '[]'
timestamp: ""
tx: null
txhash: D76DD40FDE665F72565FF3C328C238B14DE8676919A7AB857606817043742F45

./simd tx group vote $PROPOSAL_ID $BOB VOTE_OPTION_YES "aye"
auth_info:
  fee:
    amount: []
    gas_limit: "200000"
    granter: ""
    payer: ""
  signer_infos: []
  tip: null
body:
  extension_options: []
  memo: ""
  messages:
  - '@type': /cosmos.group.v1.MsgVote
    exec: EXEC_UNSPECIFIED
    metadata: aye
    option: VOTE_OPTION_YES
    proposal_id: "1"
    voter: cosmos1nvsswjsfwcyplqy73zz485cps54ar7r2we9uea
  non_critical_extension_options: []
  timeout_height: "0"
signatures: []
confirm transaction before signing and broadcasting [y/N]: y
code: 0
codespace: ""
data: ""
events: []
gas_used: "0"
gas_wanted: "0"
height: "0"
info: ""
logs: []
raw_log: '[]'
timestamp: ""
tx: null
txhash: 45DA109D39742DDB17D867ACCCA011AF4542BAC022421F0F18DB142B55208466


// 查看提案信息
./simd query group tally-result $PROPOSAL_ID
tally:
  abstain_count: "0"
  no_count: "0"
  no_with_veto_count: "0"
  yes_count: "1"

// 查看提案详细
./simd query group proposal $PROPOSAL_ID
proposal:
  executor_result: PROPOSAL_EXECUTOR_RESULT_NOT_RUN
  final_tally_result:
    abstain_count: "0"
    no_count: "0"
    no_with_veto_count: "0"
    yes_count: "1"
  group_policy_address: cosmos1afk9zr2hn2jsac63h4hm60vl9z3e5u69gndzf7c99cqge3vzwjzsfwkgpd
  group_policy_version: "1"
  group_version: "2"
  id: "1"
  messages:
  - '@type': /cosmos.bank.v1beta1.MsgSend
    amount:
    - amount: "100"
      denom: stake
    from_address: cosmos1afk9zr2hn2jsac63h4hm60vl9z3e5u69gndzf7c99cqge3vzwjzsfwkgpd
    to_address: cosmos1nyvdmlssz6e9sc7ddp37lvxjgqmrm8cgngg204
  metadata: ipfs://QmTF5BshCyRqnvfGtvYU3gYjfcXaMjLxnNFxdENmTaw6nX
  proposers:
  - cosmos1nvsswjsfwcyplqy73zz485cps54ar7r2we9uea
  status: PROPOSAL_STATUS_ACCEPTED
  submit_time: "2023-07-03T02:34:59.883957Z"
  voting_period_end: "2023-07-03T02:44:59.883957Z"

立即执行提案结束

./simd tx group exec $PROPOSAL_ID --from alice
auth_info:
  fee:
    amount: []
    gas_limit: "200000"
    granter: ""
    payer: ""
  signer_infos: []
  tip: null
body:
  extension_options: []
  memo: ""
  messages:
  - '@type': /cosmos.group.v1.MsgExec
    executor: cosmos1nxqdcm8tjrnf3c4x4082kjdhmmeafvrhkdk5z0
    proposal_id: "1"
  non_critical_extension_options: []
  timeout_height: "0"
signatures: []
confirm transaction before signing and broadcasting [y/N]: y
code: 0
codespace: ""
data: ""
events: []
gas_used: "0"
gas_wanted: "0"
height: "0"
info: ""
logs: []
raw_log: '[]'
timestamp: ""
tx: null
txhash: A088774E6C590BA008618AE3AE77F70CFACA05664B5080BCB7EC6FC05B653AE6
//查看提案结果会报错,是因为它已被完全删除。
./simd query group proposal $PROPOSAL_ID
Error: rpc error: code = Unknown desc = load proposal: not found: unknown request

查看收款人有没有收到款

./simd query bank balances cosmos1nyvdmlssz6e9sc7ddp37lvxjgqmrm8cgngg204
balances:
- amount: "100"
  denom: stake
pagination:
  next_key: null
  total: "0"

欢迎大家的意见和交流

email: li_mingxie@163.com