1. 程式人生 > >智慧合約基礎語言(八)——Solidity事件

智慧合約基礎語言(八)——Solidity事件

 

智慧合約基礎語言(八):Solidity事件

一、目錄

☞事件的定義

☞web3事件監聽

☞檢索日誌

☞底層日誌介面

二、事件的定義

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

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

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

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

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

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

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

被索引的引數將不會儲存它們自己,你可以搜尋他們的值,但不能檢索值本身。下面我們來看看,如何在Solidity中實現一個事件:

從上面的例子中,我們使用event關鍵字定義一個事件,引數列表中為要記錄的日誌引數的名稱及型別。

匿名和非匿名事件的結果對比:

下圖是通過掃描器觀察到的匿名和非匿名事件情況:

如圖所示,非匿名事件中的四個引數分別對應了四個topic,類似為四個值分別建立對應的索引。

三、deleteweb3事件監聽

在web3.js中,提供了響應事件的方法,如下:

另外一種簡便寫法是直接加入事件回撥,這樣就不用再寫watch的部分:

注意:在操作執行完成後,我們要記得呼叫event.stopWatching();來終止監聽。

四、檢索日誌

4.1Indexed屬性

可以在事件引數上增加indexed屬性,最多可以對三個引數增加這樣的屬性。加上這個屬性,可以允許你在web3.js中通過對加了這個屬性的引數進行值過濾,方式如下:

上面實現的是對value值為100的日誌,過濾後的返回。

如果你想同時匹配多個值,還可以傳入一個要匹配的陣列。

增加了indexed的引數值會存到日誌結構的Topic部分,便於快速查詢。而未加indexed的引數值會存在data部分,成為原始日誌。需要注意的是,如果增加indexed屬性的是陣列型別(包括string和bytes),那麼只會在Topic儲存對應的資料的web3.sha3雜湊值,將不會再存原始資料。因為Topic是用於快速查詢的,不能存任意長度的資料,所以通過Topic實際存的是陣列這種非固定長度資料雜湊結果。要查詢時,是將要查詢內容雜湊後與Topic內容進行匹配,但我們不能反推雜湊結果,從而得不到原始值。

4.2 顯式轉換

事件還支援傳入其它引數物件來限定可檢索的範圍,支援fromBlock,toBlock等過濾條件。

上面的程式碼實現了從第一塊開始搜尋日誌。

五、底層的日誌介面

可以通過底層的日誌介面來訪問底層的日誌機制。通過函式log0,log1,log2,log3,log4。logi支援i + 1個型別為bytes32的引數。其中第一個引數是日誌的data部分,其它引數為topic。所以下述事件:

使用API的等同寫法為:

下面是一個使用log3列印日誌的例子:

第一個引數為事件簽名的雜湊值keccak256("Deposit(address,bytes32,uint256)"),後面三個是按順序的indexed的值。

 

-END-