80%开发者都不知道的以太坊骚操作:「事件」和「日志」还可以这么玩! 80%开发者都不知道的以太坊骚操作:「事件」和「日志」还可以这么玩!

80%开发者都不知道的以太坊骚操作:「事件」和「日志」还可以这么玩!

640?wx_fmt=png&wxfrom=5&wx_lazy=1


作者 | 蔡一  志顶科技技术总监



4月6日,Daniel Larimer发布了一篇文章《EOSIO Dawn 3.0 Now Available》(译:EOSIO Dawn 3.0来啦),在章节「Simplified Contract Development」(译:更简单的合约开发)中,举了个「Hello,World」的智能合约的例子来说明合约开发的简单。 


640?wx_fmt=png&wxfrom=5&wx_lazy=1

https://gist.githubusercontent.com/bytemaster/

58d45d13dbf8732c8d467b6415a44df9/raw/ba460c2aff29c7f60ecdef7dc082a0190b5af418/

hello.cpp


然而值得注意的是,示例的合约就执行了一条语句:print( "Hello, ", user);

那么问题来了:在智能合约中print的内容会出现在哪里呢


我没实际运行过这段代码,但我知道,print的内容只会出现在每个区块链节点的日志文件或终端(Console)上。 实际上,传统的print日志打印对智能合约的开发和跟踪不存在任何意义。


那么,以太坊怎么解决这个问题的呢?以太坊引入了事件(Events)和日志(Logs)。 


这里说的「事件」和「日志」这两个术语可能会引起混淆,本质上来说,智能合约通过「事件」来产生「日志」本文会介绍以太坊的「事件」和「日志」系统常用的3种场景,供以太坊开发者参考



事件和日志的用途


「事件」和「日志」对于以太坊是非常重要的,因为它们使智能合约与用户界面之间的通信变得容易。在传统的Web开发中,一个服务器响应会提供回调给前端。在以太坊中,当一个交易被打包,智能合约能发送事件以及写日志到区块链上以便前端处理。有三种情况需要使用事件和日志。


1. 智能合约给用户界面返回值

我们还是以EOS的例子来看,鉴于Solidity拼接字符串比较麻烦,我就直接返回一个字符串。

 

640?wx_fmt=png

如果你用Web3.JS来调用HelloWorld这个智能合约的函数「hi()」,你可能会认为是这样:


640?wx_fmt=png


那么,这句调用的result会是「hello, World」呢? 其实不是,不管函数返回什么值,Web3.JS都会返回一个Transaction Hash(交易哈希)。


那要怎么做呢?现在就轮到事件上场了。


修改后的智能合约代码如下:

 

640?wx_fmt=png

而Web3.JS则需要这样写:

 

640?wx_fmt=png


当交易被打包时,回调函数将被触发, 前端将获得智能合约函数的返回值。


2. 异步数据通知

使用返回值返回给用户界面其实很少用到。大部分时间,我们是使用事件给用户界面发送数据。当智能合约想把某些数据通知用户界面时,可以发送事件,用户界面对这些时间进行监听,就可以进行不同的操作。


3. 相对便宜的数据存储

还有这一种使用方式是把日志作为数据存储。在EVM规范和黄皮书中说明,事件将产生日志,而日志是会被存储都区块链的。日志存储的Gas费用要比合约的存储便宜很多(日志每个字节花费8个Gas,而合约存储是每32个字节20,000个Gas)。因此,当你有存证等应用的时候,可以考虑使用日志来存储,而不是在合约中使用Mapping来存储。



日志的存储结构


上面说了时间和日志的三种用法,最后我们来看看日志的大致结构。


640?wx_fmt=png

 

你可以通过「remix」查看日志的接口。Topic指向特定的事件,但值是16进制的,这是个什么呢?其实这是事件的签名。图中的288d740d3b11a36c8526119855345e3ba2aee438370d264289ea6dfb76294fd0其实是sha3(Hi(string))的执行结果。下面的「event」和「args」是「remix」从区块链的「收据(Receipt)数据的Logs项中解码出来的。 


实际数据为: 

640?wx_fmt=png


那是怎么解码的呢?


前文中提到过,Topics实际上是事件的「sha3」签名,示例合约中只有一个事件,可以直接对应,如果合约中有多个事件,需要通过ABI找出对应的event,逐一签名,最后与Topics中的签名进行对应即可找到对应的事件。


事件的名称找到了,对应的参数就相对简单,示例合约的ABI如下:


640?wx_fmt=png


可以看到,type为event的事件,「输入」(inputs)只有一个,那就是「say」,类型是「string」。


我们使用eth-abi工具(https://github.com/ethereum/eth-abi)可以进行解码。(eth-abi是一个用Python编写的Ethereum ABI工具)。命令如下: 


640?wx_fmt=png


在web3.js 1.0-beta版本中,可以直接通过以下函数进行日志解码:


640?wx_fmt=png




结束语


「事件」(Events)是以太坊中很有意思的设计,对智能合约运行时与外部交互,特别是DApp的设计具有重要意义。大家在开发DApp和智能合约时可以根据实际情况灵活应用以上所介绍的3种方式,进行与前端的交互和日志的调试。也欢迎大家发掘更多的应用场景。



作者简介:蔡一,区块链技术专家,长期研究并实践区块链技术与应用,精通以太坊智能合约开发。现为志顶科技技术总监,负责公司核心产品TokenPOS通证宝设计与研发。

640?wx_fmt=png&wxfrom=5&wx_lazy=1


作者 | 蔡一  志顶科技技术总监



4月6日,Daniel Larimer发布了一篇文章《EOSIO Dawn 3.0 Now Available》(译:EOSIO Dawn 3.0来啦),在章节「Simplified Contract Development」(译:更简单的合约开发)中,举了个「Hello,World」的智能合约的例子来说明合约开发的简单。 


640?wx_fmt=png&wxfrom=5&wx_lazy=1

https://gist.githubusercontent.com/bytemaster/

58d45d13dbf8732c8d467b6415a44df9/raw/ba460c2aff29c7f60ecdef7dc082a0190b5af418/

hello.cpp


然而值得注意的是,示例的合约就执行了一条语句:print( "Hello, ", user);

那么问题来了:在智能合约中print的内容会出现在哪里呢


我没实际运行过这段代码,但我知道,print的内容只会出现在每个区块链节点的日志文件或终端(Console)上。 实际上,传统的print日志打印对智能合约的开发和跟踪不存在任何意义。


那么,以太坊怎么解决这个问题的呢?以太坊引入了事件(Events)和日志(Logs)。 


这里说的「事件」和「日志」这两个术语可能会引起混淆,本质上来说,智能合约通过「事件」来产生「日志」本文会介绍以太坊的「事件」和「日志」系统常用的3种场景,供以太坊开发者参考



事件和日志的用途


「事件」和「日志」对于以太坊是非常重要的,因为它们使智能合约与用户界面之间的通信变得容易。在传统的Web开发中,一个服务器响应会提供回调给前端。在以太坊中,当一个交易被打包,智能合约能发送事件以及写日志到区块链上以便前端处理。有三种情况需要使用事件和日志。


1. 智能合约给用户界面返回值

我们还是以EOS的例子来看,鉴于Solidity拼接字符串比较麻烦,我就直接返回一个字符串。

 

640?wx_fmt=png

如果你用Web3.JS来调用HelloWorld这个智能合约的函数「hi()」,你可能会认为是这样:


640?wx_fmt=png


那么,这句调用的result会是「hello, World」呢? 其实不是,不管函数返回什么值,Web3.JS都会返回一个Transaction Hash(交易哈希)。


那要怎么做呢?现在就轮到事件上场了。


修改后的智能合约代码如下:

 

640?wx_fmt=png

而Web3.JS则需要这样写:

 

640?wx_fmt=png


当交易被打包时,回调函数将被触发, 前端将获得智能合约函数的返回值。


2. 异步数据通知

使用返回值返回给用户界面其实很少用到。大部分时间,我们是使用事件给用户界面发送数据。当智能合约想把某些数据通知用户界面时,可以发送事件,用户界面对这些时间进行监听,就可以进行不同的操作。


3. 相对便宜的数据存储

还有这一种使用方式是把日志作为数据存储。在EVM规范和黄皮书中说明,事件将产生日志,而日志是会被存储都区块链的。日志存储的Gas费用要比合约的存储便宜很多(日志每个字节花费8个Gas,而合约存储是每32个字节20,000个Gas)。因此,当你有存证等应用的时候,可以考虑使用日志来存储,而不是在合约中使用Mapping来存储。



日志的存储结构


上面说了时间和日志的三种用法,最后我们来看看日志的大致结构。


640?wx_fmt=png

 

你可以通过「remix」查看日志的接口。Topic指向特定的事件,但值是16进制的,这是个什么呢?其实这是事件的签名。图中的288d740d3b11a36c8526119855345e3ba2aee438370d264289ea6dfb76294fd0其实是sha3(Hi(string))的执行结果。下面的「event」和「args」是「remix」从区块链的「收据(Receipt)数据的Logs项中解码出来的。 


实际数据为: 

640?wx_fmt=png


那是怎么解码的呢?


前文中提到过,Topics实际上是事件的「sha3」签名,示例合约中只有一个事件,可以直接对应,如果合约中有多个事件,需要通过ABI找出对应的event,逐一签名,最后与Topics中的签名进行对应即可找到对应的事件。


事件的名称找到了,对应的参数就相对简单,示例合约的ABI如下:


640?wx_fmt=png


可以看到,type为event的事件,「输入」(inputs)只有一个,那就是「say」,类型是「string」。


我们使用eth-abi工具(https://github.com/ethereum/eth-abi)可以进行解码。(eth-abi是一个用Python编写的Ethereum ABI工具)。命令如下: 


640?wx_fmt=png


在web3.js 1.0-beta版本中,可以直接通过以下函数进行日志解码:


640?wx_fmt=png




结束语


「事件」(Events)是以太坊中很有意思的设计,对智能合约运行时与外部交互,特别是DApp的设计具有重要意义。大家在开发DApp和智能合约时可以根据实际情况灵活应用以上所介绍的3种方式,进行与前端的交互和日志的调试。也欢迎大家发掘更多的应用场景。



作者简介:蔡一,区块链技术专家,长期研究并实践区块链技术与应用,精通以太坊智能合约开发。现为志顶科技技术总监,负责公司核心产品TokenPOS通证宝设计与研发。

猜你喜欢

转载自blog.csdn.net/starzhou/article/details/80189662