Sui Verifier: Internal Constraint
In the Internal Permit section, we introduced internal type parameters: type parameters that only accept types defined in the calling module. There, std::internal::permit<T>() used the rule to produce a proof value. On Sui, the same rule protects a handful of critical framework functions directly - no permit value involved - and the component enforcing it is the Sui Verifier.
The Sui Verifier is a set of bytecode-level checks that run on top of regular Move verification, both at compilation and when a package is published onchain. Most of its rules formalize what this chapter has already described - such as the id: UID first-field requirement from the key ability section. The internal constraint is the rule that matters most for what comes next: a function marked with it can only be called with a type parameter T that is internal - defined in the calling module.
Let's look at the classic example - the emit function from the sui::event module (covered in detail in the Events section), which requires its type parameter to be internal to the caller:
module sui::event;
// Sui Verifier will emit an error at compilation if this function is
// called from a module that does not define `T`.
public native fun emit<T: copy + drop>(event: T);
Here is a correct call to emit. The type A is defined in the same module that makes the call, so the constraint is satisfied:
/// 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 {})
}
But calling emit with a type defined elsewhere - for example, the TypeName type from the Standard Library - is rejected:
// This one fails!
public fun call_foreign_fail() {
use std::type_name;
event::emit(type_name::with_defining_ids<A>());
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Invalid event.
// Error: `sui::event::emit` must be called with a type
// defined in the current module.
}
The effect is the same authority rule we established for struct fields and saw generalized by Permit: the module that defines a type decides what happens with it. For emit, it means only the defining module can emit events of its type; for the storage functions in the next section, it means the defining module fully governs how its objects enter storage - unless it opts out by adding the store ability.
Summary
- The Sui Verifier is a set of bytecode-level rules checked at compilation and on publish.
- The internal constraint restricts a function's type parameter to types defined in the calling module.
- It applies to a handful of critical framework functions: event::emit, and the restricted storage functions covered in the next section.
Further Reading
- Internal Permit - the same rule, available to any library through std::internal.