區塊鏈研究實驗室|在Java中監聽以太坊智慧合約事件

買賣虛擬貨幣

1

什麼是智慧合約事件?

您可以從事務觸發的任何智慧合約函式中發出事件,它們是以太坊應用程式架構難題的重要組成部分。

這些事件由一個名稱和最多17個引數組成,這些引數的內容由發出函式提供。引數可以是索引的,也可以是非索引的;使用索引引數可以實現高效的鏈外查詢。

例如,如果事件x包含索引字串引數y,則在鏈外,我可以使用篩選器檢索y==“foo”的所有事件。(稍後將詳細介紹過濾器)

事件儲存為日誌而不是EVM儲存,因此,它們具有您應該注意的屬性:

  • 由於無法從智慧合約中訪問:雖然智慧合約功能會發出事件,但智慧合約在釋出後無法訪問此事件資訊。對於排放合同和任何其他外部合同都是如此。因此,您不能將事件用於跨智慧合約通訊。

  • 事件的費用很便宜!:由於事件儲存為日誌,因此與更新EVM儲存狀態的傳統方法相比,它們是非常便宜的。確切的成本取決於事件規範和事件中資料的大小。

1

事件的常見用途

非同步鏈外觸發器

大多數企業Java開發人員都熟悉事件匯流排模式,其中事件被髮布到佇列(如RabByMQ或Amazon SQL)。此模式允許對特定事件感興趣的服務非同步地從匯流排上使用它們,並執行進一步的處理,而不需要在釋出伺服器和使用者服務之間進行任何耦合。

事件匯流排模式

服務可以以類似的方式使用以太坊智慧合約事件,以太坊網路充當一種訊息佇列。非鏈服務可以向節點註冊一個事件過濾器,然後每次在以太坊網路中發出此事件時都會通知該過濾器。然後,您可以使用這些事件通知作為進一步的鏈外處理的觸發器,例如更新智慧合約狀態的基於NoSQL的快取。

以太坊作為“事件匯流排”

廉價的資料儲存用於鏈外消費

如上所述,在事件中儲存資料而不是在EVM合同儲存中儲存資料要便宜得多。

為了進行比較,稍微深入瞭解一下細節,將32位元組的資料儲存到合同儲存需要消耗20000氣體,而傳送一個事件需要消耗375加上每個索引引數的375氣體,每個位元組的資料需要額外的8氣體。

由於這些成本節約,在事件中儲存從不由鏈上智慧合約函式soley讀取的資料是一種常見的模式,而不是在合約儲存中。

一個可能是這種情況的場景示例是一個公證服務,其中IPF雜湊被提交到以太坊區塊鏈以證明建立日期。在發出包含文件的IPFS雜湊的事件後,如果存在爭議,可以透過查詢合同事件(而不是合同狀態)來驗證鏈外公證的時間戳。

1

定義和發出事件


您的以太坊智慧合約中的定義、傳送和事件都是一段程式碼:

定義

eventNotarized(address indexed notary, string documentHash)

在這個例子中,我們定義了一個名為Notarized的事件,帶有索引地址引數,notary和一個非索引字串引數documentHash。

傳送

function notarizeDocument(string _documentHash)public{
emit Notarized(msg.sender, _documentHash);
}

emit關鍵字觸發一個事件,引數以類似於函式呼叫的方式傳遞給事件。 這裡,公證地址透過msg.sender設定為事務傳送方地址,documentHash與被呼叫的函式引數相同。

使用Web3J監聽已發出的事件

到目前為止,使用web3j監聽以太坊智慧合約事件的最簡單方法是使用庫的合同包裝器功能。

下面的程式碼段連線到本地以太坊節點,並監聽從部署的公證合同發出的所有公證事件:

Web3j web3j = Web3j.build(new HttpService("http://localhost:8545"));

//Deploys a notary contract via wrapper
final Notary notaryContract = deployNotaryContract(web3j);

notaryContract
        .notarizedEventFlowable(DefaultBlockParameterName.EARLIEST, DefaultBlockParameterName.LATEST)
        .subscribe(event -> {
finalString notary = event.notary;
finalString documentHash = event.documentHash;

//Perform processing based on event values
        });

自動生成的合同包裝器程式碼包含使用命名模式<event-name> EventFlowable在智慧合約中定義的每個事件的便捷方法。此方法採用開始和結束區塊引數,並且在此示例中,使用DefaultBlockParameterName.LATEST值指示web3j無限期地繼續監聽新區塊的事件。如果需要特定的區塊範圍,可以使用DefaultBlockParameter.valueOf(BigInteger.valueOf(...))。返回一個Flowable物件,然後可以訂閱該物件,以便對發出的事件執行處理邏輯。

此方法簡化了事件偵聽過程,因為它自動將原始日誌訊息轉換為具有反映已定義事件引數的欄位的物件。如果沒有這個,你必須自己解碼這些值,雖然web3j為此提供了幫助方法,但事情可能會很快變得複雜。

按索引引數值過濾

將事件的引數設定為indexed有助於透過該引數值高效地查詢事件。透過手動構建ethfilter物件,Web3J支援此查詢。下面是監聽特定以太坊地址公證的事件的程式碼:

final EthFilter ethFilter = new EthFilter(DefaultBlockParameterName.EARLIEST, DefaultBlockParameterName.LATEST,
                notaryContract.getContractAddress());

ethFilter.addSingleTopic(EventEncoder.encode(notaryContract.NOTARIZED_EVENT));
ethFilter.addOptionalTopics("0x" + TypeEncoder.encode(new Address("0x00a329c0648769a73afac7f9381e08fb43dbea72")));

notaryContract
        .notarizedEventFlowable(ethFilter)
        .subscribe(event -> {
finalString notary = event.notary;
finalString documentHash = event.documentHash;

//Perform processing based on event values
        });

notarizedEventFlowable被過載,並且可以接受EthFilter作為引數,而不是區塊範圍。此過濾器用於以更精粒度的方式定義要監聽的事件,並使用與先前傳遞給方法相同的區塊範圍構建。

還有一些主題在過濾器上設定。在以太坊過濾器中,第一個主題始終定義為事件簽名的keccak雜湊,在我們的案例中,事件簽名為“Notarised(address,string)”。這是在Web3j提供的EventEncoder.encode(..)方法的幫助下計算的,以及在包裝類中自動生成的事件規範NOTARIZED_EVENT。

可以使用addOptionalTopics(..)方法新增其他主題,這些主題指定要匹配的索引引數的值,其順序與事件規範中定義的順序相同。編碼根據引數的型別略有不同,但幸運的是,Web3j提供了TypeEncoder類,它為我們處理這個問題。在提供的示例中,我們僅監聽公證值為地址0x00a329c0648769a73afac7f9381e08fb43dbea72的事件。

1

總結

對於後端(和前端)服務來說,事件是以非同步方式通知智慧合約更改和互動的一種很好的方式,也是一種在以太坊區塊鏈上儲存不需要智慧合約消費的資料的經濟有效的方式。

與許多以太坊互動一樣,Web3j生成的智慧合約包裝器是迄今為止最簡單的方式來訂閱和處理java後端中發出的事件。

免責聲明:

  1. 本文版權歸原作者所有,僅代表作者本人觀點,不代表鏈報觀點或立場。
  2. 如發現文章、圖片等侵權行爲,侵權責任將由作者本人承擔。
  3. 鏈報僅提供相關項目信息,不構成任何投資建議

推荐阅读

;