一次性见证(One Time Witness)
尽管常规的见证(Witness)是一种静态证明类型拥有权的好方法,但在某些情况下,我们需要确保见证仅被实例化一次。这就是一次性见证(One Time Witness,简称 OTW)的目的。
定义
一次性见证(OTW)是一种特殊类型的见证,只能使用一次。它不能手动创建,且每个模块中拥有唯一的实例。Sui 适配器将类型视为 OTW,如果满足以下规则:
- 只具有
drop
能力。 - 没有字段。
- 不是泛型类型。
- 模块名称为大写字母。
以下是 OTW 的示例:
module book::one_time {
/// The OTW for the `book::one_time` module.
/// Only `drop`, no fields, no generics, all uppercase.
public struct ONE_TIME has drop {}
/// Receive the instance of `ONE_TIME` as the first argument.
fun init(otw: ONE_TIME, ctx: &mut TxContext) {
// do something with the OTW
}
}
OTW 不能手动构造,任何试图这样做的代码都会导致编译错误。OTW 可以作为模块初始化器的第一个参数进行接收。由于 init
函数每个模块只调用一次,因此 OTW 保证只被实例化一次。
强制使用 OTW
要检查一个类型是否为 OTW,可以使用Sui 框架的 sui::types
模块提供的特殊函数 is_one_time_witness
。
use sui::types;
const ENotOneTimeWitness: u64 = 1;
/// Takes an OTW as an argument, aborts if the type is not OTW.
public fun takes_witness<T: drop>(otw: T) {
assert!(types::is_one_time_witness(&otw), ENotOneTimeWitness);
}
总结
OTW 模式是确保类型仅使用一次的强大工具。大多数开发者应该理解如何定义和接收 OTW,而 OTW 的检查和强制主要在库和框架中需要。例如,sui::coin
模块要求在 coin::create_currency
方法中使用 OTW,从而确保只创建一个 coin::TreasuryCap
。
OTW 是为接下来我们将要介绍的发布者(Publisher)对象打下基础的强大工具。