由于当前智能合约多为串行执行和串行验证,导致性能一般,无法满足业务需求。百度超级链提出了一种新的区块链数据模型: XuperModel。基于这样的底层数据模型,XuperChain可以使用多核计算能力来同时执行和验证智能合约,大大提升效率。
本期超级链学院微课堂的主题就是“为你揭开智能合约的高并发面纱——XuperModel”!明星讲师超哥先来为你划重点啦,本次课程会讲清楚以下几点:
1. 底层的数据模型对于区块链系统的重要性
2. 超级链独创数据模型——XuperModel详解
3. 智能合约的性能瓶颈问题超级链如何解决
4. XuperModel与其他数据模型的异同点
5. XuperModel为开发者提供了哪些能力
快来继续往下看吧!
Q1:数据模型对一个区块链系统而言重要么?
非常重要。数据模型体现了一个区块链系统对数据的组织方式,属于核心设计,是其区别于其他系统的重要特征。例如,比特币的UTXO,以太坊的MPT,HyperLedger Fabric的读写集,都是大家所熟知的区块链数据模型。
Q2:超级链的数据模型是什么?
超级链的数据模型是XuperModel,是基于UTXO模型进一步泛化、抽象而来的一种通用数据模型。经典的UTXO模型只能描述数字资产的转移,而XuperModel可以描述由智能合约执行而引起的数据变更, 同时又没有牺牲掉UTXO并发性能好的优点。
Q3: XuperModel和UTXO相比,相同点和不同点是什么?
相同点是每笔交易都会引用和它相关的之前发生的交易。只不过,UTXO模型中,交易的引用关系表明了资金的来源,而XuperModel中存在两种引用关系:一种是表述数字资产的来源,另一种是表述数据的版本依赖关系。两种引用关系分别用TxInput和TxInputExt两个字段来表示。当交易中只存在数字资产转移时,XuperModel就退化为UTXO模型。
Q4: 如何知道智能合约执行依赖的数据版本呢?
在超级链中通过预执行来确定智能合约依赖的数据版本。在预执行阶段,超级链内核会为每个智能合约的请求构造一个“沙箱”环境,其发起的读取和写入请求都会被内核捕获,从而可以记录到它读取的数据的版本和即将写入的数据内容。
Q5: 其他节点如何验证智能合约的正确性呢?
每个交易都是自描述的,其他节点可以根据交易中的引用信息复原智能合约的“沙箱”环境,复原的过程中需要检测其依赖的资产来源和数据版本是否仍然有效。如果是过期的版本,或者资产已经被其他交易使用,那么复原沙箱失败。如果复原环境成功,接下来就会调用虚拟机去执行这个合约,执行合约的过程是Lock-Free的,因此并发性能好。最后,在内核数据生效时,会Double-Check引用关系的有效性,最终生效到状态机里面。
Q6: 那么各个节点如何最终达成一致的状态呢?
主要是解决判断冲突的问题。大家应该都用过git,当我们运行git pull的时候,经常会发生你的本地内容和他人冲突,而需要手动介入解决冲突。XuperModel的原理很类似,数据的唯一标识是Bucket + Key, 其中Bucket对应合约名字,Key对应存取的变量名。如果多个交易都修改了同一个数据,且他们不存在父子引用的话,那么就是互相冲突的。在XuperModel中,区块中的交易拥有更高优先权,可以回滚掉和它冲突的未确认交易。
Q7: 超级链中的数据底层是怎么存储的呢?底层有两个DB,一个DB记录了账本,另一个DB维护着状态机。数据每个版本的变更的详细内容都是记录在账本中的,状态机中只是为每个变量存储了一个Hash指针,这个Hash指针可以定位到账本中的某个交易的某项输出,体现的是这个变量的最新内容。
Q8: 这种模型是支持多版本的么?
是的。默认情况下状态机中的变量的Hash指针式指向最新版本的,通过交易的TxInputExt字段,可以往前回溯到更早的版本。这种多版本机制的优势是对迭代查询、区间查询也很友好,可以避免因遍历无效版本而产生的IO开销。同时,超级链节点也提供了账本对齐的功能,类似于“git checkout”, 可以切换到历史上任意区块对应的状态。
Q9: XuperModel和Fabric的数据模型有什么异同?
首先,Fabric的数据模型是不内置数字资产转移的描述的, 而XuperModel则是UTXO模型的泛化,天然支持了数字资产转移的场景。其次,Fabric的数据模型中,数据的版本是绑定到区块高度的,因此对同一个Key的多次修改不能发生在一个区块,就导致他不能实现“Read Your Own Update”的场景。XuperModel中数据的版本是直接引用前置交易的,因此可以立即生效,在同一个区块中可以打包相关联的对同一个数据的一系列修改行为。
Q10: 对于应用开发者而言,基于XuperModel可以获得哪些能力?
首先,获得了天然的数据回溯能力。智能合约中的变量会随着合约的调用不断地发生变更,由于XuperModel维护了每次变更的前一个版本的哈希指针,可以顺藤摸瓜得到之前这个合约变量的所有版本。例如,我们之前曾经有篇小短文介绍了如何用200行智能合约代码实现一个可回溯的文件系统:
https://mp.weixin.qq.com/s/8CWKX92WRkeG6MMXkPZmVQ。其次, XuperModel 解耦了智能合约的计算和存储,使得智能合约的执行可以利用上CPU多核的算力,提升整体的性能。
分享结束后,群里也涌现出了一些精彩问题,摘取部分分享给各位。
问:「 请问XuperModel和超级链说的DAG有什么关系?」
答:DAG是有向无环图,是多个交易根据依赖关系构成的。那么,如何构建这种依赖关系呢?就需要借助XuperModel的能力为智能合约执行构造一个沙箱,为其捕获到依赖关系,最终把这些交易串起来,形成DAG。
问:「XuperModel是每个节点一直维持着一张大图还是每个交易都需要回溯?如果是前者,那账本大了之后新节点加入需要花费很大时间,而且账本大了这个表会很占内存,该如何解决?」
答:在超级链里面,要想构造交易,需要先“预执行”,预执行就锚定了交易依赖的数据版本,开销相当于在DB中的随机查(点查)。状态机DB默认是leveldb,不需要长驻内存。
问:「那是每个交易数据之中就写好了前向的交易,需要预执行的时候进行递归搜索,还是在leveldb中专门维持了一种联系表?」
答:前半句对。交易的TxInputExt是这样的:(ref_txid, ref_offset), 根据ref_txid可以反查到账本中的这个被依赖的交易内容,通过ref_offset可以拿到这个交易的TxOutput[ref_offset]这条数据内容。因此不需要遍历。
问:「 两个DB如何保证事务 」
答:超级链中,一个DB是账本,相当于binlog, 一个DB是状态机,里面有个Hash指针指向最后一次执行成功的区块。状态生效的粒度是区块,通过Batch写保证原子性,只要当区块中的交易数据变更全部成功写入状态机后,这个Hash指针才会往后『滑动』。Hash指针本身也存储在状态DB中,随同一个Batch刷下去。
问:「 智能交通业务中,节点的数据是否可以漂移在各共识节点?如果是秒级业务又该如何解决?」
答:数据的传播通路有两个:交易的广播和区块的广播。
区块的广播是线性的,交易的广播是乱序的。因此,可能出现交易对象构造的交易依赖了一个对方节点还没同步到的版本。但是,每个节点都会有例程广播自己本地未确认的交易。
如果是秒级业务的话,就要看交易依赖的数据量有多大了,还有网络的带宽是公网环节还是内网环境。在超级链中,首先是交易广播先行(尽最大努力、立即广播),然后是区块作为定序后的兜底,确保数据的最终一致性。
问:「使用UTXO数据模型,当区块数据很多的时候,查找某个区块中的交易ID所对应的时间消耗就比较大,需要遍历每个区块,效率低,那么百度超级链,在交易信息查询方面做了哪些优化?」
答:在超级链是这样存储的:
Block Namespace:
blockid ->. (block header, txid[N])
Tx Namespace:
txid -> (blockid, tx content....)
因此,查一个交易,不用遍历区块,而是一次『点查』。
原文链接:https://xuperchain.baidu.com/n/news/c47f6c7624b6334c67817ac9929c248a