一种可更新的script插件集(Extensible Script)

可更新的脚本插件集(Extensible Script)

在看了看 RFC: Extensible UDT后,发现xUDT的xudt args存在于用户的Typescript中,从而导致xUDT在一开始就需要决定使用哪些扩展,而很难中途去添加或者删除扩展,因为很难让所有用户的Cell都同时更换typescript的args。
在与@kylexu沟通后,我们想到一种可更新的脚本插件集,但目前只有idea。

出于监管目的或者规则更新的需要,或者解锁逻辑的增删,脚本管理者有时需要在原来的逻辑上动态增添逻辑,目前已有的代码更新是通过全局唯一的typescript以及type字段来实现,但是这种思路适用于代码更新,但不适用于动态的增减插件。

本方案也借助将TypeID,同时结合了xUDT的思路(copy了许多文字)。

数据结构

符合xScript的Cell数据结构可如下所示:

用于typescript时:

data:
    <issuer_defined> 
type:
    code_hash: extensible_script type script
    args:  typescript hash
lock:
    <user_defined>

用于lockscript时:

data:
    <issuer_defined> 
type:
    <user_defined>
lock:
   code_hash: extensible_script type script
   args:  typescript hash

你可能注意到script的args不再是Owner lockhash,而是变成了一个typescript hash,那么这个typescript hash意味着什么呢?

每个想要利用可更新的脚本插件集的发行方,都需要用Type ID发行一个plugins Cell用于存放所有的插件,该plugins Cell使用TypeID以保证全局只有一个cell拥有该typescript,这个typescript的hash就是用户typescript的args域的值。

extensible_script执行时,会在dep cells里寻找一个typescript hash与args一致的cell,该cell即为plugins cell,如果找不到这样的cell,则返回错误。

该typescript全局唯一的plugins Cell的数据结构可如下:

data:
    <xscript flags> <xscript data>
type:
    code_hash: type ID script
    args:  type ID args
lock:
    Owner lockhash

xscript flags是一个四字节的标记:

  • 如果flags全部为0,则不对脚本做任何验证
  • 如果flags是0x1,那么那么扩展数据将包含一个以 ScriptVec 结构进行序列化的 molecule,并且需要所有的script全部验证成功,该typescript才验证成功。
  • 如果flags是0x2,那么那么扩展数据将包含一个以 ScriptVec 结构进行序列化的 molecule,只需要任意一个script验证成功,该typescript即验证成功,具体验证哪一个,可以在Witness的里指定,由xScript脚本选择。
  • 如果flags是0x3,扩展数据将包含前一节解释的 ScriptVec 结构的 blake160 哈希。实际的 ScriptVec 结构数据将包含在当前交易中包含的 witness 中,但验证逻辑类似0x1。
  • 如果flags是0x4,扩展数据将包含前一节解释的 ScriptVec 结构的 blake160 哈希。实际的 ScriptVec 结构数据将包含在当前交易中包含的 witness 中,但验证逻辑类似0x2。
  • 其他的flag含义待定。
table Script {
    code_hash:      Byte32,
    hash_type:      byte,
    args:           Bytes,
}

vector ScriptVec <Script>;

ScriptVec 结构中包含的每个条目,都被解释为具有附加行为的扩展脚本的 CKB 脚本哈希。当一个xscript 脚本被执行时,它将按照flags指定的模式执行扩展脚本。

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

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

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

  3. 如果一个扩展脚本不匹配任何上述标准,xscript 将使用包含在扩展脚本中的 code_hash 和 hash_type 以调用 ckb_dlopen2 的功能,从当前交易的 cell deps 中加载动态链接的脚本。如果脚本可以成功定位,xscript 将寻找一个带有以下签名的导出函数:

    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 结构中的索引。argsargs_length 被设置为当前扩展脚本的 script 结构中所包含的 script args。

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

可能的用途

除了可以加监管扩展外,通过这种策略,我们可以构造一个将铸币权和最终管理权分离的UDT,并且二者都可以转让,在插件中加入一个UDT验证逻辑,其args可以放置Owner lockhash,而拥有plugins Cell的所有权的主体可以修改其args域,从而转移铸币权,同时plugins Cell也可以转移出去,将管理权彻底转移。

另一种可能的用途是多模式的锁脚本,可以在plugins Cell中加入多种验证模式,比如ETH地址、Tron地址,Webauthn地址,电子邮件地址等任意种验证模式,同时,而且通过修改脚本,可以加入更精细的限制,比如每种解锁逻辑可以转出的代币上限,或者可以解锁的时间等等。当然,由于多模式锁脚本是用户自己指定的,其实可以把插件信息直接放在lock_script的args域,然后通过动态链接来验证,从而不需要另外指定plugins cell。

6 Likes