可擴展的 UDT(Extensible UDT,本文統一稱爲 xUDT)是基於 Simple UDT 的擴展,可用於定義更多 UDT 可能須要的行爲。sUDT 爲在 Nervos CKB 上發行 UDT 提供了一個最基本的核心,xUDT 則能夠創建在 sUDT 的基礎上,知足更多的潛在需求,例如監管。git
xUDT cell 向後兼容於 sUDT,全部 sUDT 規範中定義的既存規則仍然適用於 xUDT cell。在 sUDT 的基礎上,xUDT 擴展的 cell 以下:github
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 的架構以下:架構
依賴於 flags 的內容,可能會附加不一樣的擴展數據:函數
table Script { code_hash: Byte32, hash_type: byte, args: Bytes, } vector ScriptVec <Script>;
ScriptVec 結構中包含的每一個條目,都被解釋爲具備附加行爲的擴展腳本的 CKB 腳本哈希。當一個 xUDT 腳本被執行時,它將運行這裏所包含的每一個擴展腳本。只有當全部擴展腳本都經過驗證時,xUDT 纔會認爲該驗證是成功的。區塊鏈
一個擴展的腳本能夠被下列的任一種方式加載:ui
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。spa
若是該函數返回 0,則認爲對當前擴展腳本的驗證是成功的。code
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 均可以根據擴展腳本的規則進行驗證。
當 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 哈希相同。在此以後,它將使用與前面工做流中相同的邏輯。