为了理解底层公链 CKB 的 Cell 模型,咱们前置了几篇概念性文章,讲述了咱们应该 以状态为中心设计区块链系统的,以及这么作带来的好处。而且在上一篇文章中,详细分析了 比特币 UTXO 模型和以太坊的 Account 模型,以及进行了对比分析。终于,咱们要来了解集大成者 Cell 模型了。(前排提示:一遍看不懂不要紧,多看几遍就懂了)
秘猿科技区块链小课堂第 18 期android
在设计 CKB 的时候,咱们想要解决三个方面的问题:编程
对这些问题没有答案,Layer 1 就没法长久运行,区块链给咱们的种种承诺天然也是无从谈起。这三个问题根植于区块链架构和协议设计的最深处,很难经过打补丁的方式来解决,咱们必须从最基本的数据结构开始,从新审视问题的根源,寻找更合适的地基。segmentfault
幸运的是,这个更合适的地基简单得使人感到幸福,并且一直就摆在咱们眼前。(本文会包含一些很是简单的代码,应该不会影响非技术读者阅读……)安全
Bitcoin 把整个帐本分割保存在了一个个 UTXO 里面,UTXO 是未花费交易输出(Unspent Transaction Output)的简写,其实是交易中包含的输出(CTxOut)。CTxOut 的结构很是简单,只有两个字段:cookie
class CTxOut { public: CAmount nValue; CScript scriptPubKey; ... }
每个 CTxOut 表明了一个面值不一样的硬币(Yay bit-“Coin”),其中 nValue表明这个硬币的面值是多少,scriptPubKey 是一段表示这个硬币全部者是谁的脚本(一般包含了全部者的公钥),只有能提供正确参数使这个脚本运行成功的人才能把这个硬币「转让」给另一我的。网络
为何要给「转让」打引号?由于在转让的时候,并非简单地把硬币中的 scriptPubKey 修改或是替换掉,而是会销毁和创造新的硬币(毕竟在数字的世界中销毁和创造虚拟硬币的成本很低)。每个 Bitcoin 交易,都会销毁一批硬币,同时又创造一批硬币,新创造的硬币会有新的面值和新的全部者,可是被销毁的总面值老是大于等于新创造的总面值,以保证没有人能够随意增发。交易表示的是帐本状态的变化。数据结构
这样一个模型的特色是:架构
是否是很简单?若是你以为本身已经理解了 Bitcoin 和 UTXO ,恭喜你,你也已经理解了CKB 和 Cell!分布式
Layer 1 的关注点在状态,以 Layer 1 为设计目标的 CKB 设计的关注点很天然就是状态。Ethereum 将交易历史和状态历史分为两个维度,区块和交易表达的是触发状态迁移的事件而不是状态自己,而 Bitcoin 协议中的交易和状态融合成了一个维度,交易即状态,状态即交易,正是一个以状态为核心的架构。工具
同时,CKB 想要验证和长久保存的状态,不只仅是简单的数字(nValue),而是任何人认为有价值的、通过共识的数据。显然 Bitcoin 的交易输出结构知足不了这个需求,可是它已经给了咱们足够的启发:只须要将 nValue 通常化,把它从一个存放整数的空间变成一个能够存听任意数据的空间,咱们就获得了一个更加通常化的「CTxOut」,或者叫 Cell:
pub struct CellOutput { pub capacity: Capacity, pub data: Vec<u8>, pub lock: Script, pub type_: Option<Script>, }
在 Cell 里面,nValue 变成了 capacity 和 data 两个字段,这两个字段共同表示一块存储空间,capacity 是一个整数,表示这块空间有多大(以字节数为单位),data 则是保存状态的地方,能够写入任意的一段字节;scriptPubKey 变成了 lock,只是换了一个名字而已,表达的是这块共识空间的全部者是谁 - 只有能提供参数(例如签名)使得 lock 脚本成功执行的人,才能「更新」这个 Cell 中的状态。整个 CellOutput 占用的字节数必须小于等于 capacity。
CKB 中存在着许许多多的 Cells,全部这些 Cell 的集合造成了 CKB 当前的完整状态,在 CKB 的当前状态中存储的是任意的共同知识,再也不仅仅是某一种数字货币。
交易依然表示状态的变化 / 迁移。状态的变化,或者说 Cell 内容的「更新」实际上也是经过销毁和建立来完成的(并非真的去修改原有 Cell 中的内容)。每一笔交易实际上都会销毁一批 Cells,同时建立一批新的 Cells;新创造的 Cells 会有新的全部者,也会存放新的数据,可是被销毁的 capacity 总和老是大于等于新建立的 capacity 总和,由此保证没有人能够随便增发 capacity。由于 capacity 能够转让,没法增发,拥有 capacity 等于拥有相应数量的共识状态空间,capacity 是 CKB 网络中的原生资产。Cell 的销毁只是把它标记为「已销毁」,相似 Bitcoin 的 UTXO 从未花费变为已花费,并非从区块链上删掉。每个 Cell 只能被销毁一次,就像每个 UTXO 只能被花费一次。
这样一个模型的特色是:
因此说,Cell 是 UTXO 的通常化(generalized)版本。
仅仅有一块能够保存任意状态的空间还不够。Bitcoin 之因此有价值,是由于网络中的全节点会对每一笔交易进行验证 ,使得全部用户都相信(而且知作别人也相信)Bitcoin 协议中写下的规则(例如 2100 万的上限)会获得保证。
共同知识之因此能成为共同知识,是由于每一个人都知道其余人承认这些知识 ,区块链之因此能让知识变成共同知识,是由于每一个人都知道其余人都能独立验证这些知识并由此产生承认。任何共识的过程都包含了一系列的验证以及相互之间的反复确认,这个过程正是网络中共同知识造成的过程。(须要注意的是,验证知识是相对事先肯定的验证规则来讲的,经过验证的知识不表明命题为真。)
咱们如何验证 Cell 中保存的数据呢?这时候就须要 Cell 中的另外一个字段 type 发挥做用了。type 与 lock 同样,也是一段脚本, type 定义了 data 字段中保存的数据在状态迁移过程当中必需要遵照的规则,是对状态的约束。CKB 网络在共识的过程当中,会在 CKB-VM 中执行 type 脚本,验证新生成的 Cell 中保存的状态符合 type 中预先定义好的规则。知足同一种 type 约束的全部 Cell,保存的是同一种类型的数据。
举个例子,假设咱们想定义一个叫作 SatoshiCoin 的代币(UDT,UserDefinedToken),它的状态迁移必须知足的约束是什么?只有两条:
用户必须证实本身是输入代币的全部者;
每一次转帐的时候,输入的代币数量必须大于等于输出的代币数量。
第一条约束能够经过 lock 脚原本表达,若是有兴趣能够查看这里的示例代码[1],与 Bitcoin 的 scriptPubKey 原理相同;第二条约束,在 Bitcoin 中是在底层硬编码实现的,在 CKB 中则是经过 type 脚原本实现。每一个 Cell 表明的 SatoshiCoin 数量是一种状态,咱们首先定义其状态结构,即每一个 type 等于 SatoshiCoin 的 Cell 在 data 保存的状态为一个长度为 8 的字节串,表明的是序列化事后的数量:
{ "amount": "Bytes[8]" // serialized integer }
type 脚本在执行中,须要读入交易中全部同类型的 Cells(根据 type 字段能够判断),而后检查同一类型下的输入 Cells 中保存的 amount 之和大于等于输出 Cells 中保存的 amount 之和 。因而经过 lock 和 type 两个脚本,咱们就实现了一个最简单的代币。
lock 和 type 脚本不只能够读取自身 Cell 中保存的状态,也可以引用和读取其它 Cell 中保存的状态,因此 CKB 的编程模型是一个有状态的编程模型。值得指出的是,Ethereum 的编程模型之因此强大,更可能是由于它有状态,而不是由于它的有限图灵完备。咱们能够把 type 脚本保存在一个独立的 Cell 里面,而后在每个 SatoshiCoin Cell 的 type 字段引用它,这样作的好处是相同的 type 脚本只须要一份空间保存,像这样保存数字资产定义的 Cell 咱们把它叫作 ADC(Asset Definition Cell)。
SatoshiCoin 的另外一个特色是,具体的资产与全部者之间的记录,分散保存在多个独立的 Cell 里面,这些 Cell 能够是开发者提供给用户的,也能够是用户本身拥有的,甚至是租来的。只有在共识空间全部权明确的状况下,全部者才能真正拥有共识空间里面保存的资产(任何数据都是资产)。在 CKB 上,由于用户能够真正拥有共识空间,因此用户能够真正拥有数字资产(当你能真正拥有土地的时候,才能真正拥有土地上的房子)。
Cell 是抽象的状态验证模型,Cell 提供的存储(data)没有任何内部结构,Cell 支持任意的状态验证规则(type)和全部权验证规则(lock),咱们能够在 Cell 模型上模拟 UTXO 模型(就像上面的 SatoshiCoin),也能够在 Cell 模型上构建 Account 模型。lock 脚本在验证交易输入的时候执行,确保用户对输入有全部权,有权销毁输入的 Cells;type 脚本在验证交易输出的时候执行,确保用户生成的新状态符合类型约束,正确生成了新的 Cells。因为状态模型迥异,以及计算和验证分离,CKB 的编程模型与 Ethereum 的编程模型有很是大的不一样,什么是 CKB 编程模型上的最佳实践还须要大量的探索。
Bitcoin 是一个验证网络(Verification Network)。在转帐时,用户告诉钱包/本地客户端转帐的数量和收款人,钱包根据用户提供的信息进行计算,在本地找出用户拥有的数量合适的硬币(UTXO),同时产生一批新的硬币,这些硬币有些归收款人全部,有些是找零。以后钱包将这些花费掉的硬币和新生成的硬币打包到一个交易里面,将交易广播,网络对交易验证后将交易打包到区块里面,交易完成。
在这个过程当中,网络中的节点并不关心老的状态(被销毁的硬币)是怎样被搜索出来的,也不关心新的状态(新硬币)是怎样生成出来的,只关心这些硬币的面值总和在交易先后没有改变。在转帐过程当中,计算在用户端完成,所以用户在交易发送时就能肯定计算结果(新状态)是什么。
Ethereum 是一个通用计算网络(General Computation Network)。在使用 DApp 的时候,用户告诉钱包/本地客户端想要进行的操做,钱包将用户的操做请求原样打包到交易里面,并将交易广播。网络节点收到交易以后,根据区块链的当前状态和交易包含的操做请求进行计算,生成新的状态。在这个过程当中,计算在远端完成,交易结果(新状态)只有在交易被打包到区块以后才能肯定,用户在交易发送的时候并不能彻底肯定计算结果。
(图中,上面是 Ethereum 的流程,交易中包含的是用户请求或者说事件/Event;下面是 Bitcoin/CKB 的流程,交易中包含的是链下生成的状态/State。)
CKB 是一个通用验证网络(General Verification Network)。在使用 DApp 的时候,用户告诉钱包/本地客户端想要进行的操做,钱包根据当前状态和用户的操做请求进行计算,生成新的状态。在这个过程当中,计算在用户端完成,计算结果(新状态)在交易发出的时候就已经肯定了。
换句话说,Bitcoin 和 CKB 都是先计算再共识,而 Ethereum 是先共识再计算。有趣的是,在许可链架构里面也有一样派别之分:Fabric 是先计算再共识,而 CITA(实际上不只仅是许可链)是先共识再计算。(思考题:哪种架构更适合许可链?)
计算与验证的分离同时也使得 Layer 2 与 Layer 1 天然分开了。Layer 1 关心的是新的状态是什么,并不关心新的状态是如何获得的。不管是 State channel,Plasma 仍是其余 Layer 2 方案,其实质都是在链外进行计算,在特定时候将最终状态提交到 Layer 1上进行验证。
如今咱们获得了一个很是不一样的基础数据结构,在这个结构之上咱们设计了独特的经济模型,这个结果然的更好吗?回顾一开始的三个问题也许能给咱们一些启示。
capacity 是原生资产,受到预先肯定的发行规则约束,其总量有限;
capacity 同时又是状态的度量,有多少 capacity ,CKB 上就能放多少数据,CKB 状态空间的最大值与 capacity 总量大小相等,CKB 上保存的状态不会超过 capacity 总量。
这两点决定了 CKB 不会有状态爆炸的问题。在 capacity 发行规则适当的状况下,网络应该能够长久的保持去中心化的状态。每个 Cell 都是独立状态,有明确的全部者,本来属于公共资源的状态空间被私有化,宝贵的共识空间能够被更有效的使用。
CKB 是一个通用验证网络,计算和验证获得了分离,各自的灵活性和扩展性都获得了提升。更多的计算被推到了用户端执行,计算发生在离场景和数据更近的地方,数据处理的方式更灵活,工具更多样。这也意味着,在 CKB 架构中,钱包是一个能作的事情更多,能力更大的入口。在验证端,因为计算结果已经彻底肯定,交易的依赖分析变得很是轻松,交易的并行处理也就更加容易。
在基于 Cell 创建的经济模型中,存储的使用成本与占用空间大小和占用时间成正比,矿工能够经过提供共识空间得到相应的收益。CKB 提供的 Utility 是安全的共识空间,价值来自于其安全性和可用性(accessability),并非来自于交易处理能力(TPS),与 Layer 2 负责交易的特色相辅相成,在分层网络和跨链网络中具备更好的价值捕获能力。
CKB 是一种存储这一点可能会令人感到迷惑:「这不就是 IPFS/Filecoin/(任何分布式存储)吗?」
CKB 不是分布式存储,关键的区别在于分布式存储只有存储,没有验证,也就不会对其存储的数据造成共识。分布式存储的容量能够随着存储技术的增加而等比例的增加,而 CKB 的容量则收到造成全球共识效率的限制。
CKB 也不须要担忧容量不够。在 Layer 2 以及分层技术成熟的阶段,极端状况下,Layer 1 上可能只须要放一个 merkle root 就足够了。在 Layer 1 上进行验证所须要的状态,也能够经过交易提交给节点,节点经过 merkle proof 验证状态是有效的,在此基础之上再验证状态迁移是有效的,这个方向已经有一些研究。
Qtum 是尝试在 UTXO 模型上引入更强大的智能合约的先行者之一,具体作法是保持 Bitcoin 原有的 UTXO 模型不变,在其上引入帐户抽象层(Account Abstraction Layer),支持 EVM 或是 x86 虚拟机。
在 Qtum 中,Bitcoin 的验证是第一层,EVM 的计算是第二层(注意这是一个区块连协议内部的分层,不是 Layer 1 和 Layer 2)。Qtum 对 UTXO 中 scriptPubKey 的处理逻辑进行修改,以实如今交易打包后,将 Bitcoin Transaction 中携带的请求传递给 EVM 进行执行的效果。
Qtum 将 Bitcoin 和 Ethereum 的执行模型桥接到了一块儿,网络节点先验证交易输入部分(同 Bitcoin),再调用合约进行计算(同 Ethereum),状态分散在 UTXO 模型和 EVM 本身的状态存储两个地方,总体架构比较复杂。
CKB 所作的是继承 Bitcoin 的架构思路,对 UTXO 模型进行通常化(Generalization)处理获得 Cell 模型,总体架构保持了一致性以及 Bitcoin 的简洁。CKB 上的全部状态都在 Cell 里面,计算在链下完成(相似 Bitcoin),网络节点只作验证。