Solidity語言學習筆記————33、事件(Events)

FLy_鵬程萬里發表於2018-07-08

事件(Events)

事件是使用EVM日誌內建功能的方便工具,在dapp的介面中,它可以反過來呼叫Javascript的監聽事件的回撥。

事件在合約中可被繼承。當被呼叫時,會使引數儲存到交易的日誌中——一種區塊鏈上的特殊資料結構。這些日誌與合約的地址關聯,併合併到區塊鏈中,只要區塊可以訪問就一直存在。日誌和事件在合約內不可直接被訪問,即使是建立日誌的合約。

日誌的簡單支付驗證(SPV)是可能的,如果一個外部的實體提供了一個這樣證明的合約,它可以證明日誌在區塊鏈是否存在。但需要留意的是,由於合約中僅能訪問最近的256個區塊雜湊,所以還需要提供區塊頭資訊。

可以最多有三個引數被設定為indexed——是否被索引。設定為索引後,可以允許通過這個引數來查詢日誌,甚至可以按特定的值過濾。

如果陣列(包括stringbytes)型別被標記為索引項,會用它對應的Keccak-256雜湊值做為topic。

除非是匿名(anonymous) 事件,否則事件簽名是其中一個topic,同時也意味著對於匿名事件無法通過名字來過濾。

所有未被索引的引數將被做為日誌的一部分被儲存起來。

註解
被索引的引數將不會儲存它們自己,你可以搜尋他們的值,但不能檢索值本身。

下面是一個簡單的例子:

pragma solidity ^0.4.0;

contract ClientReceipt {
    event Deposit(
        address indexed _from,
        bytes32 indexed _id,
        uint _value
    );

    function deposit(bytes32 _id) public payable {
        // 任何對該函式的呼叫都可以
        // 從JavaScript API中通過Deposit`呼叫
        // 被過濾從而被檢測到 
        Deposit(msg.sender, _id, msg.value);
    }
}

下述是使用javascript來獲取日誌的例子:

var abi = /* abi 通過編譯器生成 */;
var ClientReceipt = web3.eth.contract(abi);
var clientReceipt = ClientReceipt.at("0x1234...ab67" /* 地址 */);

var event = clientReceipt.Deposit();

// 觀察變化
event.watch(function(error, result){
    //結果將包含`Deposit`呼叫給定的引數等各種資訊
    if (!error)
        console.log(result);
});

// 或通過回撥立即開始觀察
var event = clientReceipt.Deposit(function(error, result) {
    if (!error)
        console.log(result);
});

底層的日誌介面(Low-level Interface to Logs)

通過函式log0log1log2log3log4,可以直接訪問底層的日誌元件。logi表示總共有帶i + 1個型別bytes32的引數(i表示的就是可帶引數的數目,只是是從0開始計數的)。其中第一個引數會被用來做為日誌的資料部分,其它的會做為topics。前面例子中的event 可改為如下:

pragma solidity ^0.4.10;

contract C {
    function f() public payable {
        bytes32 _id = 0x420042;
        log3(
            bytes32(msg.value),
            bytes32(0x50cb9fe53daa9737b786ab3646f04d0150dc50ef4e75f59509d83667ad5adb20),
            bytes32(msg.sender),
            _id
        );
    }
}

其中的長16進位制串是事件的簽名,相當於keccak256("Deposit(address,hash256,uint256)")

理解事件的其他資源

相關文章