事件是智能合约发出的信号。智能合约的前端UI,例如,DApps、web.js,或者任何与Ethereum JSON-RPC API连接的东西,都可以侦听这些事件。事件可以被索引,以便以后可以搜索事件记录。
1 | 事件在区块链中的存储 |
Solidity 事件
Solidity中,要定义事件,可以使用event
关键字(在用法上类似于function
关键字)。然后可以在函数中使用emit
关键字触发事件。
1 | // 声明一个事件 |
示例
创建合约并发出一个事件。
1 | pragma solidity ^0.5.0; |
上面的代码中,
event Increment(address who)
声明一个合约级事件,该事件接受一个address类型的参数,该参数是执行increment
操作的账户地址。emit Increment(msg.sender)
触发事件,事件会记入区块链中。
按照惯例,事件名称以大写字母开头,以区别于函数。
用JavaScript监听事件
下面的JavaScript代码侦听Increment
事件,并更新UI。
1 | counter = web3.eth.contract(abi).at(address); |
contract.Increment(...)
开始侦听递增事件,并使用回调函数对其进行参数化。getCount()
是一个获取最新计数并更新UI的函数。
索引(indexed)参数
一个事件最多有3个参数可以标记为索引。可以使用索引参数有效地过滤事件。下面的代码增强了前面的示例,来跟踪多个计数器,每个计数器由一个数字ID标识:
1 | pragma solidity ^0.4.21; |
counts
替换count
,counts
是一个map。event Increment(uint256 indexed which, address who)
添加一个索引参数,该参数表示哪个计数器。emit Increment(which, msg.sender)
用2个参数记录事件。
在Javascript中,可以使用索引访问计数器:
1 | counter.Increment({ which: counterId }, function (err, result) { |
事件的局限
事件构建在Ethereum中,底层的日志接口之上。虽然您通常不会直接处理日志消息,但是了解它们的限制非常重要。
日志结构最多有4个“主题”和一个“数据”字段。第一个主题用于存储事件签名的哈希值,这样就只剩下三个主题用于索引参数。主题需要32字节长,因此,如果使用数组作为索引参数(包括类型string和bytes),那么首先将哈希值转换为32字节。非索引参数存储在数据字段中,没有大小限制。
日志,包括记录在日志中的事件,不能从Ethereum虚拟机(EVM)中访问。这意味着合约不能读取自己的或其他合约的日志及事件。
总结
- Solidity 提供了一种记录交易期间事件的方法。
- 智能合约前端(DApp)可以监听这些事件。
- 索引(indexed)参数为过滤事件提供了一种高效的方法。
- 事件受其构建基础日志机制的限制
附言
基础学习资料
- Solidity中文文档:https://learnblockchain.cn/docs/solidity/introduction-to-smart-contracts.html#
- ERC20:https://learnblockchain.cn/2018/01/12/create_token/
- ERC721:https://learnblockchain.cn/2018/03/23/token-erc721/
- cryptozombies游戏:https://cryptozombies.io/zh
- 学习列表:https://github.com/yippee-ki-yay/eth-dev-reading-list
- 语法基础:https://www.tryblockchain.org/solidity-libraries-%E5%BA%93.html
- https://www.qikegu.com/docs/4991
与智能合约交互
- ethers.js:https://learnblockchain.cn/docs/ethers.js/
- web3js:
源码
示例项目
- https://solidity-by-example.org/
- https://github.com/raineorshine/solidity-by-example
- https://github.com/cyrusadkisson/solidity-baby-steps
- https://github.com/flashbots/simple-arbitrage