Cell模型的Layer1.5开发范式

1. 概述

在Jan的【硬核:CKB 与 Cell 就是 Bitcoin 与 UTXO 的一般化版本 】文章中,将Cell模型作为抽象的状态验证模型,即Cell存储状态,而Cells->Cells作为一种抽象的状态转换,在现今的大部分基于Cell模型开发的应用,都按照这种模式进行,如sUDT,Cell存储sUDT的余额,mNFT,Cell存储NFT的元数据,DAS,Cell存储域名的基础信息。

但是另一方面,可使用的Cell在一定阶段是有上限的,短期大约30G的空间,这仅够存储两、三亿个不同的sUDT Cell甚至一亿个DAS cell,这并不算多。在某种意义上,在这种模型下,后面的Dapp将面临越来越高的使用成本,即便其他资源(如网络、计算)并未使用充分,但CKB的总量有限,不得不搬去Layer2开发,曾经的EOS在资源分配模型上就存在这个问题,由于CPU和RAM资源被买光出现了人为拥堵,当然,EOS的资源定价波动更大。

虽然我们有了GodWoken,可以开发Layer2的应用,但是由于Cell模型和CKB-VM的优越性,基于Layer1开发的应用可以具有更大的灵活性,Layer1应用可以从Rollup中获得经验,利用某种向量承诺或者累加器方案(如Sparse Merkle Tree或者Verkle Tree)将状态存储在链下,而只在Cell中存储状态根,类比一下就是,原来的Layer1开发是建一层小别墅,而通过向量承诺,可以复用一块地皮,建设摩天大楼,相比GodWoken这种Layer2设计,可以将新的开发范式称为Layer1.5。

在这种情况下,使用Cell模型可以取得类似账户系统的使用体验,同时极大减少CKB的状态占用,这并不会减少CKB的价值捕获能力,因为这意味着CKB可以支撑起更多的Layer1应用,用户和开发者永远是衡量一个网络价值最重要的指标,而不会像EOS一样被某项资源限定,使得即使有大量空闲的计算和网络资源仍然拥堵。

目前已有的采用Layer1.5开发范式的应用有, Compact Extension for m-NFT Protocol: The Key to Mass Adoption用于压缩NFT占用以节省成本,以及 RFC: Compact UDT Lock用于压缩UDT的状态占用以节省成本。

简述一下,Layer1.5交易的验证分为三步,如下

  1. 资源操作的正确性验证

    这一步对应到Cell模型中,类比到Cell模型就是typescript,即状态碎片在转换过程的正确性,例如1USD可以变成两个0.5USD,但是不能变成2USD。需要验证每一项的转换是否正确。

  2. 资源的权限验证。

    这一步对应到Cell模型中,可以认为是lockscript,对应的是状态碎片是否可被使用的逻辑,例如Unipass解锁,secp256k1验签等。需要验证每一项的解锁条件是否满足。

  3. 状态转换的正确性验证。

    这一步对应是验证旧状态到新状态转换的正确性,即在应用了第一步的资源操作后,旧状态是否严格变成了新状态。

Layer1.5具有Layer1同等的安全性,但可用性保证还有待定序规则的设计,它很像zkRollup,但不需要实现复杂的zk电路就可以取得类似的效果,zkRollup实现了链下状态存储和完全的链下计算,但Layer1.5只实现链下状态存储,链上仍然完整的计算量,但考虑到zkRollup的验证成本远远大于一般应用的验证成本,所以Layer1.5在计算方面并没有过多消耗。

在经过充分优化后,也许zk的验证成本可以大大降低,并且电路撰写难度也大大降低,在那个时候,Layer1.5留下的开发经验和应用可以直接转移到zkRollup中,毕竟它们都是基于有效性证明做的,换句话说,将上面三步验证写成零知识证明电路后,它就是zkRollup。

因此,Layer1.5可以像Godwoken一样设计成一个框架,其资源操作的正确性验证和权限验证可以做成接口,然后将需要的代码通过celldeps依赖,然后通过动态链接或者exec来调用,相比Layer1,在表达能力上并没有让步,而且另一方面,Layer1.5开发模型又具有账户模型的特性,可以理解为一种同时具有Extended UTXO模型与账户模型优点的混合模型。原本废弃的Layer1版Polyjuice以及Gliadex可以使用Layer1.5的开发范式来重新实现。

2. Layer1.5 优劣

我们可以简单分析下这种开发模式的优劣:

2.1 优

  1. 极大减少了状态专用,节省了链的负担,压缩后的状态不会给Layer1带来任何状态存储成本。
  2. Layer1.5的交易可以批量上链,以解决UTXO的状态争用问题,从而获得共享状态,可以实现swap等类型的Layer1应用。
  3. 通过使用一些交易压缩技巧,可以节省交易大小,而Cell模型的交易具有不可避免的固定空间成本,因为在状态分片以后,网络资源可能是最重要的限制了,应该尽量压缩交易。

2.2 劣

  1. 交易需要附带一个状态转换证明,这会带来额外的网络和计算成本,虽然也可以用零知识证明压缩该证明。
  2. 需要设计机制来给Layer1.5的交易定序,这有点类似Rollup,否则,恶意用户可以DDOS这个Layer1.5应用。
  3. 脚本开发相比纯Layer1开发相比麻烦了一些,在Cell模型下可以自由选择Typescript以及Lockscript,但是在Layer1.5就得通过动态链接或者exec来实现这种动态性,(比如动态地选择解锁方式,Unipass,ETH,Tron等)。
  4. 需要更复杂的链下组件,简单的Layer1开发只用写拼交易逻辑即可,而Layer1.5需要Aggregator等复杂的链下组件,复杂度类似Layer2项目,这个复杂性也许可以通过设计一个Layer1.5通用开发框架来解决。
  5. Layer1.5由于将一部分状态进行了分片化,可能会影响全网的可组合性,详情见跨Cell通信一节。

总的来说,Layer1.5的方案并没有给应用带来过多的额外成本,除了Proof之外,在Layer1该占用的网络资源和计算资源并不会少,但是Layer1.5的模式,使得一个状态哪怕长期不动用,也不会给Layer1带来任何附加成本。

3. 模型选择

在区块链常用的编程模型中,面向状态的UTXO和面向账户的账户模型,以及面向资源的Move语言编程模型等,Layer1.5理论上可以采取任意一种。

如果采用UTXO模型,则将向量承诺中的每一个叶子节点作为UTXO,每笔交易我们可以消耗一些Leaf节点,同时生成一批新的Leaf节点,例如NFT应用就可以采用这种模式来设计,同质化代币也可以这样设计(硬币模型)。

也可以采取账户模型,将向量承诺的每个leaf作为一个账户,其内部具有一些代币余额,或者contract_code(合约码可以放在某个Cell内,然后通过celldeps使用),这样的话,我们可以使用这个模型实现一个swap,甚至evm兼容层。

甚至可以将这两种混合使用,NFT存储在一些leaf里,而账户存储在另一些leaf里,如此,NFT可以设定一个标价,一个账户通过将资产转到卖方账户来购买,同时NFT的所有权则自动转移到买方账户,NFT、域名交易市场就可以这样设计。

相比UTXO的诸多限制,在Layer1.5可以按照任何你想要的方式解释一个leaf包含什么,同时没有状态争用问题,也不需要状态租赁,因为使用有效性证明,只需要一个节点同步Layer1.5的状态即可保证安全性。

4. 跨Cell通信

另一个需要考虑的设计是通信,与分片的跨片通信一样,假如我们设计了Layer1.5应用,同时保持全网的可组合性,那么跨Cell通信就是必须的。

  1. 借助Cell的异步通信

    最简单的思路是,当一个Leaf想要跨Cell通信时,将这个资源提取到一个Layer1的Cell中暂存,然后再转移进另一个压缩Cell中,这种异步的通信机制不会带来任何副作用,因为Cell是独一无二的,不会有重放攻击问题,但在CKB的模型下,需要有人为这段时间的状态占用付出CKB的成本,这将使得问题复杂化。

  2. 同步组合通信

    另一种无副作用的通信机制是,在A 压缩Cell和B 压缩Cell想要通信时,计算出整个通信的结果,并在Layer1同时消耗A 压缩Cell和B 压缩Cell,以实现同步通信,由于它们的通信在一笔交易中已经完成,同样不会有重放攻击问题,但是这个机制对同步的要求过高,如果A Cell和B Cell的控制权并不完全在同一组织手上,则有极大的失败风险,或者这两个Cell所属为两个不同组织,他们可能需要像Grin的交易一样,双方都在线并交互才能完成这一次通信。

  3. 异步通信

    异步通信是使用最方便的一种方案,类似分片方案的收据,A cell的某笔交易指定一个收据,这个收据将由另一个Cell获取并执行,但是这种模式需要小心设计,以免有重放攻击的可能,同时,如 Compact Extension for m-NFT Protocol: The Key to Mass Adoption中所使用的方案,这种模式会带来只增不减的状态累积问题,即需要使用withdrawal_nft和claim_nft来通信,并且这两者的状态将永远累积。

也许这种Layer1.5的开发范式还有更好的跨Cell通信机制,如果你有更好的方案,可以补充。

5. 其他需要考虑的问题

5.1 时间问题

许多Dapp需要时间这一特性,如时间锁,借贷和流动性挖矿也需要时间来统计利息和收益,而Layer1.5很难加入时间这个属性,这是一个问题,也许可以通过header_deps,来使得整个Layer1.5交易知道自己所处的大概时间,或者可以使用时间预言机来解决这个问题。

5.2 定序器问题

在某些应用中,可以使用简单的全局锁来控制,如压缩Cell保存的是某个个人的资产。对于另一些应用,如游戏,可以采取其他策略,即普通时候是全局锁控制,但假如Cell已经24小时没有被消耗过,则它的权限控制自动转换成AlwaysSSuccess以便用户取回自己的资产。

同时,许多应用是采用Dao的形式来做的,那可以把解锁逻辑设计成PoS机制,拥有投票权的用户可以搭建一个Layer1.5节点参与提交交易上链。

总之,这个问题可以参考其他Layer2的选择。

6. 相关组件需求

6.1 Aggregator

由于Layer1.5将状态存储在链下,所以需要有一个链下组件存储状态,它同时还负责给某个上链区块(即批量交易),生成状态转换证明,这需要一个完整的后端服务。

6.2 Explorer

在Layer1.5的交易并不能在Layer1的交易上提现,所以我们可能还需要设计一个特制的交易浏览器,由于Layer1.5天然的状态分片属性,这种浏览器如何设计和表现还有待讨论。

6.3 通用Identity接口

Identity设计即我们该如何设计Layer1.5交易中的权限控制问题,这在Cell模型是使用lockscript实现的,在Layer1.5我们也需要设计一个Identity体系,比如每个Lock都需要开放一个通用的接口,以便Layer1.5的交易依赖使用,从而在Layer1.5也实现账户抽象。如果仅仅只是将某种解锁方式硬编码在Layer1.5应用的合约里,则使用起来会有很多不方便的地方,这个问题在RFC: Compact UDT Lock的设计中已经有所讨论。

6.4 通用Type接口

如果我们设计一个通用的Layer1.5,则状态转换也可以写合约定制化,逻辑类似Lock的定制化,通过这种模式我们可以实现更友好的OpenTransaction,一种综合UTXO和账户模型优点的Dapp开发模式,甚至将一个完整的图灵完备虚拟机也通过这种模式实现,如evm和wasm等。

如果我们可以开发一个Layer1.5 Dapp开发框架,将上述组件包含在内,那么Cell模型的Dapp开发和使用难度应该会下降很多。

7. idea示例

下面列举一些按理,以探讨Layer1.5开发的可能性。

7.1 跨链资产收款

以ETH->CKB跨链桥为例,跨链用户不可避免地需要购买一部分CKB用于状态存储,在CKB价格增长后,这将是一笔不可忽视的成本,也许我们可以设计一个compact Cell,其解锁逻辑为ETH解锁逻辑(毕竟是ETH跨链桥),每笔跨链资产都成为向量承诺里的一个叶子节点,从而避免令人误解的CKB占用问题,然后再通过跨Cell通信转移至其他应用或者Layer2使用跨链资产。

同时Deposit资产到Layer2也可以将资产归集到一个Cell中,以方便管理。

7.2 个人资产管理

某个用户可以将自己的资产全部塞进一个compact Cell以节省状态占用,同时不存在每一项的解锁逻辑,只存在完整的Cell的解锁逻辑。

7.3 资产交易

通过Layer1.5,在不用考虑状态争用与并发问题后,我们可以开发原生的交易平台,无论是订单簿或者AMM,我们可以使用它来交易sUDT或者DAS、mNFT等资产,同时免去了挂单所需的状态占用,在DAS交易平台和以前的GliaDex,都存在挂单要占用状态的问题,非常影响使用体验。

7.4 链游,加密地产等

其他脑洞,将向量承诺的每一个leaf作为某个链游的一块地皮,我们可以在里面写一定长度的数据(如32Byte),除了当地皮外还可以作为像素拼接画的像素拍卖等。通过Layer1.5,链游还可以开更多的脑洞。

4 Likes

使用nervosnetwork/sparse-merkle-tree作为向量承诺方案时,写了一个简单的Layer1.5转账应用,进行一些简单的性能测试。

account_count: 100000, update_count: 80
proof len:31202
keys len:2560
consume cycles: 29524322

100000个账号,四十笔一对一的交易,即更改80个leaf,验证的时候需要做两次SMT的proof验证(一次旧状态根,一次新状态根)。
Key的长度为2560byte(即80 * 32),Proof的长度为31202byte,验证消耗的Cycle为29524322,29524322 / 80 / 2 = 184527 Cycle,去除一些业务逻辑后,对每个leaf的平均验证成本在15w Cycle以下,每个leaf的平均证明字节为390Byte。
另外测试100000个账号,更新50个叶结点的验证性能。

account_count: 100000, update_count: 50
proof len:20812
keys len:1600
consume cycles: 19028139

可以看到每个leaf的平均验证成本和平均证明字节都高于上面的更新80个Key的测试,但是在尝试更新100个key的测试时,出现了内存超出CKB-VM限制的错误。

其他的向量承诺方案,如VerkleTree以及零知识证明化的MerkleTree还有待测试性能。

3 Likes