詳解 Solidity 事件Event - 完全搞懂事件的使用

Tiny熊發表於2018-05-16

很多同學對Solidity 中的Event有疑問,這篇文章就來詳細的看看Solidity 中Event到底有什麼用?

寫在前面

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

什麼是事件Evnet

事件是以太坊虛擬機器(EVM)日誌基礎設施提供的一個便利介面。當被髮送事件(呼叫)時,會觸發引數儲存到交易的日誌中(一種區塊鏈上的特殊資料結構)。這些日誌與合約的地址關聯,並記錄到區塊鏈中.
來捋這個關係:區塊鏈是打包一系列交易的區塊組成的鏈條,每一個交易“收據”會包含0到多個日誌記錄,日誌代表著智慧合約所觸發的事件。

在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"按鈕之後,雖然呼叫智慧合約成功,但是當前的介面並沒有得到更新。
使用事件監聽,就可以很好的解決這個問題,讓看看如何實現。

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

先回顧一下合約程式碼:

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"按鈕之後,會及時更新介面,如圖:
詳解 Solidity 事件Event - 完全搞懂事件的使用

完整的程式碼請訂閱小專欄區塊鏈技術檢視。

事件高階用法-過濾器

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

參考視訊

我們也推出了目前市面上最全的視訊教程:深入詳解以太坊智慧合約語言Solidity
目前我們也在招募體驗師,可以點選連結瞭解。

參考文章

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

深入淺出區塊鏈 - 系統學習區塊鏈,打造最好的區塊鏈技術部落格。

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

☛ 關注公眾號“深入淺出區塊鏈技術”第一時間獲取區塊鏈技術資訊。

詳解 Solidity 事件Event - 完全搞懂事件的使用

相關文章