EOS [进阶篇][EOS 源码分析] 8.EOS 保留权限 eosio.code 深度解读

itleaks · 2018年09月19日 · 307 次阅读

inline action简单来说就是action调用另外一个action, 具体来说就是一个智能合约的代码调用另外一个智能合约的函数。

eoiso.code这一特殊权限是dawn4.0后新增的内部特殊权限,用来加强inline action的安全性。比如alice调用智能合约contract1.test,一开始alice看过contract1.test的逻辑,发现它只是一个打印函数,并不会调用其他合约。所以alice以自己active的权限alice@active去执行contract1.test。但是contract1的拥有者某一天可能偷偷更改了test的实现,在test函数中调用eosio.token的transfer函数以alice@active权限就可以取走alice的EOS. 为了解决权限乱用问题,EOS新增了eosio.code这个特殊权限。采用eosio.code后,contract1.test要以alice@active去调用eosio.token,必须得到alice的授权,即必须在alice@active里添加contrac1@eosio.code授权

$cleos set account permission alice active '{"threshold": 1,"keys": [{"key":"EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV", 
"weight":1}],"accounts": [{"permission":{"actor":"contract1","permission":"eosio.code"},"weight":1}]}' owner -p alice@owner

即用户调用push action -p permission授权的权限只作用域该action,要用到其他action必须再授权eosio.code


Inline action权限分析

我们以【inline action开发实践】博文中的实例为例,hello.code智能合约调用hello.target合约

class hello : public eosio::contract {  

  public:

    using contract::contract;

    /// @abi action 

    void hi( account_name from, account_name to) {

        require_auth(from);

        print( "Hello, from:", name{from}, ", to:", name{to});

        action(

            //这里{to, active}必须授权给{_self, eosio.code}

            permission_level{to, N(active)},

            //调用 hello.target合约 的'callme' action

            N(hello.target), N(callme),

            std::make_tuple(to)

         ).send();

    }

};

通过下面的命令执行hello.code智能合约

$cleos push action hello.code hi '["args.user","args.user1"]' -p args.user

调用时序图如下

时序图中有2次调用check_authorization

  • 3中的check_authorization是检测交易的签名是否满足action 'hello.code@hi'调用的权限声明args.user@active,这个检测机制已经在【EOS权限机制】一文已经详细分析过了

  • 11中的check_authorization是检测hello.code@eosio.code是否满足action "hello.target@callme"的权限声明to@active(这里的to='args.user1'),也就是args.user1@active。所以为了让这个inline action调用成功,必须添加如下授权

    $cleos set account permission args.user1 active '{"threshold": 1,"keys": [],"accounts": [{"permission":{"actor":"hello.code",
    "permission":"eosio.code"},"weight":1}]}' owner -p args.user1@owner
    

    这里有个疑问,为啥是检测(hello.code, eosio.code)授权是否满足权限声明呢?我们仔细看下上面的hi代码

    void hi( account_name from, account_name to) {
    
        require_auth(from);
    
        print( "Hello, from:", name{from}, ", to:", name{to});
    
        action(
    
            //这里{to, active}必须授权给{_self, eosio.code}
    
            permission_level{to, N(active)},
    
            //调用 hello.target合约 的'callme' action
    
            N(hello.target), N(callme),
    
            std::make_tuple(to)
    
         ).send();
    
    }
    

    当hello.code智能合约代码通过action.send调用其他智能合约时,hi代码是拿不到任何私钥的,也就没法为声明的权限签名,即没法证明该智能合约具备action声明的权限to@active。因此,只有系统代码做担保了,因而系统提出了一个虚拟权限eosio.code。然后系统直接告诉系统检验逻辑(authorization_manager) ,‘action(hello.target)’已经具备hello.code@eosio.code权限。然后authorization_manager只需检验to@active是否授权给hello.code@eosio.code即可。通过这种虚拟的权限证明解决了合约调用合约的权限检测问题

上面红色的部分就是系统代为担保的权限证明。对于用户直接提交的action,这个权限证明是从transaction的签名里恢复出来的

原文链接:https://blog.csdn.net/itleaks/article/details/80557560

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册