这里说的eosio智能合约不是泛指eos的智能合约,它是一个特殊的具体的合约。它本事可大了,我们一起来看看它有哪些功能

负责智能合约部署

大家有注意到如下红色字体的log吗

$ cleos set contract hello.code ../eos-contract/hello -p hello.code

Publishing contract...

executed transaction: daabe65267af4b9a11e5ff90a165bbaac68469630f499bcea1ef0eb7da6d970c  1792 bytes  2558 us

#         eosio <= eosio::setcode               {"account":"hello.code","vmtype":0,"vmversion":0,"code":"0061736d01000000013b0c60027f7e006000017e600...

#         eosio <= eosio::setabi                {"account":"hello.code","abi":"00010c6163636f756e745f6e616d65046e616d6501026869000104757365720c61636...

这段log很明显的说明了

$ cleos set contract eosio build/contracts/eosio.bios -p eosio

等价于调用eosio智能合约的setcode和setabi函数

$ cleos push action eosio setcode '[eosio.bios.wasm]' -p eosio

$ cleos push action eosio setabi eosio '[eosio.bios.abi] -p eosio

也就说合约部署是通过调用eosio合约来实现的

对应的源码:

set contract会产生setcode和setabi两个action

add_standard_transaction_options(contractSubcommand, "account@active");

add_standard_transaction_options(codeSubcommand, "account@active");

add_standard_transaction_options(abiSubcommand, "account@active");

contractSubcommand->set_callback([&] {

shouldSend = false;

set_code_callback();

set_abi_callback();

std::cout << localized("Publishing contract...") << std::endl;

send_actions(std::move(actions), 10000, packed_transaction::zlib);

});

chain::action create_setcode(const name& account, const bytes& code) {

return action {

tx_permission.empty() ? vector<chain::permission_level>{{account,config::active_name}} : get_account_permissions(tx_permission),

setcode{

.account   = account,

.vmtype    = 0,

.vmversion = 0,

.code      = code

}

};

}

struct setcode {

account_name                     account;

uint8_t                          vmtype = 0;

uint8_t                          vmversion = 0;

bytes                            code;

static account_name get_account() {

return config::system_account_name;

}

static action_name get_name() {

return N(setcode);

}

};

const static uint64_t system_account_name    = N(eosio);

set_code和set_abi都是通过调用system_account_name即eosio智能合约来执行的

负责账号创建

同样我们看看create account,其实就是调用eosio合约的newaccount函数

$ cleos create account eosio hello.code EOS7KBTMkUq4VPakqsZUnZfBbMbS2U7cn9qSa3q6G5ZzEeUeNSVgv EOS7KBTMkUq4VPakqsZUnZfBbMbS2U7cn9qSa3q6G5ZzEeUeNSVgv

executed transaction: 01aff4356a6277eec777494fc6aeaf97164c53997c46fe853247ed7e100f4987  200 bytes  911 us

#         eosio <= eosio::newaccount            {"creator":"eosio","name":"hello.code","owner":{"threshold":1,"keys":[{"key":"EOS7KBTMkUq4VPakqsZUnZ...

负责权限管理

这次是调用eosio的updateauth函数

$ cleos set account permission testaccount active '{"threshold" : 1, "keys" : [], "accounts" : [{"permission":{"actor":"bob","permission":"active"},"weight":1}, {"permission":{"actor":"stacy","permission":"active"},"weight":1}]}’ owner

executed transaction: b1bc9680a9ba615a6de8c3f7c692d7d28ff97edae245bb40f948692b14ea6c15  160 bytes  189 us

#         eosio <= eosio::updateauth            {"account":"testaccount","permission":"active","parent":"owner","auth":{"threshold":1,"keys":[],"acc...

warning: transaction executed locally, but may not be confirmed by the network yet

蛋生鸡,鸡生蛋问题

既然eosio是一个智能合约,而它又负责合约部署,那它自己是谁部署的呢?我们先来看下这个结构图

eosio contract负责系统服务,比如部署合约,创建账号。infra contracts层比如eosio.token和eosio.msig类似库作用的合约,比如多签名,发行代币,方便dapp层使用。Dapp才是用户直接接触的,每个开发人员编写程序然后部署,这些程序都是DApp。

eosio contract由3个部分构成

  1. nativeaction

nativeactions就是前面提到的setcode, setabi, newaccount功能的函数集。这部分代码是hardcode在EOS系统代码里的,也就说不需要部署这一步骤,所以就解决了蛋生鸡,鸡生蛋问题。

2.  eosio.bios, eosio.system

eosio.bios是一个智能合约的代码,是通过智能合约部署方式绑定到eosio contract上的。那你可能会说,eosio.bios部署后,nativeactions部分是不是就失效了啊。确实可以这样实现,由于setcode这些action需要永久生效,这就需要eosio.bios包含nativeactions这些函数,这样就出现了相同一份代码分散在两个模块,独立性和维护不够好。所以,目前的实现是通过特殊处理让nativeactions的函数有最高优先级,永不覆盖,哪怕eosio.bios实现了同样的函数(比如set_code, set_abi)。但是eosio.system和eosio.bios是一个级别的,都是contract,  是水火不相容的,一旦将eosio.system绑定到eosio这个账号,eosio.bios就失效了,所以eosio.bios的函数要么是临时用途的,要么就需要bios.system重新实现,比如setalimits会失效,而setpriv会在eosio.system重新实现。这个和cpu启动一样,一开始bios(bootloader)代码运行,然后引导system代码,当system加载后,bios(bootloader)代码失效。所以从这个设计和名字可以看出,EOS确实是在按照操作系统的逻辑设计。

eosio.bios的接口

EOSIO_ABI( eosio::bios, (setpriv)(setalimits)(setglimits)(setprods)(reqauth) )

eosio.sytem的接口

EOSIO_ABI( eosiosystem::system_contract,

(setram)

// delegate_bandwith.cpp

(delegatebw)(undelegatebw)(refund)

(buyram)(buyrambytes)(sellram)

// voting.cpp

// producer_pay.cpp

(regproxy)(regproducer)(unregprod)(voteproducer)

(claimrewards)

// native.hpp

(onblock)

(newaccount)(updateauth)(deleteauth)(linkauth)(unlinkauth)(postrecovery)(passrecovery)(vetorecovery)(onerror)(canceldelay)

//this file

(setpriv)

)

nativeaction解读

nativeaction注册

nativeaction是通过SET_APP_HANDLER注册的

#define SET_APP_HANDLER( receiver, contract, action) \

set_apply_handler( #receiver, #contract, #action, &BOOST_PP_CAT(apply_, BOOST_PP_CAT(contract, BOOST_PP_CAT(_,action) ) ) )

SET_APP_HANDLER( eosio, eosio, newaccount );

SET_APP_HANDLER( eosio, eosio, setcode );

SET_APP_HANDLER( eosio, eosio, setabi );

SET_APP_HANDLER( eosio, eosio, updateauth );

SET_APP_HANDLER( eosio, eosio, deleteauth );

SET_APP_HANDLER( eosio, eosio, linkauth );

SET_APP_HANDLER( eosio, eosio, unlinkauth );

/*

SET_APP_HANDLER( eosio, eosio, postrecovery );

SET_APP_HANDLER( eosio, eosio, passrecovery );

SET_APP_HANDLER( eosio, eosio, vetorecovery );

*/

SET_APP_HANDLER( eosio, eosio, canceldelay );

void set_apply_handler( account_name receiver, account_name contract, action_name action, apply_handler v ) {

apply_handlers[receiver][make_pair(contract,action)] = v;

}

对应的函数名是apply_eosio_xxx,比如apply_eosio_setcode,apply_eosio_newaccount

nativeaction函数调用

系统会先检测action的名字是否注册在native handler里,如果在则直接调用,不在的话,执行合约代码,并跳转到相应的action函数

class apply_context {

{

public:

apply_context(controller& con, transaction_context& trx_ctx, const action& a, uint32_t depth=0)

:control(con)

,db(con.db())

,trx_context(trx_ctx)

,act(a)

//合约的账号

,receiver(act.account)

,used_authorizations(act.authorization.size(), false)

}

action_trace apply_context::exec_one()

{

auto start = fc::time_point::now();

const auto& cfg = control.get_global_properties().configuration;

try {

//获取智能合约对象

const auto &a = control.get_account(receiver);

privileged = a.privileged;

//检测该action是否是native action,如果是则调用native handler

auto native = control.find_apply_handler(receiver, act.account, act.name);

if (native) {

//hative handler(action)存在,则调用

(*native)(*this);

}

//只要不是setcode调用,允许nativehandler和contract部署的代码都执行

if( a.code.size() > 0

&& !(act.account == config::system_account_name && act.name == N(setcode) && receiver == config::system_account_name) ) {

try {

control.get_wasm_interface().apply(a.code_version, a.code, *this);

} catch ( const wasm_exit& ){}

}

….

} FC_CAPTURE_AND_RETHROW((_pending_console_output.str()));

}

/********************************

* 本文来自CSDN博主"爱踢门"

* 转载请标明出处:http://blog.csdn.net/itleaks

******************************************/

如果你对EOS,ETH技术及开发感兴趣,请入QQ群讨论: 829789117


如需实时查看最新文章,请关注公众号"区块链斜杠青年",一起探索区块链未来

[EOS源码分析]6.EOS特殊智能合约eosio相关推荐

  1. [EOS源码分析]1.EOS源码编译运行

    本文所有实践都是基于EOS dawn-v4.1.0,请切到该分支然后实践 切换命令:git checkout dawn-v4.1.0 目前网络上都是针对老版EOS2.0源码编译的文章,我在mac上参考 ...

  2. [EOS源码分析]4.EOS源码调试

    在[EOS源码编译运行]一文已经详细描述了EOS源码编译.但是阅读代码,光跑代码是不够的,必须要可以调试.一搜发现网上没有相关的文章,只好自己探索折腾.不过很快发现其实EOS已经为我们做好了的,只需带 ...

  3. [EOS源码分析]2.EOS账号钱包密钥等基本概念及操作实践

    本文所有实践都是基于EOS dawn-v4.1.0,请切到该分支然后实践 切换命令:git checkout dawn-v4.1.0 cleos cleos应用程序是用户端命令行交互模块,用于解析用户 ...

  4. 以太坊C++客户端Aleth源码分析,转账交易和智能合约的入口代码

    本文主要记录以太坊C++客户端Aleth的源码分析和相关实验过程和结果.本文将讲解两部分的内容,一是转账交易和智能合约的入口代码在哪里?二是通过实验验证转账交易和智能合约交易这两种不同交易所对应的不同 ...

  5. [EOS源码分析]7.EOS智能合约开发实践之合约调用合约(inline action)

    首先,目前dawn-4.1, dawn-4.2使用inline action是会报如下错误 transaction declares authority '{"actor":&qu ...

  6. [EOS源码分析]5.EOS编写HelloWorld智能合约及各种坑

    本文所有实践都是基于EOS dawn-v4.1.0,请切到该分支然后实践 切换命令:git checkout dawn-v4.1.0 HelloWorld源码 #include <eosioli ...

  7. [EOS源码分析]10.EOS区块同步及生产

    本文所有实践都是基于EOS v1.0.1,请切到该分支然后对比源码 切换命令:git checkout v1.0.1 提到区块生产和同步,我们肯定有几个疑问? 节点同步 1)节点从哪里同步数据    ...

  8. eos源码分析和应用(一)调试环境搭建

    转载自 http://www.limerence2017.com/2018/09/02/eos1/#more eos基于区块链技术实现的开源引擎,开发人员可以基于该引擎开发DAPP(分布式应用).下面 ...

  9. c+智能指针源码分析_C ++中的智能指针

    c+智能指针源码分析 In this article, we'll take a look at how we can use Smart Pointers in C++. 在本文中,我们将研究如何在 ...

最新文章

  1. phpMyAdmin import.php 跨站脚本漏洞
  2. 协议关键技术_北京理工大学与华为签署战略合作协议
  3. Ajax基本案例详解之$.get的实现
  4. java水文模型,分布式水文模型.ppt
  5. CSS 的三种样式 内联 内部 外部
  6. Gin实践 番外 Golang交叉编译
  7. Kubernetes持久化存储Cephfs
  8. transformers model inputs
  9. apache重写模块开启
  10. 使用phonegap,进行页面跳转
  11. 双线macd指标参数最佳设置_MACD“双线合一”抄底法:等待个股最佳买点的出现,及时买进...
  12. SpringMVC中解决POST和GET请求中文乱码问题
  13. 有什么电脑软件可以测试网速,电脑怎么测试网速(测网速大全)
  14. asm bin hex elf文件区别
  15. 诗歌中的宇宙飞船和电子计算机代表什么,高考中可能出现的与神舟五号飞船有关的综合题...
  16. html5 indexedDB 数据库 详讲
  17. 系统命名法(IUPAC命名法)
  18. 配置Ubuntu以及ssh
  19. 智能文档处理IDP关键技术与实践-高翔
  20. AD19学习笔记之元器件的绘制

热门文章

  1. linux pcsc,PCSC-LITE使用及移植总结
  2. 庆祝鼓舞女性的技术-这是Ada Lovelace日!
  3. 论文翻译-Text Recognition in the Wild: A Survey
  4. Assets文件夹和RAW文件夹区别
  5. DP问题从入门到精通2.2(线性DP,最短编辑距离)
  6. Hackergame 2021
  7. 常用的英语短语短句(持续更新中)
  8. 发起“元点计划”,非繁城品“环保+助学”彰显企业社会责任感
  9. android电视dvd播放器,dvd播放器怎么连电视
  10. Python实现二维码表白内容