【刘文彬】EOS商业落地利器:多签名操做与应用

原文连接:醒者呆的博客园,www.cnblogs.com/Evsward/p/m…html

eos主网上线在即,它之因此能受到各方青睐,主要是看中了它在将来商业应用落地的潜力。在这期间,完善的帐户与权限系统是必要条件。 关键字:eos,帐户,钱包,权限,多重签名,eosio.msig,proposal,权重,阈值node

概况

  • 帐户:是存储在区块链上的人们可识别的ID。
  • 权限:每一个事务都有,它是由已配置许可的帐户所评估的。
  • 阈值:每一个被命名的权限都有一个有效范围,必须知足是在许可下的一个签名事务,将被视为有效。
  • 签名:事务的签名是经过利用一个客户端来执行,该客户端拥有一个已加载并已解锁的钱包。
  • 钱包:能够保护及使用你的keys的一个软件。这些keys多是也可能不是区块链受权的一个许可帐户。

钱包

钱包是一个客户端,用于存储keys,可能与也可能不与一个或多个帐户进行关联。一个钱包会有锁定和解锁两种状态,理想状态下,它是被一个高熵密码所保护。EOSIO有一个命令行客户端cleos,与一个轻客户端keosd交互,它俩构成了eos钱包的这种模式。bash

帐户

一个私人个体或者一个组织均可以拥有帐户,在交易或者其余push一个事务到区块链上的时候,帐户是必须的。 Authorities(权限) 和 Permissions(许可)并发

这两个概念特别容易搞混为一谈,这里给作一下区分。app

Authorities决定了是否每个给出的action都被正确受权。
复制代码

每一个帐户都有两个与生俱来的权限命名:ide

  • owner,象征着一个帐户的全部权。只有不多的事务会须要这种权限。但最值得注意的是,actions能够对owner的权限作出各类改变。因此通常来讲,建议owner被冷藏存储,不告诉任何人。owner能够用来回复另外一个可能已遭泄露的许可。
  • active,用于转移资金,投票生产者以及作其余高级帐户的变动操做。惟一不一样的是,它不可以改变owner。

除了这两个与生俱来的权限。一个帐户也能拥有自定义命名的权限,它能够进一步扩展帐户管理。自定义权限很是灵活而且提出了众多可能的用例实现。在开发者社区,这些问题已经被提了出来,包括他们是如何工做的,以及若是有的话是什么约定被采用了。许可对于任何给定的权限能够被分配到一个或多个公钥或者一个有效的帐户名称。学习

综合实践

下面是结合全部上述概念以及一些小例子,用来展现如何实际使用它们。区块链

默认帐户配置(单签名)

这里主要讲述当一个帐户被建立之后,它是如何配置的。它分别拥有owner和active权限,可独立设置key,两个keys都是权重为1,且许可的阈值也都是1。该帐户在执行某个操做action时,须要经过默认的配置,单独签名受权一个本机权限。测试

建立帐户演示ui

Usage: cleos create account [OPTIONS] creator name OwnerKey [ActiveKey]
复制代码

(在eos正式版本中,activeKey已不强制,变为可选)在建立帐户时,须要指定其owner和active两个权限的key,这里要使用公钥。因此,

liuwenbin@liuwenbin:~$ cleos create account eosio lllwwwbbb "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV"
executed transaction: 7afb37faf4fadaf1b23bbf33a2ec316baf41fcd8e5587f4b2307db091c372829  200 bytes  209 us
# eosio <= eosio::newaccount {"creator":"eosio","name":"lllwwwbbb","owner":{"threshold":1,"keys":[{"key":"EOS6MRyAjQq8ud7hVNYcfnV...
warning: transaction executed locally, but may not be confirmed by the network yet
复制代码

这个版本只须要指定一个owner权限的key便可建立帐户。active权限是小于owner的,因此显得不那么重要。

多签名帐户

上面单签名的内容很简单,之因此介绍它,是为了与本节多签名帐户进行比较学习。
复制代码

多签名帐户,一个帐户假设为Jack的owner和active权限分别被受权为其余两个帐户Alice和Bob的许可。

@Jack

permission account weight threshold
owner 2
@Alice 1
@Bob 1
active 1
@Alice 1
@Bob 1

多帐户权限演示

首先,咱们建立至少三对key:

liuwenbin@liuwenbin:~$ cleos wallet keys
[
  "EOS5WsMPtPqW8d3yxfCWP9WJcbkD3wDBWDfyV2CLagC7tWKT9wGkX",
  "EOS5nrEfZ4wcnmt2u2PGWDneZDNevQ6MoiF4RE3hpLKHk2rWpBB8x",
  "EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV",
  "EOS6PTrfoaTYRHUhCedBf6b9CX3KDpJoWry6WQHe3WkpdFTMV2f78"
]
复制代码

而后,分别使用不一样的public key建立三个帐户:jack, alice和bob,建立成功之后,咱们先来查看当前jack帐户的permission内容:

liuwenbin@liuwenbin:~$ cleos get account jack
permissions:
     owner     1:    1 EOS5WsMPtPqW8d3yxfCWP9WJcbkD3wDBWDfyV2CLagC7tWKT9wGkX
        active     1:    1 EOS5WsMPtPqW8d3yxfCWP9WJcbkD3wDBWDfyV2CLagC7tWKT9wGkX
复制代码

接着,按照上面咱们设计的表格内容,咱们先对jack的owner权限进行修改:

liuwenbin@liuwenbin:~$ cleos set account permission jack owner '{"threshold":2,"keys":[],"accounts":[{"permission":{"actor":"alice","permission":"owner"},"weight":1},{"permission":{"actor":"bob","permission":"owner"},"weight":1}],"waits":[]}' -p jack@owner
executed transaction: 494777ac55fa19144027ba5fdf75dcdaab4c4d52cdcaa13c0b6ecabfe622ffd1  160 bytes  136 us
# eosio <= eosio::updateauth {"account":"jack","permission":"owner","parent":"","auth":{"threshold":2,"keys":[],"accounts":[{"per...
warning: transaction executed locally, but may not be confirmed by the network yet
复制代码
注意这里使用到了 cleos set account permission 命令。这条命令中比较重要的部分是第三个参数authority的内容。
复制代码

authority的内容能够是:

  • NULL,表明删除权限
  • public key,将该权限的内容设置为一个公钥
  • JSON字符串,完整地复杂地设置一个帐户某个权限的内容
  • 一个文件名,同上,只不过改成将完整配置放在文件中读取

根据咱们以上对jack owner权限的设计方案,是属于比较复杂的权限内容,所以这里采用的是第三种方式,及JSON字符串的方式。那么JSON字符串的格式是什么?咱们例举本次生效的配置格式化以下:

{
    "threshold": 2,
    "keys": [],
    "accounts": [
        {
            "permission": {
                "actor": "alice",
                "permission": "owner"
            },
            "weight": 1
        },
        {
            "permission": {
                "actor": "bob",
                "permission": "owner"
            },
            "weight": 1
        }
    ],
    "waits": []
}
复制代码

咱们分别来介绍这里面的字段:

threshold

目前最多只有两个帐户,每一个帐户的权重都是1,因此threshold的取值范围是1或者2。

1:在@Jack帐户上执行任何须要owner权限的操做必须由@Alice或者@Bob帐户任意一个帐户进行签名受权。
2:在@Jack帐户上执行任何须要owner权限的操做必须由@Alice和@Bob帐户进行多签名受权。
复制代码

keys

也能够经过JSON字符串设置秘钥,这与在命令中第三个参数直接使用公钥是相同的效果。可是要注意的是,若是该帐户已经经过JSON设置了复杂的权限内容,再次修改的时候必定还须要使用原JSON数据进行增量修改,若使用命令行加公钥的方式会直接覆盖掉原JSON设置的复杂权限内容。

accounts

权限是经过其余帐户来受权,其中包括:

  • permission:某个帐户actor的某个权限
  • weight,与上面的threshold呼应使用
  • 咱们这里就是经过设置该字段来实现的多帐户签名。

waits

设置延时时间,最大不超过max_transacton_delay的配置值。


下面来设置其active权限,active权限与owner权限不一样的是threshold的值,以及

帐户除了owner权限是根权限之外,active自己是其子权限,而 cleos set account permission 命令设置的权限默认都是active的子权限,注意,咱们在设置active权限自己的时候,要手动指定其父权限为owner,不然会默认指向本身,报错。
复制代码
liuwenbin@liuwenbin:~$ cleos set account permission jack active '{"threshold":1,"keys":[],"accounts":[{"permission":{"actor":"alice","permission":"owner"},"weight":1},{"permission":{"actor":"bob","permission":"owner"},"weight":1}],"waits":[]}' owner -p jack@owner
executed transaction: 0865e7e9122354a2c29fd9ab48bb39b8a7bd758fdd7c4dc376e21ce45d8e23fb  176 bytes  461 us
# eosio <= eosio::updateauth {"account":"jack","permission":"active","parent":"owner","auth":{"threshold":1,"keys":[],"accounts":...
warning: transaction executed locally, but may not be confirmed by the network yet
复制代码

这样,jack帐户的权限就所有按照以上权限设计表格设置完毕了,下面咱们使用命令来验证一下目前jack帐户的权限内容:

liuwenbin@liuwenbin:~$ cleos get account jack
permissions:
     owner     2:    1 alice@owner, 1 bob@owner,
        active     1:    1 alice@owner, 1 bob@owner,
复制代码

多签名演示

一. 部署eosio.msig合约

首先要注意的是,EOS中对多签名的支持是经过eosio.msig智能合约来支持的,所以秉承eos"专人专责"的设计规范,咱们先建立一个帐户eosio.msig,并用该帐户部署eosio.msig合约。
复制代码

若是不是本身新增或者对原合约有修改的话,推荐直接使用build目录下的contract,已经生成好了相关的wast以及abi文件。

二. 部署eosio.token合约

这里咱们使用token合约的相关权限操做进行多签名的演示。一样的,咱们也建立一个帐户eosio.token并用其部署eosio.token合约。建立一个SYS token,并发放给jack,bob和alice三人分别100个。而后咱们调用命令:

liuwenbin@liuwenbin:~$ cleos push action eosio.token transfer '["jack","bob","50 SYS"]' -p jack@owner
executed transaction: 8166f8503a098eeab6642afe375167e18bf79d0d904015f5bba19524ce2d56d6  144 bytes  846 us
# eosio.token <= eosio.token::transfer {"from":"jack","to":"bob","quantity":"50 SYS","memo":""}
# jack <= eosio.token::transfer {"from":"jack","to":"bob","quantity":"50 SYS","memo":""}
# bob <= eosio.token::transfer {"from":"jack","to":"bob","quantity":"50 SYS","memo":""}
warning: transaction executed locally, but may not be confirmed by the network yet
liuwenbin@liuwenbin:~$ cleos get currency balance eosio.token alice
100 SYS
liuwenbin@liuwenbin:~$ cleos get currency balance eosio.token jack
50 SYS
liuwenbin@liuwenbin:~$ cleos get currency balance eosio.token bob
150 SYS
复制代码

该命令执行成功,是由jack@owner权限许可的该命令操做。

三. 描述问题,引出多签名

咱们在上一小节中介绍到了,jack的owner权限是与bob和alice相关的。因此可能遇到这么一个状况,jack今天不在,而它又须要以上的操做怎么办?那么是否能够经过上面对jack权限的设置,在jack不在的状况下经过bob和alice的操做完成本属于jack权限许可的操做呢?是的,这就是多签名的概念和意义。

四. 创建多签名操做提案

首先,eos中关于多签名的命令是multisig,这也是经过第一步中eosio.msig合约实现的。

jack不在,要想经过bob和alice两我的来审批本属于jack的操做,这就要比jack本人操做要麻烦一点,须要新建一个提案。
复制代码
liuwenbin@liuwenbin:~$ cleos multisig propose nojack '[{"actor":"alice","permission":"owner"},{"actor":"bob","permission":"owner"}]' '[{"actor":"jack","permission":"owner"}]' eosio.token transfer '{"from":"jack","to":"bob","quantity":"5 SYS","memo":"test multisig"}' -p eosio.msig
executed transaction: a223945e79c92cd5ca5243d64dce02ecf9bb1420e6ca3b5e5ac3fdae3dd4e8c3  240 bytes  389 us
# eosio.msig <= eosio.msig::propose {"proposer":"eosio.msig","proposal_name":"nojack","requested":[{"actor":"alice","permission":"owner"...
warning: transaction executed locally, but may not be confirmed by the network yet
复制代码
注意在提案中的定义操做要输入完整的key-value对应参数关系。本例中,transfer后面的参数的定义内容与上面直接用jack是一致的,但格式是完整格式,上面jack单签名时是使用的简略版,可自行对比发现。

这个提案结尾须要一个帐户受权,这个帐户是不作限制的,只是为了往后操做这个提案自己,所以这里选择一个不想关的用来部署eosio.msig合约的帐户eosio.msig签名受权该提案。
复制代码

五. 查看提案

liuwenbin@liuwenbin:~$ cleos multisig review eosio.msig nojack
{
  "proposal_name": "nojack",
  "packed_transaction": "38d0295b000000000000000000000100a6823403ea3055000000572d3ccdcd0100000000000091790000000080ab26a72e00000000000091790000000000000e3d320000000000000000535953000000000d74657374206d756c746973696700",
  "transaction": {
    "expiration": "2018-06-20T03:55:36",
    "ref_block_num": 0,
    "ref_block_prefix": 0,
    "max_net_usage_words": 0,
    "max_cpu_usage_ms": 0,
    "delay_sec": 0,
    "context_free_actions": [],
    "actions": [{
        "account": "eosio.token",
        "name": "transfer",
        "authorization": [{
            "actor": "jack",
            "permission": "owner"
          }
        ],
        "data": {
          "from": "jack",
          "to": "bob",
          "quantity": "50 SYS",
          "memo": "test multisig"
        },
        "hex_data": "00000000000091790000000000000e3d320000000000000000535953000000000d74657374206d756c7469736967"
      }
    ],
    "transaction_extensions": []
  }
}
复制代码

重点查看该提案设定的action,包括该action须要的权限,操做名,参数等。

六. 查看提案审批状况

multisig合约定义了两个数据表,其中一个approvals表就是记录了提案的审批状态。

liuwenbin@liuwenbin:~/.local/share/eosio/nodeos/config$ cleos get table eosio.msig eosio.msig approvals                                {
  "rows": [{
      "proposal_name": "nojack",
      "requested_approvals": [{
          "actor": "alice",
          "permission": "owner"
        },{
          "actor": "bob",
          "permission": "owner"
        }
      ],
      "provided_approvals": []
    }],
  "more": false
}
复制代码

七. 审批提案

提案建立完成之后,就须要alice和bob这两个帐户分别进行审批,他们各自都须要使用本身的owner权限签名审批这个动做。

liuwenbin@liuwenbin:~$ cleos multisig approve eosio.msig nojack '{"actor":"alice","permission":"owner"}' -p alice@owner
executed transaction: be473b9abcc361a6d4c00d726318d06cb98775bd9390f2ebe1e4e8d72afd5de2  128 bytes  269 us
# eosio.msig <= eosio.msig::approve {"proposer":"eosio.msig","proposal_name":"nojack","level":{"actor":"alice","permission":"owner"}}
warning: transaction executed locally, but may not be confirmed by the network yet
liuwenbin@liuwenbin:~$ cleos multisig approve eosio.msig nojack '{"actor":"bob","permission":"owner"}' -p bob@owner
executed transaction: 98c707b04ef43b17e25bfb5fb6700300f438ea3af08f5c5f44724bb7f66c9eb2  128 bytes  441 us
# eosio.msig <= eosio.msig::approve {"proposer":"eosio.msig","proposal_name":"nojack","level":{"actor":"bob","permission":"owner"}}
warning: transaction executed locally, but may not be confirmed by the network yet
复制代码

八. 返回第6步

liuwenbin@liuwenbin:~/.local/share/eosio/nodeos/config$ cleos get table eosio.msig eosio.msig approvals                                {
  "rows": [{
      "proposal_name": "nojack",
      "requested_approvals": [],
      "provided_approvals": [{
          "actor": "alice",
          "permission": "owner"
        },{
          "actor": "bob",
          "permission": "owner"
        }
       ]
    }],
  "more": false
}
复制代码

能够看到,原requested_approvals中的待审批项已经所有转到了provided_approvals 已审批列表中。

这里咱们能够经过unapprove命令将已审批项转至未审批集合中去。unapprove的参数与以上approve彻底相同。
复制代码

九. 执行提案

以上两个非jack帐户的审批过程就是多签名的内容,多签名执行成功之后,能够开始执行提案。

liuwenbin@liuwenbin:~$ cleos multisig exec eosio.msig nojack -p eosio.msig
executed transaction: 8734cd573e33c0bbc9f13372f4950908312afdac0146bccae624dba53995bf4b  160 bytes  441 us
# eosio.msig <= eosio.msig::exec {"proposer":"eosio.msig","proposal_name":"nojack","executer":"eosio.msig"}
warning: transaction executed locally, but may not be confirmed by the network yet
复制代码

解决问题:以上提案执行过程会出现执行失败的状况,错误信息:

{"auth":{"actor":"jack","permission":"owner"},"provided_delay":0,"provided_permissions":[{"actor":"eosio.msig","permission":"eosio.code"}],"provided_keys":[],"delay_max_limit_ms":388800000}
复制代码
解决方法是要部署system合约并利用system合约为多签名合约的功能受权,受权成功之后再执行便可成功。
复制代码

cleos push action eosio setpriv '["eosio.msig", 1]' -p eosio 1个小坑:是在部署system合约时报错transaction took too long, 这种状况只须要在执行命令时加 -x 参数,默认值是30s,改成60让时间延长一些便可执行成功。

TODO:立刻会根据当前eos最新版本v1.0.6发出一篇关于环境搭建的配置文章,以免将来踩到与此相似的环境问题。
复制代码

十. 验证结果

执行成功之后,再次检查各帐户的SYS余额,可以发现此提案的转帐50个SYS的操做已经生效。

liuwenbin@liuwenbin:~$ cleos get currency balance eosio.token alice
100 SYS
liuwenbin@liuwenbin:~$ cleos get currency balance eosio.token jack
45 SYS
liuwenbin@liuwenbin:~$ cleos get currency balance eosio.token bob
155 SYS
复制代码

自定义权限

上面提到了,除了owner和active权限以外,咱们还能够自定义权限。仍在以上@Jack帐户中进行补充,增长一个自定义权限,名为publish:

permission account weight threshold
publish 2
@Alice 2
@Bob 2
"EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV" 1

weight:

权重,这是相对于上面threshold阈值的概念,就拿上面的属于帐户@Jack的publish权限来说,它包含三个子权限分别是:

  • @Alice帐户,权重为2
  • @Bob帐户,权重为2
  • 一个keys,权重为1

而此时publish权限的阈值设定为2,也就是说,@Alice或@Bob任意一个帐户都可以签名受权@Jack帐户的publish权限,由于这两个帐户的权重均为2,任意一个签名均可保证够到publish权限的阈值2。而若是只有权重为1的keys签名,则必须再有以上任意一个帐户来同时签名,总权重达到了3,超过了publish阈值2才能够成功受权。

自定义权限部分的演示与上面的相似,经过set account permission能够设置有key,有帐户,不一样权重的十分复杂的权限内容。这里再也不赘述。
复制代码

总结

本文能够分为两部分,第一部分是如何为一个帐户设置复杂的权限体系,第二部分是如何利用帐户权限进行多帐户签名。这部份内容十分灵活,依据这个流程,咱们能够根据业务场景须要,调整设计。例如,多帐户必须均签名才能经过某一个操做,或者多帐户只要其中一个或者多个签名便可经过某一个操做。经过本文所述,都可实现。

参考资料

  • EOS官方文档
  • 本地环境测试(基于EOS v1.0.5)

相关文章和视频推荐

圆方圆学院聚集大批区块链名师,打造精品的区块链技术课程。 在各大平台都长期有优质免费公开课,欢迎报名收看。

公开课地址:ke.qq.com/course/3451…

相关文章
相关标签/搜索