Sui 驗證器:內部限制 (Sui Verifier: Internal Constraint)
在 內部許可章節中,我們介紹了內部型別 參數:只接受於呼叫模組中定義之型別的型別參數。在該章節中, std::internal::permit<T>() 使用此規則產生證明值。在 Sui 上,相同規則會直接 保護少數關鍵框架函式——不涉及許可值——而負責強制執行此規則的元件便是Sui 驗證器。
Sui 驗證器是一組位元碼層級的檢查,會在編譯期間及套件發布至鏈上時,於一般 Move 驗證之上執行。其大部分規則皆將本章先前已說明的內容形式化——例如 key 能力章節中的 id: UID 第一欄位要求。對接下來內容最重要的是 內部限制:標記了此限制的函式,只能以內部型別參數 T 呼叫——也就是在呼叫模組中 定義的型別。
讓我們看看經典範例:sui::event 模組中的 emit 函式(於 事件章節詳細說明),其要求型別參數必須是呼叫端的內部型別:
module sui::event;
// 若從未定義 `T` 的模組呼叫此函式,Sui 驗證器將在編譯時
// 產生錯誤。
public native fun emit<T: copy + drop>(event: T);
以下是正確的 emit 呼叫。型別 A 定義於進行呼叫的相同模組中,因此符合限制:
/// Defines the type `A`.
module book::exercise_internal;
use sui::event;
/// Type defined in this module, so it's internal here.
public struct A has copy, drop {}
/// Works, because `A` is defined in this module.
public fun call_internal() {
event::emit(A {})
}
但若以其他位置定義的型別呼叫 emit——例如來自 標準函式庫的 TypeName 型別——則會遭拒絕:
// 此呼叫會失敗!
public fun call_foreign_fail() {
use std::type_name;
event::emit(type_name::with_defining_ids<A>());
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 無效的事件。
// 錯誤:呼叫 `sui::event::emit` 時,必須傳入於
// 目前模組中定義的型別。
}
其效果與我們為結構欄位建立、並透過 Permit 推廣的權限規則相同:定義型別的模組決定該型別可進行哪些操作。對於 emit,這表示只有 定義模組可以發出其型別的事件;對於下一節的儲存函式,則表示定義 模組完全掌控其物件如何進入儲存空間——除非它藉由加入 store能力選擇退出此限制。
總結 (Summary)
- Sui 驗證器是一組在編譯時及發布時檢查的位元碼層級規則。
- 內部限制會將函式的型別參數限縮為於呼叫模組中定義的型別。
- 它適用於少數關鍵框架函式:event::emit,以及下一節介紹的受限制 儲存函式。
延伸閱讀 (Further Reading)
- 內部許可——透過 std::internal 向任何函式庫提供的相同規則。