by Xuejie Xiao, Jan Xie
Thanks to Quake Wang, Ian Yang for PoCs and feedback.
===== 目录 =====
- Goals
- Roles
- Basic Flow
- Data Schema
- Examples
- Nervos DAO
- Spore
- Appendix
CKB Transaction 是在链外构建并签名的,Transaction 的构建过程即客户端处理用户输入并生成计算结果的过程,涉及用户操作,inputs 的选择,outputs 的生成,手续费设置等方面。对于一个特定的 Transaction,它的构建、签名和广播可能发生在同一个节点上,也可能在不同节点上,构建过程本身可能是多个节点合作参与的。因此,CKB 应用的特点是状态在链外生成,链上验证,客户端需要深度参与应用的交易处理,CKB Transaction 的协同创作过程即 CKB 应用的执行过程。
CKB Transaction CoBuild Protocol 描述的是一个多个参与方之间协同创作 CKB Transaction 的链外流程,包含与交易构建 (Building) 和签名 (Signing) 相关的标准流程和数据交换格式。我们希望通过提出和定义这样一个标准流程,降低 CKB 应用的开发门槛,提高 CKB 应用之间的可组合性,提高应用的用户体验,促进 CKB 应用角色的去中心化,使得 CKB 应用参与角色可以更容易的相互协作。
这篇文章将概述 Transaction CoBuild Protocol 的目标,角色和思路,并给出具体的例子供参考。CoBuild protocol 的设计和实现还在进行中,我们正在与社区团队一起构建 PoC 和搜集反馈。
Goals
CKB Transaction CoBuild Protocol 的设计目标包括:
- Message signing: 构建一个对终端用户友好的签名标准(类似 EIP712),用户可以知道自己确认的是什么动作,钱包可以确认呈现给用户签名的 message 与交易数据一致,script 可以验证用户签名的消息与交易行为一致。
- Script interface: 构建一个友好的 on-chain script 调用标准。一个 type/lock script 类似 Ethereum 上一个 solidity 合约,可以定义多个 actions (functions), 这些 actions 构成了 script 的接口。应用开发者在和一个 CKB app 做交互的时候,应该可以通过
ScriptInfo
拿到它的 scripts 和对应的 actions, 然后构造Message
. 只要有了Message
, 后续的签名和inputs/outputs都有标准流程/自动化工具可以实现,开发者只需要处理Message
, 不需要自己处理交易数据。这样开发者只需要和ScriptInfo
/ actions /Message
打交道,可以获得与处理 solidity ABI / message 类似的体验。 - Witness Layout: 构建一个方便组合、方便工具自动编排的 Witness layout 标准,代替现有的 WitnessArgs.
- Transaction Building: 提供链外合作构建 Full/Open Transaction 的标准流程及据交换格式。
- P2P based, Local first: 所有流程中所有参与角色应该是无需许可可以自由加入自由选择的,一个具体的参与者可以承担一个或者多个角色。我们希望由此构建一个基于 p2p 范式的 perpetual app network. (proxy 或者 server/client 模式可以用来解决某些特殊场景的兼容性,但不应该放到标准流程中。)
Roles
协同创作交易的过程中涉及如下角色:
- Builder: 提供完整 transaction 所需要的素材,例如 inputs, outputs, messages 或者除了签名之外的 witnesse 数据等。
- Asset Manager: 理解 CKB 上的资产(e.g. CKByte, xUDT, Spore),能够查询并展示资产,提供相应的资产操作。
- Fee Manager:分析给定交易支付的 fee 及 feerate,展示 fee/feerate 给用户,根据 CKB 交易池状况设置合理手续费;
- Signer: 管理 keypairs, 根据用户请求对数据(CKB 交易或者是任意 message)进行签名;
参与方可以承担一个或者多个角色。
接下来我们会基于最常见的场景概述 CoBuild protocol,其中 CKB 应用承担 Builder 角色,Wallet 承担 Asset Manager, Fee Master 以及 Signer 的角色,CKB 应用, Wallet, 用户按照标准流程进行交互。
更复杂的情况,例如有多个 builder, 或者 asset manager, fee manager ,signer 分别是不同参与方,需要根据具体场景具体讨论,本文不做深入。
Basic Flow
用户在使用 CKB app 的过程中
- 点击 app 某个按钮发起操作,app 根据用户请求的操作,生成
Message
; - app (as Builder) 根据自己的应用逻辑,处理
Message
得到执行结果,用这些数据构建对应的Transaction
, 体现用户动作 (Message) 和对应的执行结果 (inputs/outputs). Transaction witness 中放置相应的WitnessLayout
数据(其中包含Message
)。 - app 构建
BuildingPacket
, 将Transaction
放入BuildingPacket.payload
中,将Message
依赖的ScriptInfo
放入BuildingPacket.script_infos
中,将Message
放入BuildingPacket.message
中, 将Transaction inputs
对应的 cell 内容放入到BuildingPacket.resolved_inputs
中; - app (as Fee Manager) 计算并为交易设置手续费,更新
Transaction
,如果手续费可以允许 wallet 进行调整, 那么设置BuildingPacket.change_output
将对应的 output 指定为用于调整手续费用途 - app 将
BuildingPacket
发送给 wallet (as Signer), 请求 wallet 进行签名; - wallet 解析
BuildingPacket
, 将Message
,payload
, 以及script_infos
呈现给用户确认:
a. 如果用户同意,对BuildingPacket.payload
中的交易数据进行签名,根据 WitnessLayout 规则将签名填入交易 witness 中,将完整的签名后交易广播。
b. 如果用户拒绝,通知 CKB App 签名请求被拒绝。
Transaction Building & Signing 流程图
Data Schema
交易构建流程中使用的核心数据结构是 BuildingPacket
, 链上合约处理的核心数据结构是 WitnessLayout
,这两个结构通过 Message
关联起来。
其中数据结构定义如下:
// 这是一个汇总所有 CoBuild 数据结构的 Schema
//
// WitnessLayout, BuildingPacket 是两个入口:
// - WitnessLayout 是 on-chain scripts 构造/解析 witness 入口
// - BuildingPacket 是 Transaction Co-build 流程中各方交换数据的标准格式
// 考虑到未来可能的升级需要,入口结构都是 union,可以通过增加 variant 进行扩展。
array Byte32 [byte; 32];
array Hash [byte; 32];
vector ByteVec <byte>;
vector String <byte>; // for UTF-8 encoded bytes
// A (script_info, script, action) combo
// 代表用户想要执行的具体的动作: app XXX 中 X script 的 action Y
table Action {
script_info_hash: Byte32, // script info
script_hash: Byte32, // script
data: ByteVec, // action data
}
vector ActionVec <Action>;
table Message {
actions: ActionVec,
}
table ScriptInfo {
// The dapp name and domain the script belongs to
name: String,
url: String,
// Script info.
// schema: script action schema
// message_type: the entry action type used in WitnessLayout
script_hash: Byte32,
schema: String,
message_type: String,
}
vector ScriptInfoVec <ScriptInfo>,
table ResolvedInputs {
outputs: CellOutputVec,
outputs_data: BytesVec,
}
table BuildingPacketV1 {
// 表示用户操作,包含 actions
message: Message,
// standard CKB transaction: <https://github.com/nervosnetwork/ckb/blob/3d674d558e5574f0c77a52798775c903561a933a/util/gen-types/schemas/blockchain.mol#L66>
// 包含钱包完成功能所需要的、与 Message 对应的交易信息。
// `Message` 包含的是用户主动发起的动作信息,这些动作会被 builder 理解并转化为对应的
// 交易(也就是对应 Message 的 state transition)填入到 BuildingPacket.payload 中。
payload: Transaction,
// resolved_inputs 会存有 payload transaction inputs 所对应的 cells 信息
// 钱包可以用这个信息来计算和显示 ckb transfer 的数值和手续费
resolved_inputs: ResolvedInputs,
// 代表 payload transaction 哪个 output 是找零, 可选项
// 如果为空, 则代表当前这个 transaction 无法调整找零, 相当于只能使用指定的手续费
// 如果不为空, 则代表钱包可以修改对应 output 上的 capacity, 来实现调整手续费的目的
change_output: Uint32Opt
// Message 中 actions 依赖的所有 ScriptInfo
script_infos: ScriptInfoVec,
// 一个交易可能会用到多个不同的 lock script,每个 lock script 在 Signing 过程中,
// 都可能会需要交换一些临时数据,这些数据可以保存到这里。这些数据不需要签名也不会被包含到最终交易。
lock_actions: ActionVec,
}
union BuildingPacket {
BuildingPacketV1,
}
table SighashAll {
// seal 的设计意图是用来存放用来 cover 交易中其他部分的“最终的封印”,e.g. signature
// seal 本身在交易广播后是有可能被其他人修改的 (malleable),除 seal 外的其他部分受到 seal 保护是不可修改的(non-malleable)。
// 通过专用的字段 seal 有助于把 witnesses 里面需要被 signature 保护的数据和 signature 自身隔开,方便代码处理
seal: ByteVec,
message: Message,
}
table SighashAllOnly {
seal: ByteVec,
}
// placeholder for open transactions
table OtxStart {...}
table Otx {...}
union WitnessLayout {
SighashAll: 4278190081,
SighashAllOnly: 4278190082,
Otx: 4278190083,
OtxStart: 4278190084,
}
Examples
Nervos DAO
有了 CoBuild 的帮助,我们就可以为 Nervos DAO 构建独立的 web UX 了!Nervos DAO type script 早就在 mainnet 上运行,过去只有 Neuron 和 CKBull 少数几个应用内置了对 Nervos DAO 的支持,现在我们可以很轻松的为它构建 web UX,正如这个 PoC 所展示的。不仅如此,我们还可以将 Nervos DAO app 与 JoyID, Unisat, OKX wallet 或者其他 wallet 集成起来,方便用户使用。
如果想要了解更多细节,请翻阅这个仓库中的代码和文档。
Spore
附录
- CKB Open Transaction (OTX) CoBuild Protocol Overview
- CoBuild Hashes
- Lock/Type Script Validation Rules
- Custom Union Ids in WitnessLayout
- CoBuild-Only or CoBuild+Legacy
2024/02/16 更新:增加了目录以及四个附录:“CoBuild Hashes”, “Lock/Type Script Validation Rules”, “Custom Union Ids in WitnessLayout”, “CoBuild-Only or CoBuild+Legacy”.
2024/02/14 更新:增加了 附录 以及 CKB CoBuild Open Transaction (OTX) Overview.
2024/02/11 更新:增加了 例子:如何让 Spore 支持 CoBuild.
2024/03/15 更新:调整了 lock script 校验规则,Action 也可以使用 lock script hash 作为 script_hash
项的值