事件

2022-05-16 10:46 更新

Solidity 事件在 EVM 的日志記錄功能之上提供了一個抽象。應(yīng)用程序可以通過以太坊客戶端的 RPC 接口訂閱和監(jiān)聽這些事件。

事件是合約的可繼承成員。當(dāng)你調(diào)用它們時,它們會導(dǎo)致參數(shù)存儲在交易日志中——區(qū)塊鏈中的一種特殊數(shù)據(jù)結(jié)構(gòu)。這些日志與合約的地址相關(guān)聯(lián),并入?yún)^(qū)塊鏈中,并在區(qū)塊可訪問時一直存在(從現(xiàn)在開始一直存在,但這可能會隨著 Serenity 而改變)。無法從合約內(nèi)部訪問日志及其事件數(shù)據(jù)(甚至無法從創(chuàng)建它們的合約中訪問)。

可以為日志請求 Merkle 證明,因此如果外部實體提供具有此類證明的合約,它可以檢查日志是否確實存在于區(qū)塊鏈中。你必須提供區(qū)塊頭,因為合約只能看到最后的 256 個區(qū)塊哈希。

您可以將屬性添加indexed到最多三個參數(shù),這會將它們添加到稱為“主題”的特殊數(shù)據(jù)結(jié)構(gòu)中,而不是日志的數(shù)據(jù)部分。一個主題只能包含一個單詞(32 個字節(jié)),因此如果您對索引參數(shù)使用引用類型,則該值的 Keccak-256 哈希值將存儲為主題。

所有沒有該indexed屬性的參數(shù)都被ABI 編碼 到日志的數(shù)據(jù)部分。

主題允許您搜索事件,例如在為某些事件過濾一系列塊時。您還可以按發(fā)出事件的合約地址過濾事件。

例如,下面的代碼使用 web3.jssubscribe("logs") 方法過濾與某個主題與某個地址值匹配的日志:

var options = {
    fromBlock: 0,
    address: web3.eth.defaultAccount,
    topics: ["0x0000000000000000000000000000000000000000000000000000000000000000", null, null]
};
web3.eth.subscribe('logs', options, function (error, result) {
    if (!error)
        console.log(result);
})
    .on("data", function (log) {
        console.log(log);
    })
    .on("changed", function (log) {
});

事件簽名的哈希是主題之一,除非您使用說明anonymous符聲明事件。這意味著無法按名稱過濾特定的匿名事件,只能按合約地址過濾。匿名事件的優(yōu)點是部署和調(diào)用成本更低。它還允許您聲明四個索引參數(shù),而不是三個。

筆記

由于事務(wù)日志只存儲事件數(shù)據(jù)而不存儲類型,因此您必須知道事件的類型,包括索引哪個參數(shù)以及事件是否是匿名的,以便正確解釋數(shù)據(jù)。特別是,可以使用匿名事件“偽造”另一個事件的簽名。

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.21 <0.9.0;

contract ClientReceipt {
    event Deposit(
        address indexed from,
        bytes32 indexed id,
        uint value
    );

    function deposit(bytes32 id) public payable {
        // Events are emitted using `emit`, followed by
        // the name of the event and the arguments
        // (if any) in parentheses. Any such invocation
        // (even deeply nested) can be detected from
        // the JavaScript API by filtering for `Deposit`.
        emit Deposit(msg.sender, id, msg.value);
    }
}

JavaScript API 中的使用如下:

var abi = /* abi as generated by the compiler */;
var ClientReceipt = web3.eth.contract(abi);
var clientReceipt = ClientReceipt.at("0x1234...ab67" /* address */);

var depositEvent = clientReceipt.Deposit();

// watch for changes
depositEvent.watch(function(error, result){
    // result contains non-indexed arguments and topics
    // given to the `Deposit` call.
    if (!error)
        console.log(result);
});


// Or pass a callback to start watching immediately
var depositEvent = clientReceipt.Deposit(function(error, result) {
    if (!error)
        console.log(result);
});

上面的輸出如下所示(修剪):

{
   "returnValues": {
       "from": "0x1111…FFFFCCCC",
       "id": "0x50…sd5adb20",
       "value": "0x420042"
   },
   "raw": {
       "data": "0x7f…91385",
       "topics": ["0xfd4…b4ead7", "0x7f…1a91385"]
   }
}

了解事件的其他資源?


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號