hao86下載站:值得大家信賴的游戲下載站!

首頁 > 區(qū)塊鏈 > 深入了解Solidity事件——Event

深入了解Solidity事件——Event

時間:2024-02-27 08:30:18
來源:hao86下載
區(qū)塊鏈

【#區(qū)塊鏈# #深入了解Solidity事件——Event#】

來源:登鏈社區(qū)

在今天的文章中,我們將看一下 Solidity event,在更通用的以太坊和 EVM 中稱為logs。我們將看到如何使用它們,它們的定義以及如何使用事件主題哈希和簽名來過濾日志,以及關于何時應該使用這些的一些建議。

我們還將涵蓋 檢查-事件-交互 模式,這種著名的模式傳統(tǒng)上應用于狀態(tài)變量的重入,但我們將看到為什么這樣的模式也應該應用于觸發(fā)事件以及涉及的潛在風險和安全漏洞。

如何在 Solidity 中定義事件?

可以使用event關鍵字在 Solidity 中定義事件,如下所示。

interface ILight {
event SwitchedON();
event SwitchedOFF();
event BulbReplaced();
}

你可以通過完全限定的訪問合約名稱,后跟.和事件名稱來從另一個合約中訪問事件,如下所示:

event RegisteredSuccessfully(address user)

事件簽名將是:

event RegisteredSuccessfully(address user)

事件主題哈希將是:

bytes32 topicHash = RegisteredSuccessfully.selector;

請注意,只有 Solidity v0.8.15 以后,事件的 .selector 成員才能使用。

如果你查看發(fā)出的任何區(qū)塊鏈日志,你會發(fā)現(xiàn)日志的主題的索引0(第一個)條目的對應于事件主題哈希。由于主題是能通過日志進行搜索的內(nèi)容,因此我們可以用事件主題哈希能進行過濾:

  • 在特定地址的智能合約內(nèi)搜索特定事件。

  • 在區(qū)塊鏈上的所有合約中搜索特定事件。

我們將在下面進一步看到,anonymous 匿名事件是此規(guī)則的例外。anonymous關鍵字使它們不可搜索,因此使用術語“匿名”

基于這一事實,我們還可以推斷,Solidity 中定義的最簡單的事件,沒有參數(shù),比如上面定義的事件BulbReplacedSwitchedON,將在底層使用 LOG1 操作碼來觸發(fā)日志中的主題,因為事件本身是可搜索的。

可以添加更多的主題,其他主題將使用LOG2,LOG3,LOG4LOG5,只要這些參數(shù)被標記為indexed。讓我們在下一節(jié)中看一下索引參數(shù)。

事件參數(shù)和索引參數(shù)

事件可以接受任何類型的參數(shù),包括值類型(uintN,bytesN,booladdress...),struct,enum和用戶定義的值類型。

根據(jù)我在寫本文的研究,唯一不允許的類型是內(nèi)部函數(shù)類型。外部函數(shù)類型是允許的,但內(nèi)部函數(shù)類型不允許。舉例來說,下面的代碼將無法編譯。

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

contract AnonymousEvents {
event SecretPasswordHashUpdated(bytes32 secretPasswordHash) anonymous;
}

如果事件聲明為anonymous,在合約 ABI 中,事件的"anonymous"字段將標記為true。

imghttps://github.com/ethereum/solidity/issues/13086

匿名事件的一個優(yōu)點是,它使你的合約更便宜部署,并且在觸發(fā)時 Gas方面也更便宜。

匿名事件的一個很好的用例是對于只有一個事件的合約。監(jiān)聽合約中的所有事件是有意義的,因為只有這一個事件將出現(xiàn)在事件日志中。訂閱其名稱是無關緊要的,因為只定義了一個單一事件來由合約發(fā)出。因此,你可以將事件定義為匿名,并訂閱來自合約的所有事件日志,并確認它們都是相同的事件。

查看匿名事件在流行代碼庫中的使用示例,如在 DappHub 的 DS-Note 合約[7] 中。

img來源代碼[8]

我們可以在上面的代碼片段中看到,由于事件聲明為匿名,這使得可以定義第四個“indexed”參數(shù)。

請注意,由于匿名事件沒有 bytes32 主題哈希,因此匿名事件不支持 .selector 成員。

使用 LOG 操作碼在匯編中觸發(fā)事件

imghttps://docs.soliditylang.org/en/v0.8.19/yul.html#evm-dialect

在匯編中觸發(fā)事件是可能的,使用 logN 指令,該指令對應于 EVM 指令集中的操作碼。

要在匯編中觸發(fā)事件,你必須將要由事件發(fā)出的所有數(shù)據(jù)存儲在 memory 中的特定位置。

一旦你將要由事件發(fā)出的數(shù)據(jù)存儲在內(nèi)存中,然后可以將以下參數(shù)指定給 logN 指令:

  • p = 從中開始獲取數(shù)據(jù)的內(nèi)存位置?;旧线@是一個內(nèi)存指針,或者是一個“偏移量”或“內(nèi)存索引”,具體取決于你如何稱呼它。

  • s = 你希望從 p 開始在事件中發(fā)出的字節(jié)數(shù)。

  • 所有其他參數(shù) t1、t2、t3t4 都是你希望成為可索引的事件參數(shù)。請注意這里有兩個重要的事情:1)這些參數(shù)應該與你事件定義中以相同順序定義的參數(shù)相同,2)這些參數(shù)應該放在內(nèi)存中以獲取數(shù)據(jù)。

下面的代碼片段顯示了如何在匯編中執(zhí)行此操作。

event ExampleEventAsm(bytes32 tokenId);

function _emitEventAssembly(bytes32 tokenId) internal{
bytes32 topicHash = ExampleEventAsm.selector;

assembly {
let freeMemoryPointer := mload(0x40)
mstore(freeMemoryPointer, topicHash)
mstore(add(freeMemoryPointer, 32), tokenId)

// emit the `ExampleEventAsm` event with 2 topics
log2(
freeMemoryPointer, // `p` = starting offset in memory
64, // `s` = number of bytes in memory from `p` to include in the event data
topicHash, // topic for filtering the event itself
tokenId // 1st indexed parameter
)
}
}

事件的 gas 成本

所有記錄操作碼(LOG0、LOG1、LOG2、LOG3、LOG4)都需要消耗 gas。它們具有的參數(shù)(主題)越多,它們消耗的 gas 就越多。

image-20240226195203141

此外,像索引或數(shù)據(jù)大小等其他因素也會導致事件發(fā)出消耗更多 gas。

檢查 - 事件 - 交互模式

檢查-生效-交互模式[9]也適用于事件。

一種檢測這些模式的方法是使用 Remix 靜態(tài)分析工具。

這種模式也可以被 Slither 檢測到。當對一個在外部調(diào)用后觸發(fā)事件的合約運行 slither 時,你將得到一個發(fā)現(xiàn),提示 “重入事件”。

因此,對于 dApp 來說,順序很重要,這樣你就可以正確地查看哪個事件首先、接下來和最后被發(fā)出。這在遞歸或重入調(diào)用的情況下尤其重要。如果在外部調(diào)用后觸發(fā)事件,并且這個外部調(diào)用進行了一個重入調(diào)用,那么:

  1. 第一個發(fā)出的事件是第二次重入調(diào)用完成后的事件。

  2. 第二個發(fā)出的事件是初始交易后發(fā)出的事件。

理解這一點,也使得可以在鏈下提供清晰的審計跟蹤,以監(jiān)視合約調(diào)用。你可以看到哪些函數(shù)首先和最后被調(diào)用,以及在執(zhí)行交易期間每個例程的運行順序。

slither 檢測器文檔[10] - Solidity 和 Vyper 的靜態(tài)分析器。

這種潛在的漏洞也在 Trail of Bits 對 Liquity[11] 智能合約的審計中發(fā)現(xiàn)并報告。

img
img

何時應該觸發(fā)事件?

在你的合約中可能有幾種情況下觸發(fā)事件可能很重要和有用。

  • 當受限制的用戶和地址執(zhí)行某些操作時(例如:所有者或合約管理員)。這包括例如受歡迎的 transfer ownership (address) 函數(shù),該函數(shù)只能由所有者調(diào)用以更改合約的所有者。

img
  • 更改一些關鍵變量或算術參數(shù),這些變量負責合約的核心邏輯。在 DeFi 協(xié)議的背景下尤其重要。

img

Slither 檢測器文檔[12]中描述了更多關于這些情況的信息。

這也在 Trail 對 LooksRare 的審計報告中描述了。

img
  • 監(jiān)視在生產(chǎn)中部署的合約以檢測異常。

img

查看 0xprotocol[13] 的詳細信息,了解有關事件的安全相關問題。

參考

  1. 匿名事件使用目的的缺失文檔(知其所以然)[14]

  2. [匿名事件的優(yōu)勢]

小編推薦下載

相關文章

更多>>

同類軟件下載