这是Nervos 系列的第二篇。上一篇文章中,一休哥概要性地介绍了Nervos 。首先回顾一下之前我们得到的结论:Nervos Network通过分层架构的设计,将状态生成和状态验证/存储进行分离,来解决区块链的可扩展性问题,破解“不可能三角”难题。
一休哥认为,Nervos项目具有“圣杯”特质。我是如何得到这个的结论的?
这是一个拆解分析的过程,需要一些专业知识储备。我希望通过这个系列,能帮助大家在分析各类项目时打开一些思路。
今天我为大家拆解Nervos内的Cell模型设计,它如何实现可扩展性的,为了方便阅读,我们做如下约定:本文内的Nervos与CKB意思保持一致。通过阅读本文,你将对以下内容有直观印象:
1、CKB的结构是什么样子?
2、CKB里的最小元素Cell模型是什么样子的?
3、为什么Cell模型是比特币UTXO模型的泛化版?
4、我通过一个生活中的案例,来让你对Cell模型有更直观的体会,加深印象。
1. CKB的结构
上图是 CKB 的结构图,CKB中主要有四种主要的数据结构:
- Cell(细胞,最小单元)
- Transaction(事务、交易)
- Script(脚本)
- Block(区块)
CKB链上,依然是由很多Block区块链接组成一条长链,一个区块又是由多个Transaction交易构成,而每条交易本身是Cell的创建和销毁的过程。
Cell是CKB上最小的资产单元,用于存储用户有价值的信息。接下来我们来看这个Cell模型。
2. Cell是比特币UTXO模型的泛化通用版
2.1 比特币的UTXO模型
了解比特币的朋友知道,比特币把整个账本分割保存在了一个个UTXO里面,UTXO是未花费交易输出(Unspent Transaction Output)的简写,实际上是交易中包含的输出(CTxOut)。CTxOut的结构非常非常的简单,只有两个字段:
class CTxOut
{
public:
CAmount nValue;
CScript scriptPubKey;
...
}
每一个CTxOut代表了一个面值不同的硬币(Yay bit-”Coin”),其中nValue代表这个硬币的面值是多少,scriptPubKey是一段表示这个硬币的所有者是谁的脚本(通常为所有者的公钥),只有能提供正确的参数使这个脚本运行成功的人,才能把这个硬币“转让”给另外一个人。
在UTXO模型中,保存的数据仅仅是原生币(BTC)的数量(nValue),我们不能在BitCoin的UTXO中存储ETH,这就是为什么我们不能直接将ETH转入一个BTC地址。
CKB的Cell模型
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中的状态。
以上都是偏技术的解释,下面我用一个生活中的案例来讲,也许大家对Cell模型就能有直观的印象。
3. Cell就像是一个寄存柜
想象一个大型超市门前的寄存柜,我们去逛超市时,随身带着一些东西,不方便,寄存柜就是用来临时存放我们物品的地方。
每个寄存柜都由一个储物空间,其有自己的容量( Capacity ),它在出厂的时候就已经被设定的,我们假定每个储物柜的存储容量不一样( CKB 里面每个Cell的空间容量均可以不一样)。
每个寄存柜里面,可以放置任何有价值的东西(data),可以放一个书包、矿泉水、面包等等,只要存放的东西不超过柜子的容量( Capacity);并且,每个寄存柜的东西(data)是相互独立的,用户可以自己管理它。同理, CKB 的 Cell 里面,也可以存放任何有价值的信息,比如UDT
(User Defined Token
)。同一个Token,不同的持有者,他们的Cell不同,实现不同用户的资产隔离,用户可以自己管理和支配其拥有的Token。这与以太坊的ERC20不同,ERC20的Token是在一个智能合约里面维护的,智能合约内,通过一个列表,记录该ERC20 Token的持有者,以及每个持有者的账面余额。
我们现在要存包,按下“存包”按钮,系统会自动发出广播,这个type(存包脚本,或者存包程序),第一个做出应答的空柜子,执行预先设定好的type(存包脚本,或存包程序),自动打开柜门,与此同时,生成一张条形码凭证(lock),该凭证记录着这个柜子所有权的验证规则。此时我们将物品放入储物柜中,将柜门关闭,完成存包的过程。与此同时,这个柜子的状态,被标记为“已使用”,除了拥有条形码凭证(lock)的我之外,其他人都无法打开这个柜子。
当我们逛完超市出来,要进行取包操作,我们拿着条形码凭证(lock),在相应的机柜面前扫码,程序根据预置的验证规则,打开正确的柜子。如果拿着一张过期、已经扫过的条形码去验证,则系统认为是无效的请求,不会再次打开柜门,它不会出现“双花”的现象。当完成取包,关闭柜门时,这个柜子的状态,被标记为“可使用”状态,其他人才可以使用这个柜子。
在CKB里,type脚本在验证交易输出的时候执行,确保用户生成的新状态符合类型约束,正确生成了新的Cells。正如上面示例中存包时必须要打开空的柜门,如果存包时打开了一个别人的柜门,那是件非常危险的事情。因此这里必须的约束条件是:1、空箱;2、生成这个与该空箱对应的条形验证码,以确保能够验证取包。Cell模型数据结构里面,type就是用来决定这些约束条件的脚本。
在CKB里,lock脚本在验证交易输入的时候执行,确保用户对输入有所有权,有权销毁输入的Cells,正如上面示例中取包时验证我手里的条形码是否有效,是否能打开对应的柜子。这里所有权验证规则(lock)的条件有:1、是否已验证过;2、是否对应的橱柜处于“使用中”的状态。
当我完成了取包之后,这个柜子状态由“已使用”变为“未使用”,对应到Cell的销毁中来,Cell的销毁只是把它标记为”已销毁“,类似Bitcoin的UTXO从未花费变为已花费,并不是从区块链上删掉。
上面这个示例中,存包和取包就是两个交易事务(Transaction),如果这个寄存柜有记录历史事务的功能,那么多条存取包事务就可以组成一个区块(Block),多个区块(Block)首尾连接起来,就形成一个下图上面部分的链式结构:
CKB底层的共识机制和BitCoin一样,是POW方式,POW共识已经在Bitcoin上安全稳定地运行了超过十年之久,CKB的Layer 1层主要解决数据的安全性和去中心化,使用比较安全稳定的POW共识,有助于加速系统的利用。之后我还会在这个系列中的【CKB通证经济】篇为大家分享。
最后小结一下,CKB中主要有四种主要的数据结构:
- Cell(细胞,最小单元)
- Transaction(事务、交易)
- Script(脚本)
- Block(区块)
Cell是CKB的最小数据存储单元,CKB从Bitcoin里面的UTXO模型中得到启发,设计出泛化的、具有可扩展性的Cell模型,该模型特别像超市门前的寄存柜,最后我们通过寄存柜的业务实现,来加深对Cell模型的理解。
参考:理解CKB的Cell模型