詳解 Solidity 事件Event - 徹底搞懂事件的使用

本文首發於深刻淺出區塊鏈社區 原文連接:搞懂 Solidity 事件 Event - 如何在 DApp 中使用原文已更新,請讀者前往原文閱讀html

不少同窗對Solidity 中的Event有疑問,這篇文章就來詳細的看看Solidity 中Event到底有什麼用?git

寫在前面

Solidity 是以太坊智能合約編程語言,閱讀本文前,你應該對以太坊、智能合約有所瞭解,若是你還不瞭解,建議你先看以太坊是什麼,另外 本文在監聽合約事件是對上一篇Web3與智能合約交互實戰進行補充,若是閱讀了上一篇能夠更好的理解本文。github

什麼是事件Evnet

事件是以太坊虛擬機(EVM)日誌基礎設施提供的一個便利接口。當被髮送事件(調用)時,會觸發參數存儲到交易的日誌中(一種區塊鏈上的特殊數據結構)。這些日誌與合約的地址關聯,並記錄到區塊鏈中. 來捋這個關係:區塊鏈是打包一系列交易的區塊組成的鏈條,每個交易「收據」會包含0到多個日誌記錄,日誌表明着智能合約所觸發的事件。web

在DAPP的應用中,若是監聽了某事件,當事件發生時,會進行回調。 不過要注意:日誌和事件在合約內是沒法被訪問的,即便是建立日誌的合約。編程

在Solidity 代碼中,使用event 關鍵字來定義一個事件,如:瀏覽器

event EventName(address bidder, uint amount);

這個用法和定義函數式同樣的,而且事件在合約中一樣能夠被繼承。觸發一個事件使用emit(說明,以前的版本里並不須要使用emit),如:數據結構

emit EventName(msg.sender, msg.value);

觸發事件能夠在任何函數中調用,如:編程語言

function testEvent() public {

    // 觸發一個事件
     emit EventName(msg.sender, msg.value); 
}

監聽事件

經過上面的介紹,可能你們仍是不清楚事件有什麼做用,若是你跟過Web3與智能合約交互實戰這篇文章,你會發現點擊"Updata Info"按鈕以後,雖然調用智能合約成功,可是當前的界面並無獲得更新。 使用事件監聽,就能夠很好的解決這個問題,讓看看如何實現。ide

修改合約,定義事件及觸發事件

先回顧一下合約代碼:函數

pragma solidity ^0.4.21;

contract InfoContract {
    
   string fName;
   uint age;
   
   function setInfo(string _fName, uint _age) public {
       fName = _fName;
       age = _age;
   }
   
   function getInfo() public constant returns (string, uint) {
       return (fName, age);
   }   
}

首先,須要定義一個事件:

event Instructor(
       string name,
       uint age
    );

這個事件中,會接受兩個參數:name 和 age , 也就是須要跟蹤的兩個信息。

而後,須要在setInfo函數中,觸發Instructor事件,如:

function setInfo(string _fName, uint _age) public {
       fName = _fName;
       age = _age;
       emit Instructor(_fName, _age);
   }

Web3與智能合約交互實戰, 點擊"Updata Info"按鈕以後,會調用setInfo函數,函數時觸發Instructor事件。

使用Web3監聽事件,刷新UI

如今須要使用Web3監聽事件,刷新UI。 先回顧下以前的使用Web3和智能合約交互的代碼:

<script>
    if (typeof web3 !== 'undefined') {
        web3 = new Web3(web3.currentProvider);
    } else {
        // set the provider you want from Web3.providers
        web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:7545"));
    }

    web3.eth.defaultAccount = web3.eth.accounts[0];

    var infoContract = web3.eth.contract(ABI INFO);

    var info = infoContract.at('CONTRACT ADDRESS');

    info.getInfo(function(error, result){
        if(!error)
            {
                $("#info").html(result[0]+' ('+result[1]+' years old)');
                console.log(result);
            }
        else
            console.error(error);
    });

    $("#button").click(function() {
        info.setInfo($("#name").val(), $("#age").val());
    });

</script>

如今能夠不須要 info.getInfo()來獲取信息,而改用監聽事件獲取信息,先定義一個變量引用事件:

var instructorEvent = info.Instructor();

而後使用**.watch()**方法來添加一個回調函數:

instructorEvent.watch(function(error, result) {
        if (!error)
            {
                $("#info").html(result.args.name + ' (' + result.args.age + ' years old)');
            } else {
                console.log(error);
            }
    });

代碼更新以後,能夠在瀏覽器查看效果,這是點擊"Updata Info"按鈕以後,會及時更新界面,如圖:

完整的代碼請訂閱小專欄區塊鏈技術查看。

事件高級用法-過濾器

有時咱們會有這樣的需求:獲取當前全部姓名及年齡記錄,或者是,要過濾出年齡28歲的記錄,應該如何作呢? 以及另一個常見的場景:想要獲取到代幣合約中全部的轉帳記錄,也一樣須要使用事件過濾器功能,這部份內容請你們訂閱小專欄區塊鏈技術閱讀。

<!-- 有時咱們會有這樣的需求:獲取當前全部姓名及年齡記錄,應該如何作呢? 實際上事件支持過濾器,能夠從全部的區塊中過濾出符合要求的事件,如: ```js var instructorEvent = info.Instructor({}, {fromBlock: 0, toBlock: 'latest'}); ``` 或者是,要過濾出年齡28歲的記錄,能夠這樣: ```js var instructorEvent = info.Instructor({ 'age': 28}); ``` 好比,咱們要獲取到代幣合約中,全部的轉帳記錄, 就可使用: ```js var transferEvent = token.Transfer({}, {fromBlock: 0, toBlock: 'latest'}) var transferEvent.watch(function(error, result){ // handle result.args.from result.args.to }); ``` -->

參考文章

https://coursetro.com/posts/code/100/Solidity-Events-Tutorial---Using-Web3.js-to-Listen-for-Smart-Contract-Events https://github.com/ethereum/wiki/wiki/JavaScript-API#contract-events

深刻淺出區塊鏈 - 系統學習區塊鏈,打造最好的區塊鏈技術博客。

☛ 個人知識星球爲各位解答區塊鏈技術問題,歡迎加入討論。

☛ 關注公衆號「深刻淺出區塊鏈技術」第一時間獲取區塊鏈技術信息。

相關文章
相關標籤/搜索