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

链客,专为开发者而生,有问必答!

此文章来自区块链技术社区,未经允许拒绝转载。
在这里插入图片描述
eosio.system 概览
笔者使用的IDE是VScode,首先来看eosio.system的源码结构。如下图所示。

本文分析的源码来自于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::optionaleosio::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
定义在libraries\eosiolib\producer_schedule.hpp。该结构体定义了有效生产者集合的出块顺序、账户名以及签名密钥。

struct producer_schedule {
// 时间计划的版本号,按顺序递增。
uint32_t version;
// 此计划的生产者列表,包括其签名密钥
std::vector<producer_key> producers;
};
陌生的部分是producer_key,该结构体定义在libraries\eosiolib\privileged.hpp,是用来映射生产者及其签名密钥,用于生产者计划。

struct producer_key {
name producer_name;
// 此生产者使用的区块签名密钥
public_key block_signing_key;
// 重载运算符小于号,producer_key的两个对象进行小于号比较时,返回的是其name类型的生产者账户的比较。
friend constexpr bool operator < ( const producer_key& a, const producer_key& b ) {
return a.producer_name < b.producer_name;
}

EOSLIB_SERIALIZE( producer_key, (producer_name)(block_signing_key) )
};
一个问题:name类型是EOS中账户类型,那么它的对象是如何比较的?请转到第二大节。

abihash
native.hpp除了声明以上必要结构体以外,还协助eosio.system合约定义了一个状态表abihash。该状态表只有两个字段,一个是账户名,另一个是hash,该hash是当前账户的abi。在EOS中,一个账户除了通过命令

cleos get account xxxxxxxxxxxx

获得自身属性之外,还可以通过分别通过命令get code和get abi获得该账户部署的合约的abi hash以及code hash,这两个hash是用来校验其部署的智能合约的内容是否发生改变。其中abi hash就是存储在native.hpp定义的状态表中。下面是源码内容:

struct [[eosio::table(“abihash”), eosio::contract(“eosio.system”)]] abi_hash {
name owner;
capi_checksum256 hash;
uint64_t primary_key()const { return owner.value; } // 以账户的值作为该表的主键。

EOSLIB_SERIALIZE( abi_hash, (owner)(hash) )
};
注意:通过[[eosio::table(“abihash”), eosio::contract(“eosio.system”)]]的方式可以为合约定义一个状态表,而不再需要原始的typedef multi_index的方式了。这种方式适用于只有主键的情况,如果有多级索引,仍旧需要multi_index。

native合约类
先展示位于native.hpp文件中的native合约类以及位于eosio.system.hpp文件中的system_contract的区别。

class [[eosio::contract(“eosio.system”)]] native : public eosio::contract

class [[eosio::contract(“eosio.system”)]] system_contract : public native

eosio::contract是EOS中所有智能合约的基类,native合约类继承于它,然后system_contract合约类继承于native,而他们二者共同组成了eosio.system智能合约。这种方式让原本单一的智能合约架构变得丰富。作为基类的native,它都声明了eosio.system的哪些属性呢?下面仔细观瞧。

[[eosio::action]] newaccount
我们常用的system newaccount功能就是在native中声明的。该action在创建新帐户后调用,此代码强制实施新帐户的资源限制规则以及新帐户命名约定。规则包含两个:

帐户不能包含’.’ 强制所有帐户的符号长度为12个字符而没有“.” 直到实施未来的帐户拍卖流程。
新帐户必须包含最少数量的token(如系统参数中所设置),因此,此方法将为新用户执行内联buyram购买内存,其金额等于当前新帐户的创建费用。
[[eosio::action]]
void newaccount( name creator,
name name,
ignore owner,
ignore active);
陌生的部分是ignore,该结构位于libraries\eosiolib\ignore.hpp。

ignore
告诉数据流忽略此类型,但允许abi生成器添加正确的类型。当前非忽略类型不能在方法定义中成功忽略类型,即允许

void foo(float,ignore

但不允许

void foo(float,ignore

因为int已经被声明为忽略类型,所以后面不能再作为非忽略类型出现了。ignore结构体源码如下:

template
struct [[eosio::ignore]] ignore {};
其他[[eosio::action]]
动作

返回值

参数

解释

updateauth

void

ignore

更新账户的某项权限内容

deleteauth

void

ignore

删除账户的某项权限内容

linkauth

void

ignore

连接其他账户

unlinkauth

void

ignore

解除某账户的连接

canceldelay

void

ignore<permission_level> canceling_authignore<capi_checksum256> trx_id

取消某个延迟交易

onerror

void

ignore<uint128_t> sender_idignore<std::vector

处理错误

setabi

void

name accountconst std::vector

设置账户的abi内容

setcode

void

name accountuint8_t vmtypeuint8_t vmversionconst std::vector

设置账户的code内容

二、name.hpp
name结构体定义在libraries\eosiolib\name.hpp,源码注释如下:

struct name {
public:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值