【精】EOS智能合约:system系统合约源码分析

系统合约在链启动阶段就会被部署,是因为系统合约赋予了EOS链资源、命名拍卖、基础数据准备、生产者信息、投票等能力。本篇文章将会从源码角度详细研究system合约。

关键字:EOS,eosio.system,智能合约,name类型,native.hpp,newaccount,bidname,core token init,onblock,更新已入选生产节点

eosio.system 概览

笔者使用的IDE是VScode,首先来看eosio.system的源码结构。如下图所示。

image

本文分析的源码来自于eosio.contracts。

一、native.hpp

该文件可以分为两个部分,前一个部分是定义了一些结构体,后一个部分是帮助eosio.system合约声明action。总体看上去,这个文件是负责权限的结构。下面先看他都定义了哪些结构体。

权限等级权重 struct permission_level_weight { permission_level permission; uint16_t weight; EOSLIB_SERIALIZE( permission_level_weight, (permission)(weight) ) };

注意,合约中定义的结构体一般都会在末尾加入EOSLIB_SERIALIZE宏,将结构体的字段属性序列化,这行代码不是必须的,但加上了能够加快解析的速度,从而提升编译效率。

权限等级权重结构体只有两个字段,一个是permission_level类型的对象permission,另一个是16位的无符整型类型的权重。permission_level是定义在eosiolib/action.hpp文件中的一个结构体。它是通过一个账户名以及其权限名构建的,例如{"useraaaaaaaa","active"},这样的一个组合构成了一个权限对象。

公钥权重 struct key_weight { eosio::public_key key; uint16_t weight; EOSLIB_SERIALIZE( key_weight, (key)(weight) ) };

这个结构体的结构与前面的相似,所以陌生的部分只有eosio::public_key,这是定义在eosiolib/crypto.hpp中的结构体,它代表了EOS中一个公钥对象,该对象可以是K1类型或者R1类型。

secp256k1和secp256r1是两种椭圆曲线数学模型,均属于公钥生成算法。私钥生成公钥的算法也即ECC的字面含义椭圆曲线,是通过该数学模型生成的一种正向快速逆向困难的算法,目前这个算法包括secp256k1和secp256r1 ,secp256k1是比特币首先使用的,而secp256r1据说更有优势,但也有被爆漏洞的历史,由于比特币没有使用secp256r1,因此还有“比特币躲过secp256r1子弹”的说法。目前这两种EOS均支持。

等待权重 struct wait_weight { uint32_t wait_sec; uint16_t weight; EOSLIB_SERIALIZE( wait_weight, (wait_sec)(weight) ) };

该结构体没有什么特别的,陌生的部分仍旧只有第一个参数wait_sec,但通过字面含义即可理解,就是等待的秒数。

权力 struct authority { uint32_t threshold = 0; std::vector<key_weight> keys; std::vector<permission_level_weight> accounts; std::vector<wait_weight> waits; EOSLIB_SERIALIZE( authority, (threshold)(keys)(accounts)(waits) ) };

这个结构体比较有趣了,它包含四个属性,其中第一个是32位无符整型类型的阈值,初始化位0。剩余三个属性即以上介绍到的三个结构体的集合对象。所以,这也说明了一个账户的权力是由一个阈值、多个密钥、多个权限、多个等待组成的。下面又到了当春乃发生的“authority”和“permission”的区别问题。

authority 指有权利的人。permission 指某项许可。所以某人需要拥有很多别人授权的许可,才能称之为有权利的人。(希望我解释清楚了♫ ♫♬♪♫ )

区块头 struct block_header { uint32_t timestamp; name producer; uint16_t confirmed = 0; capi_checksum256 previous; capi_checksum256 transaction_mroot; capi_checksum256 action_mroot; uint32_t schedule_version = 0; std::optional<eosio::producer_schedule> new_producers; EOSLIB_SERIALIZE(block_header, (timestamp)(producer)(confirmed)(previous)(transaction_mroot)(action_mroot) (schedule_version)(new_producers)) };

这个结构体有意思了,好像在很多地方都见过block_header的声明,怎么这里又冒出来一个。有这种感觉很正常,因为之前一直研究的内容都集中在链上,之前看到的block_header是链上的声明,并不是智能合约的。通过全文检索可以查到,block_header结构体由两个文件定义:

libraries\chain\include\eosio\chain\block_header.hpp,这个明显是链上的定义,因为路径中包含了chain的字样。

eosio.system\include\eosio.system\native.hpp,另外这一个就是本文介绍的这个结构体了,这是专门服务于智能合约的代码。

所以由此可见,EOS中很多底层的基础结构体都是分两套的,一套给链使用,另一个套给智能合约使用,而他们的定义方式似乎从原来的一模一样发展到今天的些许不同。而目前EOSIO的架构体系中,eosio.contracts作为单独的项目已经从eos分隔出来,并且代码已经发生了不同。因此这种两套体系的概念的困惑会越来越小。

回到native.hpp的区块头结构体。

时间戳,uint32_t类型

生产者,name类型

confirmed,已确认数,uint16_t,初始化为0。

前一个区块的hash,是capi_checksum256类型的

事务Merkle树根,Merkle数的内容请点击以及点击。概况来讲,是为了校验区块内打包的事务的真伪以及完整性的。

action的merkle树根,校验区块内所有action的真伪以及完整性。

计划版本,schedule_version,uint32_t类型,初始化为0。

后续计划出块者。producer_schedule类型。

producer_schedule

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsspgz.html