新闻开发人员企业区块链解释事件和会议新闻时事通讯
订阅我们的新闻.
电子邮件地址
我们尊重您的隐私
主页博客区块链开发
以太坊智能合约中的事件和日志指南
Joseph Chow撰写的示例代码的以太坊事件和登录用例的技术介绍2016年6月6日发布于2016年6月6日
事件和日志在以太坊中很重要,因为它们有助于智能合约与其用户界面之间的通信。在传统的Web开发中,服务器响应是在对前端的回调中提供的。在以太坊中,当交易被挖掘时,智能合约可以发出事件并将日志记录到前端可以处理的区块链中。有多种方法可以解决事件和日志。本技术简介将解释一些有关事件的混淆源以及一些与事件相关的示例代码.
事件可能会造成混乱,因为它们可以以不同的方式使用。一个人的事件可能看起来不像另一个人的事件。事件和日志有3种主要用例:
- 用户界面的智能合约返回值
- 数据异步触发
- 便宜的存储方式
事件和日志之间的术语是造成混乱的另一个原因,这将在第三个用例中进行解释。.
1)用户界面的智能合约返回值
事件的最简单用法是将合同的返回值传递到应用程序的前端。为了说明问题,这是问题所在:
contract ExampleContract {//一些状态变量…函数foo(int256 _value)返回(int256){//操作状态… return _value; }}代码语言:JavaScript(javascript)
假设exampleContract是ExampleContract的一个实例,使用web3.js的前端可以通过模拟合同执行来获得返回值:
var returnValue = exampleContract.foo.call(2); console.log(returnValue)// 2代码语言:JavaScript(javascript)
但是,当web3.js将合同调用作为事务提交时,它无法获得返回值[1]:
var returnValue = exampleContract.foo.sendTransaction(2,{from:web3.eth.coinbase}); console.log(returnValue)//交易哈希代码语言:JavaScript(javascript)
sendTransaction方法的返回值始终是创建的交易的哈希值。交易不会将合约价值返还给前端,因为交易不会立即被挖掘并包含在区块链中.
推荐的解决方案是使用事件,这是事件的预期目的之一.
合同ExampleContract {事件ReturnValue(地址索引为_from,int256 _value);函数foo(int256 _value)返回(int256){ReturnValue(msg.sender,_value);返回_value;然后,前端可以获取返回值:var exampleEvent = exampleContract.ReturnValue({_ from:web3.eth.coinbase}); exampleEvent.watch(function(err,result){if(err){console.log(err)return;} console.log(result.args._value)//检查result.args._from是web3.eth.coinbase然后//在界面中显示result.args._value并调用// exampleEvent.stopWatching()})exampleContract.foo.sendTransaction(2,{from:web3.eth.coinbase})代码语言:JavaScript(javascript)
当挖掘调用foo的事务时,将触发监视内部的回调。这有效地允许前端从foo获取返回值.
2)带有数据的异步触发器
返回值是事件的最小用例,通常可以将事件视为具有数据的异步触发器。当合同要触发前端时,合同会发出一个事件。因为前端正在监视事件,它可以采取行动,显示消息等。下一部分提供了一个示例(用户存款时可以更新UI。)
3)更便宜的存储方式
第三种用例与所涵盖的用例完全不同,那就是将事件用作便宜得多的存储形式。在以太坊虚拟机(EVM)和 以太坊黄纸, 事件称为日志(有LOG操作码)。说到存储,从技术上讲,可以将数据存储在日志中,而不是将数据存储在事件中,这在技术上会更加准确。但是,当我们超出协议的层次时,可以说合同发出或触发前端可以响应的事件更为准确。每当发出事件时,相应的日志就会写入到区块链中。事件和日志之间的术语是造成混乱的另一个原因,因为上下文表明哪个术语更准确.
原木被设计为一种存储形式,其天然气成本远低于合同存储。日志基本上[2]每字节花费8 gas,而合同存储每32字节花费20,000 gas。尽管日志可节省大量天然气,但无法从任何合同中获取日志[3].
不过,在某些情况下,使用日志作为便宜的存储空间,而不是使用前端触发器。日志的一个合适示例是存储可由前端呈现的历史数据.
加密货币交易所可能希望向用户显示他们在交易所进行的所有存款。与其将这些存款详细信息存储在合同中,不如将它们存储为日志要便宜得多。之所以可以这样做,是因为交易所需要用户的余额状态(存储在合同存储中),而无需了解历史存款的详细信息.
合约CryptoExchange {事件存款(uint256索引_market,地址索引_sender,uint256 _amount,uint256 _time);函数deposit(uint256 _amount,uint256 _market)返回(int256){//执行存款,更新用户余额等存款(_market,msg.sender,_amount现在); }代码语言:JavaScript(javascript)
假设我们要在用户存款时更新UI。这是一个使用事件(存款)作为异步触发器的示例,该触发器具有数据(_market,msg.sender,_amount,现在)。假设cryptoExContract是CryptoExchange的一个实例:
var depositEvent = cryptoExContract.Deposit({_ sender:userAddress}); depositEvent.watch(function(err,result){if(err){console.log(err)return;} //将result.args的详细信息附加到UI})代码语言:JavaScript(javascript)
提高为用户获取所有事件的效率是为事件的_sender参数建立索引的原因:事件存款(uint256索引为_market的地址,地址索引为_sender,uint256 _amount,uint256 _time).
默认情况下,侦听事件仅在实例化事件时开始。首次加载UI时,没有要追加的存款。因此,我们要检索从块0开始的事件,这是通过向事件添加一个fromBlock参数来完成的.
var depositEventAll = cryptoExContract.Deposit({_ sender:userAddress},{fromBlock:0,toBlock:’latest’}); depositEventAll.watch(function(err,result){if(err){console.log(err)return;} //将result.args的详细信息附加到UI})代码语言:JavaScript(javascript)
呈现UI时,应调用depositEventAll.stopWatching().
放在一边-索引参数
最多可以索引3个参数。例如,提议的令牌标准具有:事件传输(地址从_from索引的地址,地址从_to索引的地址,uint256 _value)。这意味着前端可以有效地监视令牌转移:
- 由地址tokenContract.Transfer({_ from:senderAddress})发送
- 或由地址tokenContract.Transfer({_ to:receiverAddress})接收
- 或通过地址发送到特定地址tokenContract.Transfer({_ from:senderAddress,_to:receiverAddress})
结论
已经为事件提供了三个用例。首先,使用事件简单地从使用sendTransaction()调用的协定函数中获取返回值。其次,将事件用作数据的异步触发器,该事件可以通知观察者(例如UI)。第三,使用事件将日志作为更便宜的存储形式写入区块链。此介绍显示了一些 蜜蜂 用于处理事件。有 其他方法 处理事件,日志和收据,这些主题将在以后的文章中介绍.
感谢Aaron Davis,Vincent Gariepy和Joseph Lubin对本文的反馈.
参考
[1] web3.js可以监视交易是否包含在区块链中,然后在EVM实例中重播交易以获取返回值,但这是添加到web3.js中的大量逻辑
[2] LOG操作的气体成本为375,每个主题的气体成本为375,但是当存储许多字节时,这些成本仅占存储总成本的很小一部分.
[3]可以使用针对日志的Merkle证明,因此,如果外部实体提供具有此类证明的合同,则合同可以验证日志实际上存在于区块链中.
希望开发人员直接将其引导至您的收件箱?
订阅我们的时事通讯以获取最新的以太坊新闻,企业解决方案,开发人员资源等信息。网络研讨会
如何构建成功的区块链产品
网络研讨会
如何设置和运行以太坊节点
网络研讨会
如何构建自己的以太坊API
网络研讨会
如何创建社交令牌
网络研讨会
在智能合约开发中使用安全工具
网络研讨会