区块链开发(十五)以太坊中的Events和Logs解析及用途

    以太坊中的事件(Events)和日志(Logs)是个特别让人困惑的概念,本文帮大家梳理。
    因为上篇文章,我们讨论过以太坊go-ethereum客户端查询交易列表的一些办法,这篇文章,我们具体实现一种filter的探讨。让我们明白这种方法具体如何使用。重点在最后一部分。希望对开发起到一定的帮助作用。我们从基本的概念说起,来整体理解这个过程。
    首先,以太坊中的Events和Logs基本上算是同一个概念。Solidity和web3.js中称为Events,以太坊黄皮书中称为Logs。你可以理解为:以太坊通过Logs实现Events(事件)功能。智能合约代码通过LOG 将日志写入区块链中。
    (如果用Truffle框架开发也是一样的,因为Truffle框架本身就包装的Web3.js)
    日志内容位于区块链的什么地方?
    日志内容是交易收据(Transaction Receipts)的一部分,整个日志内容,包括Receipts的其它内容会生成一个ReceiptsRoot存储在区块的头部。而完整数据则是链下存储。
    事件和日志的主要用途有四种:
    1.帮助用户客户端(web3.js)读取智能合约的返回值;
    2.智能合约异步通知用户客户端(web3.js);
    3.用于智能合约的存储(比Storage便宜得多);
    4.我认为有第四种,可以帮助我们通过filter过滤出历史交易数据,具体实现看下面文章解析。

    下面我们逐个解释
    1.帮助用户客户端(web3.js)读取智能合约的返回值:
    假设下面的智能合约:

    contract ExampleContract {
      // some state variables ...
      function foo(int256 _value) returns (int256) {
        // manipulate state ...
        return _value;
      }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    我们可以通过web3.js的message call功能模拟调用智能合约:

    var returnValue = exampleContract.foo.call(2);
    console.log(returnValue) // 2
    • 1
    • 2

    但是在真实的环境中我们需要发送交易(Transaction)来调用某个智能合约。这时我们将无法获得智能合约的返回值。因为该交易当前只是被发送、打包、执行还有一段时间(需要矿工的工作量证明来实现)。此时调用的返回值只是该交易的txid或称为tx hash值。

    var returnValue = exampleContract.foo.sendTransaction(2, {from: web3.eth.coinbase});
    console.log(returnValue) // transaction hash
    • 1
    • 2

    这时事件(Events)就登场了:我们往往将写入链上方法,或者叫让链上数据改变的方法。我们在方法前面加上Event来实现。

    //以下是solidity智能合约代码
    contract ExampleContract {
      event ReturnValue(address indexed _from, int256 _value);
      unction foo(int256 _value) returns (int256) {
        ReturnValue(msg.sender, _value);
        return _value;
      }
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    //以下是web3.js用户客户端代码

    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})
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    当交易被打包时,web3.js中的callback就会被调用,这时web3.js就可以得到交易中的智能合约调用的返回值了。
    至于为什么交易打包,web3.js中的callback就被调用那是另一个问题了,简单解释如下。web3.js会和以太坊某个节点相连,当该节点得知某个交易写进block后,会通知相连的节点相关信息。
    2.智能合约异步通知用户客户端(web3.js):
    上面例子是智能合约通知用户客户端的典型例子,但还有更多的异步调用可以通过类似的方式实现,从而实现了智能合约异步调用用户客户端的能力。
    注:智能合约通常用solidity编写,运行在以太坊节点上(EVM)。
    注:用户客户端通常用web3.js编写,运行在web服务器上,web3.js跟某个以太坊节点相连。
    3.用于智能合约的存储(比Storage便宜得多):
    相比智能合约账户的Storage,用日志的方式存储一些信息会便宜很多。Storage中大致的价格是:每32字节(256位)存储需要消耗20,000气(Gas)。而日志大致是每字节8气(Gas)。
    下面看一个例子:

    //solidity智能合约代码,模拟用户存款功能
    contract CryptoExchange {
      event Deposit(uint256 indexed _market, address indexed _sender, uint256 _amount, uint256 _time);
      function deposit(uint256 _amount, uint256 _market) returns (int256) {
        // perform deposit, update user’s balance, etc
        Deposit(_market, msg.sender, _amount, now);
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    //当某户调用智能合约存了某笔款后, 智能合约需要主动通知用户客户端更新相应信息。
    4.帮助我们通过filter过滤出历史交易数据.
    下面的方法具体实现我们开始讲的通过filter办法,从链上扒出历史交易数据的办法。
    //以下是web3.js代码:

    var depositEvent = cryptoExContract.Deposit({_sender: userAddress});
    depositEvent.watch(function(err, result) {
      if (err) {
        console.log(err)
        return;
      }
      else{
          // append details of result.args to UI
          //将这笔交易写入客户端资料库中,方便以后查询历史交易数据。
      }  
    })
    //通过增加fromBlock参数指定关注的区块范围,来查询所有的交易数据。(获取链上存储的历史交易数据,我们用扒链的办法来获取,因为eth目前没有提供获取历史数据的API。)
    var depositEventAll = cryptoExContract.Deposit({_sender: userAddress}, {fromBlock: 0, toBlock: 'latest'});
    depositEventAll.watch(function(err, result) {
      if (err) {
        console.log(err)
        return;
      }
      else{
      // append details of result.args to UI
      //如果不想再被通知可以调用:
      //depositEventAll.stopWatching();
      }
    })
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    //注:indexed关键字表示按该字段索引日志,以提高查询效率。

    转载请注明:比特阁 » 区块链开发(十五)以太坊中的Events和Logs解析及用途

    喜欢 0

还没有人抢沙发呢~