跳至內容
0%

什麼是 Solidity 中的 modifier?

作者 Frederik B

發布於 2022年10月4日閱讀時間 1 分鐘

Solidity 是一種物件導向的高階語言,用於實作智慧合約。在學習 Solidity 的過程中,你會遇到修飾器(modifier),這是一種特殊類型的函式,用來修改其他函式的行為。

在本文中,我們將說明 Solidity 修飾器的作用、介紹修飾器的類型,並示範如何使用它們。讀完本文後,你將能夠辨識 Solidity 修飾器並理解如何使用它們。

Solidity 修飾器的作用是什麼?

**修飾器是一種特殊的 Solidity 函式類型,用來修改其他函式的行為。**舉例來說,開發者可以使用修飾器,在允許函式執行之前檢查是否滿足某個條件。

修飾器與函式類似,可以接受參數並具有回傳型別。修飾器也可以串連使用,也就是說一個函式上可以套用多個修飾器。

不過,修飾器只能修改合約邏輯,無法修改合約的儲存空間,包括結構體(struct)在內。修飾器能減少開發者需要撰寫的樣板程式碼,並讓 Solidity 程式碼更易讀。

Solidity 函式可以套用多個修飾器嗎?

**可以,開發者可以在單一 Solidity 函式上使用多個修飾器。**多個修飾器之間以逗號分隔。使用多個修飾器時,有一點需要注意:修飾器的順序很重要。清單中第一個修飾器會先被執行,第二個修飾器接著被套用,依此類推。

舉例來說,如果你有一個修飾器用來檢查使用者是否已通過驗證,另一個修飾器用來檢查使用者是否有權限查看某個資源,那麼這些修飾器套用的順序,將決定使用者最終能否查看該資源。

Solidity 修飾器有哪些不同類型?

Solidity 修飾器大致可分為四類:閘門檢查(gate check)、前置條件(prerequisite)、過濾器(filter),以及重入攻擊防護(reentrancy attack prevention)。

1. 閘門檢查

「閘門檢查」是一種修飾器,會在允許函式執行前,檢查某個條件是否成立。

舉例來說,假設你有一個函式讓使用者可以從帳戶提款,但在函式執行前,開發者可能想先檢查使用者的帳戶餘額是否足夠進行提款。這種檢查就被視為閘門檢查修飾器。

另一個閘門檢查的例子,是在允許使用者查看某項資源前,先檢查使用者是否已通過驗證。

2. 前置條件

「前置條件」是一種修飾器,用於為函式執行設定好環境,而不是檢查某個條件是否成立。

舉例來說,Solidity 開發者可能會使用一個函式,要求呼叫時必須連同傳送一定數量的 Ether 才能執行。在這種情況下,前置條件就是負責設定 Ether 餘額的函式。

3. 過濾器

「過濾器」是一種修飾器,會檢查某個條件是否成立,若成立,就允許函式執行。若條件不成立,函式就不會執行。

與閘門檢查不同的是,即使條件成立,閘門檢查也不會自動允許函式執行;而過濾器則會在條件成立時允許函式執行。

4. 重入攻擊防護

重入攻擊是一種攻擊方式,惡意行為者試圖透過遞迴呼叫多次執行某個函式,藉此進行利用。

舉例來說,假設你有一個函式讓使用者可以從帳戶提款。重入攻擊者可能會嘗試多次呼叫該函式,藉此提領超過其帳戶實際餘額的金額。

為了防止重入攻擊,你可以使用修飾器來檢查該函式是否正被遞迴呼叫。若是,函式就不會執行。

require 與 Solidity 修飾器之間的關係是什麼?

require 經常與修飾器互換使用,因為兩者都能讓你在允許函式執行前,檢查某個條件是否成立。若指定的條件不成立,編譯器就會拋出錯誤。

舉例來說,以下敘述使用了 require 關鍵字,讓只有擁有者才能與該函式互動:

require 與 Solidity 修飾器之間存在一些重要差異:

  1. 修飾器可以用來為函式執行設定環境(如前置條件的情況)
  2. require 只能用來檢查某個條件是否成立
  3. 修飾器可以被覆寫(override)
  4. require 不能被覆寫

Solidity 處理修飾器的方式與 Vyper 有何不同?

Vyper 是一種以 Python 風格設計、用於 Ethereum 智慧合約開發的語言,為了提升安全性做出了一些取捨,其中包括不使用修飾器。取而代之,開發者需在函式內使用內嵌的檢查與斷言(assert),而在修改智慧合約時,也需要再次以明確的方式將變更寫在函式中。

Vyper 選擇移除修飾器功能,提升了智慧合約的可稽核性,因為讀者不必在腦中將修飾器套用在函式上,才能理解該函式會執行什麼動作。

什麼是修飾器覆寫(modifier overriding)?

關鍵字「virtual」可用來標示某個修飾器可以在衍生合約中被覆寫。舉例來說,假設你有一個合約「Base Contract」,其中有一個修飾器「myModifier」。你還有一個合約「Derived Contract」,它繼承自「Base Contract」。

如果「Base Contract」被標示為「virtual」,那麼它就可以在衍生合約中被覆寫。這種做法常見於函式庫的情境中,讓合約具備可自訂性。

修飾器如何與繼承機制配合運作?

**繼承讓你能夠擴充合約的屬性與特性,而在修飾器的情境中,繼承讓你可以新增修飾器,或覆寫既有的修飾器。**這可以透過前一節提到的 virtual 關鍵字來實現。

以下這個簡單的實作範例,展示了繼承與修飾器如何協同運作:

在這個範例中,合約 B 繼承自合約 A。兩個合約都有一個名為「X」的修飾器。不過,在合約 B 中,這個修飾器被標示為「override」,表示它覆寫了合約 A 中的修飾器。

如何在 Solidity 中使用修飾器

要使用修飾器,首先需要在合約中定義修飾器函式。修飾器會使用一個特殊符號「_;」,只有在修飾器的條件被滿足時,才會插入函式主體。

以下合約示範了如何使用修飾器:

在上面的範例中,該合約有兩個修飾器:「onlyOwner」與「costs」。

第一個修飾器會檢查 msg.sender 是否為合約擁有者,第二個修飾器則檢查 msg.value 是否大於或等於某個特定價格。

這兩個修飾器都可以套用在合約中的任何函式上。

繼續學習 Solidity 修飾器

修飾器是用來修改其他函式行為的函式。透過使用修飾器,你可以減少需要撰寫的樣板程式碼,並讓你的 Solidity 程式碼更易讀。

若想繼續學習 Solidity 修飾器,並了解如何成為 Solidity 開發者,歡迎報名 Alchemy University 為期 7 週的 Ethereum Developer Bootcamp。這個由 ChainShot 團隊原創、完全免費的 Solidity 速成課程,是學習 Solidity 的最佳途徑。如果開發者對開發領域完全陌生,Alchemy University 為期 3 週的 JavaScript 速成課程,會是在開始 Ethereum bootcamp 之前很好的先修課程。

Background gradient

打造區塊鏈魔法

Alchemy 結合最強大的 Web3 開發者產品與工具,並提供資源、社群與卓越的支援。