背景介绍
eos的智能合约中,不少合约都会调用require_receipent方法,用于通知合约的参与方账户。这里的通知,实际上是调用被通知账户的智能合约,如果它部署了。被通知账户接到通知后,可以在其智能合约中做一系列操作,这个功能极大的方便了dapp的功能交互。
require_receipent如何传递通知
拿eosio.token发币合约为例,当用户触发了一个transfer转账动作,则会调用require_receipent方法通知from、to账户
看看require_receipent方法的实现,其实就是将需要通知的账户,加入通知列表中
通知动作的执行,实际上是exec函数完成的,它会轮询通知列表,执行exec_one函数挨个通知
exec_one函数,则会检查被通知账户是否部署了合约,如果部署了,则调用合约的apply函数,apply函数的用途会在稍后讲解。至此,require_recipient成功将消息传递给了被通知账户的合约。
eosio.token合约源码:源码
require_recipient、exec、exec_one等方法:源码
智能合约如何被调用
1. apply函数
前文提到了apply函数,实际上就是智能合约的入口。apply函数的作用就是监听合约的调用,当合约方法被调用时,apply函数会创建上下文环境,供合约方法运行
同样,apply函数作为智能合约入口,在接收到通知后,可以自定义处理逻辑、调用handler进行下一步动作。具体apply函数怎么实现,根据智能逻辑而定,但是每个智能合约必须实现apply函数。
extern "C" {
void apply( uint64_t receiver, uint64_t code, uint64_t action ) {
// 下一步处理逻辑
}
}
2. EOSIO_DISPATCH
EOSIO_DISPATCH宏是eosio.cdt合约编译器提供的一个默认定义,实现了最简单的apply函数,逻辑是当receiver==code时,被通知账户和合约部署账户相同时,才执行智能合约的方法
EOSIO_DISPATCH_HELPER来具体做执行的动作
依然拿eosio.token合约举例,合约的最后,直接调用了EOSIO_DISPATCH宏,用默认的apply去执行合约
apply和EOSIO_DISPATCH用法详见:https://developers.eos.io/eosio-home/docs (Custom Dispatchers一节)
智能合约的通信原理详见:https://developers.eos.io/eosio-cpp/docs/communication-model
使用require_recipient触发合约动作示例
1. 需求
当A账户转账到B账户时,B账户部署合约检查memo,当memo不合法时,终止这笔转账
2. 合约实现示例
这里我们自己实现了apply函数,检测到合约动作是transfer时,即执行testrecipient::transfer方法。将这个合约部署在B账户上,则B账户在收到转账时,会调用testrecipient::transfer方法检测memo是否合法
往eosiotest账户部署上面的智能合约,则非法的转账会被拒绝
参考文章
智能合约通信模式:https://developers.eos.io/eosio-cpp/docs/communication-model
apply函数和EOSIO_DISPATCH的用法:https://developers.eos.io/eosio-home/docs/writing-a-custom-dispatcher
使用require_recipient触发合约动作:https://eos.live/detail/11530
使用eosio.cdt编译合约后,apply函数如何重写:http://knowledge.cryptokylin.io/topics/99
后记
最近,eos重磅级侧链准备出来了,作者也忙着coding没太多时间更新。后面等侧链的事情落地了,再为大家介绍一波,尽请期待!