查看原文
其他

RFC:可扩展的 UDT(Extensible UDT)

Xuejie Xiao Nervos 中文社区 2021-09-11


可扩展的 UDT(Extensible UDT,本文统一称为 xUDT)是基于 Simple UDT 的扩展,可用于定义更多 UDT 可能需要的行为。sUDT 为在 Nervos CKB 上发行 UDT 提供了一个最基本的核心,xUDT 则可以建立在 sUDT 的基础上,满足更多的潜在需求,例如监管。



数据结构



xUDT Cell


xUDT cell 向后兼容于 sUDT,所有 sUDT 规范中定义的既存规则仍然适用于 xUDT cell。在 sUDT 的基础上,xUDT 扩展的 cell 如下:

data: <amount: uint128> <xudt data>type: code_hash: extensible_udt type script args: <owner lock script hash> <xudt args>lock: <user_defined>


这个被加上去的 xudt args 和 xudt data 部分提供了所有 xUDT 所需的新功能,我们将会在下文阐述这些细节的架构。



xUDT Args


xUDT args 的架构如下:


  • 4 个字节的 xUDT 标记

  • 可变长度扩展数据

依赖于 flags 的内容,可能会附加不同的扩展数据:


  • 如果 flags 全部为 0,我们不需要任何扩展数据。值得注意的是,向后兼容的查看方式是,一个空白的 sUDT cell 也等于有一个全部为 0 的隐藏 flags 字段。

  • 如果 flags 是 0x1,那么扩展数据将包含一个以 ScriptVec 结构进行序列化的 molecule (https://github.com/nervosnetwork/molecule)

table Script { code_hash: Byte32, hash_type: byte, args: Bytes,}
vector ScriptVec <Script>;

ScriptVec 结构中包含的每个条目,都被解释为具有附加行为的扩展脚本的 CKB 脚本哈希。当一个 xUDT 脚本被执行时,它将运行这里所包含的每个扩展脚本。只有当所有扩展脚本都通过验证时,xUDT 才会认为该验证是成功的。

一个扩展的脚本可以被下列的任一种方式加载:

  • 有些扩展的逻辑可能已经有预定义的哈希,例如,我们可以使用 0x0000 ... 0001 来表示监管的扩展。这些脚本的实际代码已经被镶嵌在 xUDT 自身的脚本中了。

  • Owner lock (所有者的锁)可拿来使用:如果当前交易中的一个 input cell 使用了与当前扩展脚本相同脚本哈希的 lock script,我们可以认为该扩展脚本已经被验证。

  • 如果一个扩展脚本不匹配任何上述标准,xUDT 将使用包含在扩展脚本中的 code_hash 和 hash_type 以调用 ckb_dlopen2(https://github.com/nervosnetwork/ckb-c-stdlib/blob/37eba3102100808ffc6fa2383bcf9e1e2651c8ea/ckb_dlfcn.h#L108-L113) 的功能,从当前交易的 cell deps 中加载动态链接的脚本。如果脚本可以成功定位,xUDT 将寻找一个带有以下签名的导出函数:

int validate(int is_owner_mode, size_t extension_index, const uint8_t* args, size_t args_length);

is_owner_mode 表示当前 xUDT 是否通过所有者模式解锁(如 sUDT 所述),extension_index 指的是当前的扩展在 ScriptVec 结构中的索引。args 和 args_length 被设置为当前扩展脚本的 Script 结构中所包含的 script args。

如果该函数返回 0,则认为对当前扩展脚本的验证是成功的。

  • 如果 flags 是 0x2,扩展数据将包含前一节解释的 ScriptVec 结构的 blake160 哈希。实际的 ScriptVec 结构数据将包含在当前交易中的 witness 中。我们将在下面解释这一部分。



xUDT Data


xUDT 数据是一个以 XUDTData 结构来进行序列化的模组:

vector Bytes <byte>;vector BytesVec <Bytes>;
table XUDTData { lock: Bytes; data: BytesVec;}

包含在 XUDTData 中的 data 字段,必须与包含在 xUDT args 中的 ScriptVec 结构的长度相同。一些扩展可能需要在每个 xUDT cell 中存储特定于用户的数据。xUDT 数据为此类数据提供了一个放置的位子。

XUDTData 中包含的 lock 字段不会被 xUDT 脚本使用,它被保留用于当前 cell 脚本特定数据。

扩展脚本首先需要找到它定位在 xUDT args 中的索引,然后在 XUDTData 结构的 data 字段的同一个索引处,查找当前扩展脚本的数据。



操作



xUDT 采用与 sUDT 相同的治理操作:所有者锁控制所有治理行为,如代币铸造等。

然而,xUDT 的正常调用操作不同于 sUDT。根据所用的 flags,可能会有两种使用模式:


原始扩展脚本


当 flags 设置为 0x1 时,原始扩展数据将直接包含在 xUDT args 中。

Inputs: <vec> xUDT_Cell Data: <amount: uint128> <xudt data> Type: code_hash: extensible_udt type script args: <owner lock script hash> <xudt args> Lock: <user defined> <...>Outputs: <vec> xUDT_Cell Data: <amount: uint128> <xudt data> Type: code_hash: extensible_udt type script args: <owner lock script hash> <xudt args> Lock: <user defined> <...>Witnesses: WitnessArgs structure: Lock: <user defined> Input Type: <BytesVec structure>

与第一个输入 xUDT cell 相同的索引的 witness 是由 xUDT 脚本定位的。它首先被解析为 WitnessArgs 结构,因此 WitnessArgs 的 input_type 字段被视为 BytesVec 结构。这个结构也必须与 xUDT args 和 xUDT data 部分的长度相同。扩展脚本可能还需要特定交易的数据,以便进行验证。Witness 在此为这种数据需求提供了一个放置的位置。

注意,每个扩展脚本在交易中只执行一次。扩展脚本负责检查当前类型的所有 xUDT cell,确保当前扩展脚本的每个 cell 数据和 witness 都可以根据扩展脚本的规则进行验证。



P2SH Style Extension Script


当 flags 设置为 0x2 时,xUDT args 只包含扩展数据的 blake160 哈希。用户会被要求直接提供在 Witness 中的扩展数据:

Inputs: <vec> xUDT_Cell Data: <amount: uint128> <xudt data> Type: code_hash: extensible_udt type script args: <owner lock script hash> <xudt args> Lock: <user defined> <...>Outputs: <vec> xUDT_Cell Data: <amount: uint128> <xudt data> Type: code_hash: extensible_udt type script args: <owner lock script hash> <xudt args> Lock: <user defined> <...>Witnesses: WitnessArgs structure: Lock: <user defined>      Input Type: <Raw Extension Data> <BytesVec structure>

这里唯一的区别是,在相应的 WitnessArgs 结构中的 input_type 字段包含在 ScriptVec 数据结构中的原始扩展数据,xUDT 脚本必须首先验证这里提供的原始扩展数据的哈希,是否与 xUDT args 中包含的 blake160 哈希相同。在此之后,它将使用与前面工作流中相同的逻辑。






: . Video Mini Program Like ,轻点两下取消赞 Wow ,轻点两下取消在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存