【鏈塊技術44期】智能合約基礎語言(八)——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-

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章