Skip to content

Latest commit

 

History

History
66 lines (51 loc) · 3.44 KB

File metadata and controls

66 lines (51 loc) · 3.44 KB

EVM中的事件与日志

事件和日志在以太坊中很重要,在介绍智能合约的时候介绍了Solidity中事件的使用方法,但是还有一些更深入的问题没有讨论。在传统的Web开发中,通常是前端向服务器发起一次Http请求,当服务器接收到这个请求后作出相应的操作或者返回对应的数据。

用一个简单的智能合约来说明这个过程;

contract ExampleContract {
  function echo(int256 _value) returns (int256) {
    return _value;
  }
}

通常我们直接调用合约中的方法都希望可以直接拿到返回值,假设exampleContract是ExampleContract的一个实例,我们调用echo方法像下面这样;

// 伪代码
var returnValue = exampleContract.echo(2);
console.log(returnValue)// 2

但是当这个合约部署在区块链系统上以后,通过直接调用并不能按照预期执行。

var returnValue = exampleContract.echo.sendTransaction(2,{from:web3.eth.coinbase}); 
console.log(returnValue)// 交易哈希

sendTransaction方法的返回值始终是所创建事务的哈希值。交易不会将合约价值返还给前端,因为交易不会立即被打包成区块添加进区块链中。推荐的解决方案是使用事件,这是事件的预期目的之一。

// 给合约增加事件
contract ExampleContract {
    event ReturnValue(address indexed _from, int256 _value);
    function echo(int256 _value) returns (int256) {
        ReturnValue(msg.sender, _value);
        return _value;
    }
}
A frontend can then obtain the return 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)
  // check that result.args._from is web3.eth.coinbase then
  // display result.args._value in the UI and call
  // exampleEvent.stopWatching()
})

// 调用合约
exampleContract.foo.sendTransaction(2, {from: web3.eth.coinbase})

当调用echo的交易被执行时,将触发监视内部的回调。 这有效地允许前端从echo获取返回值。

获得返回值仅仅是事件很小的一个使用场景,通常可以将事件视为具有数据的异步触发器。 当合约想要触发前端时,合约会发出一个事件。 由于前端正在监视事件,它可以进行对应的操作,显示消息等。

日志还有一种与之前介绍截然不同的用法,那就是将事件用作便宜得多的存储形式。日志被设计为一种存储形式,其gas成本远低于合同存储。日志基本每字节花费8 gas,而合同存储每32字节花费20,000 gas。尽管日志可以节省大量gas,但无法从任何合约中获取日志。但是,在某些情况下,使用日志作为廉价存储,而不是使用前端触发器。日志的一个合适示例是存储可由前端呈现的历史数据。

加密货币交易所可能希望向用户显示他们在交易所进行的所有存款。与将这些存款详细信息存储在合约中相比,将它们存储为日志要便宜得多。之所以可能这样做,是因为交易所需要用户的余额状态,该状态存储在合同存储中,而无需了解历史存款的详细信息。

EVM的事件与日志为用户界面的提供了智能合约返回值,同时也提供了日志这样一种非常便宜的存储方式,最后可以通过事件的方式异步的感知到合约执行。