eos源码赏析(十二):EOS之从“狼人游戏”看智能合约调用及权限分配(下)

2021-11-23 10:31:37 浏览数 (1)

接上篇,本篇从智能合约内部权限使用出发,结合“狼人游戏”源码,谈谈eosio中权限的分配及使用,本文主要分为以下三部分:

  • 狼人团队的声明探析
  • 多签名账户
  • 权限eosio.code的相关说明

狼人团队的声明

eos3d合约地址

https://github.com/yanxi-me/eos3d-contract

在“狼人游戏”源码底部,其团队已声明:

将owner 权限已经移交给了eosio.prods,即所有的出块节点(BP),active 权限为合约代码本身,这是为了可以利用合约实现自动提币。开发团队已经对合约没有任何控制权限。但其做过的恶会永远记录在这条链上,从笔者角度出发,不建议参与这种资金盘游戏,哪怕源码已公开,你对源码已经了如指掌,但奈何eos中合约可更新机制,我们还是无法确保合约开发者永远不作恶。

由于源码已作出更新,我们就从最新的代码开始看。狼人游戏需要我们拿一定量的eos代币以某一比例去兑换相应的狼人系统的货币,这个过程其实可以看做为抵押,将自己的eos代币抵押至狼人团队的账户。而后有分红以及最后的获奖,均为从狼人团队账户转账至分红者及最后的获奖者。在狼人团队最新的声明中指出:active 权限为合约代码本身,这是为了可以利用合约实现自动提币,那么我们来看看是如何进行提币的(也可参考exchange合约中的内容或者dice小游戏中的内容),代码如下:

图1 eos3d::withdraw的实现

从上图中可以看出,_this_contract(即本合约,或称狼人游戏)的active权限是保留着的,但一个合约的部署或者更新使用active权限即可。我们从上篇文章中(eos源码赏析(十一):EOS之从“狼人游戏”看智能合约调用及权限分配(上))也可以得知:内联通信采用调用其他action的形式,这些action需要作为调用操作的一部分来执行。在确保当前action可以执行的情况下,内联操作使用和当前action相同的域和权限进行操作。而在withdraw中使用action send的形式调用eosio.token给分红者或最后中奖者转出一定量的eos代币,此处使用了该合约账户的active权限。

作为eos的开发者我们都应知道,eos的智能合约是可以更新的,前期狼人游戏获取用户权限甚至更新用户权限,本文不谈溢出问题,从权限的角度出发这些潜在危险就令人惊惧。具体权限的解释说明及测试,可参考以下文章币乎大佬荆凯的文章:

https://bihu.com/article/1074544

关于owner和active的权限在官方文档及众多博文内容中已经有过许多介绍,不管是开发者还是eos的持有者都应当有相当高的警惕在保存好自己私钥的同时,不擅自授权自己账户的active权限给一个不可信智能合约,因为你永远无法保证一个合约开发者不去作恶。

在介绍完狼人团队给出的active权限的相关解释之后,其团队还提到:将owner 权限已经移交给了 eosio.prods中的eosio.prods又是什么呢。我们通过获取账户信息可以看到:

图2 eosio.prods

在上图中我们可以看出这个账户是拥有了排名前15节点的账户的active权限的,也就是说只有这15个节点的账户一致通过某一协定才能使用该active权限。这就涉及到了我们将要谈到的多签名账户。

多签名账户

我们在搭建自己的单机节点使用eosio注册新的账户或者在主网找别人注册账户的时候,均使用了单个账户的active权限。那么这个多签名账户是如何实现的呢?我们以明教为例,为了限制明教教主张无忌的一些作为,将教主的owner权限和active权限分别赋予光明左使杨逍和光明右使范遥的许可。我们先创建三人的账户,然后分别将杨逍和范遥的公钥通过set account permission的形式赋予张无忌这个账户的owner权限,

命令行如下:

cleos set account permission zhangwuji owner'{"threshold": 2, "keys":[{"key":"EOS4yMJpETmGkfdzppQJaJ4cbyqrskAVEmt4vbRHd7kVJ8JVdRkm7","weight":1},{"key":"EOS874qo6PMTt2eTao5S6SC2AxJqPH9DE6f9tS7nsHRbzG1NkrorL","weight":1}], "accounts":[{"permission":{"actor":"fanyao","permission":"owner"},"weight":1},{"permission":{"actor":"yangxiao","permission":"owner"}, "weight":1}],"waits": []}}' -p zhangwuji@owner

active权限的设定也是类似

如下图:

图3 权限设定

通过cleos get account zhangwuji 我们可以看到,张无忌这个账户的owner包含有两个公钥,也是我们刚才注册杨逍和范遥两个账户的公钥,同时其owner权限转交给了yangxiao@owner和fanyao@owner。通过查看账户张无忌中的内容可以看到,其owner为2,也就是我们刚才在设置权限的时候threshold设置为2,此处2表示张无忌这个账户的owner权限操作需要经过杨逍和范遥两人的owner权限才可执行。而如果threshold设置为1的话,则杨逍或者范遥任意一人的aowner权限即可令张无忌的owner权限执行。此时明教也不是张无忌一人说了算了。

在狼人团队转交的owner权限给15个超级节点的active,也就意味着只有15个超级节点的active权限全部同意,狼人团队的智能合约owner权限才可执行,这样源码中没有获取用户权限或更新用户权限的操作,而其owner权限又掌握在eosio.prods手里,大大降低了其主动作恶的风险。但依然,狼人游戏智能合约的active权限还依旧保留着,我们依然要谨慎的参与此类游戏,因合约的部署和更新使用active权限即可,笔者再次建议不授权自己的权限给任何不可信任合约。关于多重签名的使用,集中在系统四大合约之一的eosio.msig智能合约中,我们有时间再进行讨论。

eosio.code的相关说明

我们在查看狼人团队的账户时发现,其账户的active权限有@eosio.code,最近两天群里讨论较多的也是权限相关的内容,我在上一篇内容中也对某个账户使用了eosio.code权限的设置。我们来思考一个问题,假设狼人团队获取了账户user的active权限,他们是否可以通过更新智能合约的形式偷偷的调用eosio.token的transfer函数转走user的eos代币呢?答案也是否定的。这还需要涉及到eosio.code权限的使用,用户user必须授权其active权限中加入狼人团队eosio.code权限,这样针对eosio.token这个合约,狼人团队才可使用user的active权限来操作eosio.token中的相关action。

关于eosio.code权限的issue,大家可以参考下:

https://github.com/EOSIO/eos/issues/4348

对于一个相对去中心的系统来说,权限扮演的角色十分重要,那么这个eosio.code又是什么呢?今天中午在群里关于eosio.code的讨论如下,暂时得出结论如下:不擅自将自己的active权限授权给不可信智能合约的eosio.code特殊权限。

那么eosio.code这个权限又是什么呢?我们从源码中可以看到,eosio.code是个虚拟存在的但不得不使用的特殊权限。那么我个eosio.code的权限校验都使用在哪些地方呢?我们继续来看。

图4 eosio.code

读者中的大部分应该都在帮别人注册主网账户或者自己搭建测试节点的时候使用过newaccount指令,但newaccount指令后面进行了哪些操作,我们可能并未知悉,在图5中便是newaccount的具体信息,在进行对待注册账户的各种校验之后,调用validate_authority_precondition即权限校验的先决条件需要满足注册时赋予了eosio.code权限。

图5 validate_authority_precondition

笔者在翻看代码更新记录时,eosio团队在历史修改中关于validate_authority_precondition函数的解释如下:

A contract no longer satisfies all permissions of its account by default. If a contract needs to be able send an inline action or deferred transaction and requires adding some specific permission to the authorizations of the action, then the authority of that permission must be set up in such a way that it can be satisfied by just the "eosio.code" permission.

也就印证了我们上面所说的action的发起人必须授权其active权限中加入智能合约账户的eosio.code权限,这样针对eosio.token这个合约,智能合约才能用action发起人的active权限来操作eosio.token中的相关action,如issue,如transfer。

而在另一个issue中,有人提出的相关质疑,BM也做了回复,如下:

https://github.com/EOSIO/eos/issues/3002

1、Why does dice contract ask for user‘s active key? the user can not trust so many DApp before to use them in product. And to enable DApp to transfer any cash in any amount from user's account is too dangerous and not acceptable in practice. 2、even dice app version 1.0.0 is secure enough, how to ensure version 1.0.1/1.1.0/1.2.0 .... is enough too? think about this case : a user authorize dice app at version 1.0.0, then a bad guy change dice app and update it maliciously. a). how to let user just auth exactly current version's DApp and do not auth to the future version? b). how to disable contract be updated by other account? it seems anybody can update a DApp in private net.

BM的回答,也就是我们现在在用的版本,加入了eosio.code的虚拟权限

The dice app should be modified so as not to require permission from user to transfer funds. Future feature would be to allow delegation of "contract@eosio.code" to refer to a particular code revision rather than "any code revision".

我们现在来回顾下本篇内容所要表述的事情:

  • 狼人游戏团队智能合约权限的声明
  • 以明教张无忌为例演示多重签名的实现
  • 以群内eosio.code权限的讨论为契机,对eosio.code的使用做分享

通过以上分析我们可以得出以下结论

  • 不管是合约开发者还是代币持有者,都要时刻对权限的授权增加警惕
  • 为了整个生态持续良好的发展,智能合约开发者在无法公开源码的情况下,上交出智能合约账户的部分权限或许是一种很好的方式
  • 多重签名是区块链行业发展的重要组成部分
  • 用户的active权限不授权不可信和智能合约eosio.code权限

最后笔者再哔哔几句,eos或者说区块链的生态还处于初期,很多内容或场景并未完善,作为开发者请爱惜自己的羽毛,毕竟没有羽毛的托付,再厉害的鸟面对蔚然蓝天时也无法起飞.

0 人点赞