智能合约基础语言(八)——Solidity事件

智能合约基础语言(八):Solidity事件

一、目录

☞事件的定义

☞web3事件监听

☞检索日志

☞底层日志接口

二、事件的定义

事件是使用EVM日志内置功能的方便工具,在DAPP的接口中,它可以反过来调用Javascript的监听事件的回调。

事件在合约中可被继承。当被调用时,会触发参数存储到交易的日志中(一种区块链上的特殊数据结构)。这些日志与合约的地址关联,并合并到区块链中,只要区块可以访问就一直存在(至少Frontier,Homestead是这样,但Serenity也许也是这样)。日志和事件在合约内不可直接被访问,即使是创建日志的合约。

日志的SPV(简单支付验证)是可能的,如果一个外部的实体提供了一个这样证明的合约,它可以证明日志在区块链是否存在。但需要留意的是,由于合约中仅能访问最近的256个区块哈希,所以还需要提供区块头信息。

可以最多有三个参数被设置为indexed,来设置是否被索引。设置为索引后,可以允许通过这个参数来查找日志,甚至可以按特定的值过滤。

如果数组(包括string和bytes)类型被标记为索引项,会用它对应的Keccak-256哈希值做为topic。

除非是匿名事件,否则事件签名(比如:Deposit(address,hash256,uint256))是其中一个topic,同时也意味着对于匿名事件无法通过名字来过滤。

所有未被索引的参数将被做为日志的一部分被保存起来。

被索引的参数将不会保存它们自己,你可以搜索他们的值,但不能检索值本身。下面我们来看看,如何在Solidity中实现一个事件:

从上面的例子中,我们使用event关键字定义一个事件,参数列表中为要记录的日志参数的名称及类型。

匿名和非匿名事件的结果对比:

下图是通过扫描器观察到的匿名和非匿名事件情况:

如图所示,非匿名事件中的四个参数分别对应了四个topic,类似为四个值分别建立对应的索引。

三、deleteweb3事件监听

在web3.js中,提供了响应事件的方法,如下:

另外一种简便写法是直接加入事件回调,这样就不用再写watch的部分:

注意:在操作执行完成后,我们要记得调用event.stopWatching();来终止监听。

四、检索日志

4.1Indexed属性

可以在事件参数上增加indexed属性,最多可以对三个参数增加这样的属性。加上这个属性,可以允许你在web3.js中通过对加了这个属性的参数进行值过滤,方式如下:

上面实现的是对value值为100的日志,过滤后的返回。

如果你想同时匹配多个值,还可以传入一个要匹配的数组。

增加了indexed的参数值会存到日志结构的Topic部分,便于快速查找。而未加indexed的参数值会存在data部分,成为原始日志。需要注意的是,如果增加indexed属性的是数组类型(包括string和bytes),那么只会在Topic存储对应的数据的web3.sha3哈希值,将不会再存原始数据。因为Topic是用于快速查找的,不能存任意长度的数据,所以通过Topic实际存的是数组这种非固定长度数据哈希结果。要查找时,是将要查找内容哈希后与Topic内容进行匹配,但我们不能反推哈希结果,从而得不到原始值。

4.2 显式转换

事件还支持传入其它参数对象来限定可检索的范围,支持fromBlock,toBlock等过滤条件。

上面的代码实现了从第一块开始搜索日志。

五、底层的日志接口

可以通过底层的日志接口来访问底层的日志机制。通过函数log0,log1,log2,log3,log4。logi支持i + 1个类型为bytes32的参数。其中第一个参数是日志的data部分,其它参数为topic。所以下述事件:

使用API的等同写法为:

下面是一个使用log3打印日志的例子:

第一个参数为事件签名的哈希值keccak256("Deposit(address,bytes32,uint256)"),后面三个是按顺序的indexed的值。

-END-

猜你喜欢

转载自blog.csdn.net/liankuaixy/article/details/82972042