UID和ID

UID类型在sui::object模块中定义,是围绕ID类型包装而成,而ID类型则是围绕address类型包装。在Sui中,UID保证是唯一的,且在对象被删除后不可再次使用。

// 文件:sui-framework/sources/object.move
/// UID是对象的唯一标识符
public struct UID has store {
    id: ID
}

/// ID是地址的包装器
public struct ID has store, drop {
    bytes: address
}

新UID的生成:

  • UID是从tx_hash和递增的index派生而来的。
  • derive_id函数在sui::tx_context模块中实现,因此生成UID需要TxContext。
  • Sui验证器不允许使用未在同一函数中创建的UID。这防止了在对象被解包后预先生成和重复使用UID。

使用object::new(ctx)函数可以创建新的UID,它接受对TxContext的可变引用,并返回一个新的UID。

let ctx = &mut tx_context::dummy();
let uid = object::new(ctx);

在Sui中,UID充当对象的表征,并允许定义对象的行为和特征。其中一个关键特性是动态字段,这得益于UID类型的显式定义。此外,它还允许进行后文将要解释的对象转移(TTO)

UID的生命周期

UID类型通过object::new(ctx)函数创建,并通过object::delete(uid)函数销毁。object::delete函数通过值消耗UID,并且除非值是从对象中解包出来的,否则不可能删除它。

let ctx = &mut tx_context::dummy();

let char = Character {
    id: object::new(ctx)
};

let Character { id } = char;
id.delete();

保持UID

在对象结构解包后,并不需要立即删除UID。有时它可能携带动态字段或通过对象转移传输到它的对象。在这种情况下,UID可以被保留并存储在一个单独的对象中。

删除的证明

返回对象的UID的能力可以用于所谓的“删除证明”模式。虽然这是一个不常用的技术,但在某些情况下很有用,例如,创建者或应用程序可以通过交换已删除ID来激励对象的删除。

在框架开发中,这种方法可以用来忽略或绕过对“获取”对象施加的某些限制。例如,如果有一个强制执行传输逻辑的容器,类似于Kiosk,通过提供删除证明就可以特殊情况下跳过检查。

这是一个值得探索和研究的开放主题,可以以各种方式使用。

ID

谈到UID时,我们也应该提到ID类型。它是围绕address类型的包装器,用于表示地址指针。通常,ID用于指向一个对象,但没有限制,也没有保证ID指向一个现有对象。

ID可以作为事务参数在事务块中接收。此外,可以使用to_id()函数从一个address值创建ID。

fresh_object_address

TxContext提供了fresh_object_address函数,可以用于创建唯一的地址和ID。这在一些应用程序中分配唯一标识符给用户行为,例如市场中的order_id,可能非常有用。