Nervos 底层公链 CKB 的虚拟机(CKB-VM)是基于 RISC-V 打造的区块链虚拟机。在《CKB-VM 诞生前记》和《CKB-VM 诞生记(一)》中,我们介绍了 CKB 虚拟机的设计理念,以及基于 RISC-V 指令集打造的选择逻辑。
那么再往前推一步,我们为什么会选择基于真实 CPU 指令集来构建 CKB-VM 呢?在本篇文章中,CKB-VM 设计者肖雪洁将和我们继续讨论 CKB-VM 的设计灵感、设计以及基于真实 CPU 指令集来构建 CKB-VM 的额外优势。
灵感与设计
在设计 CKB-VM 之前,我们发现很多区块链项目并不是用真实的 CPU 指令集来构造自己的虚拟机。我们熟知的以太坊下一代虚拟机 EWASM、EOS 以及 Dfinity 等都选择了 WASM(WebAssembly,一种编码格式)来构造自己的虚拟机。我们也完全可以设计出一个具有高级语言特性的 VM,比如可以用于静态验证,或是可以直接支持高级数据结构,或是支持各种加密算法的 VM。
但是我们发现,虽然带有高级语言特性的虚拟机能够提供更多的便利,比如能够支持语法各异的编程语言,但同时也会出现其他一些问题:任何复杂的、带有高级语言功能的 VM,无论多么灵活,都不可避免的会在设计层面引入一些语义约束,出于性能的原因,不同的语言在底层几乎需要共享相同的语义(带有高级语言特性的虚拟机需要绑定密码学原语,若未来现有的原语被攻破,或者需要更换一套密码学原语时,需要通过分叉来实现)。这样一来, VM 自身的灵活性就会受到限制,这和 CKB 作为加密经济底层基础设施的愿景并不相符。
与此同时,一个带有高级语言功能的 VM 通常会包含某些高级的数据结构与算法,这样任何在 VM 中嵌入的高级数据结构与算法都可能只适合于某一类应用的开发,却不适用于其它应用程序的开发。并且,我们无法预设所有可能的使用方式,这些嵌入 VM 本身的数据结构或算法除了兼容性之外没有任何作用,随着时间的推移,甚至会成为负担。
另外我们还发现,所有的区块链项目都要在冯·诺伊曼 CPU 架构(x86,x86_64,ARM 等架构)下才能运行,并且所有高级的 VM 特性都必须映射到现代体系架构的 CPU 汇编指令。
举个例子,虽然 V8 引擎(由 Google 开发的开源 JavaScript 引擎,用于 Google Chrome 及 Chromium 中)看上去可以有无限量的内存,但是其内部实现依然需要依靠一个十分复杂的垃圾回收算法,才能在有限的内存空间中模拟出无限的内存空间。
类似的,Haskell (一种标准化的,通用的纯函数编程语言)或是 Idris(一个通用的依赖类型纯函数式编程语言) 可能具有先进的静态类型检查模式(在某种程度上)来证明软件运行的正确性,但在完成类型检查之后,还是需要通过一个翻译层把静态验证后的代码转换成未验证的原生 x86_64 汇编指令。
这里的关键在于无论我们如何设计 VM,都没有办法太过偏离当前的体系结构。换句话说,在任何 VM 的最底层,都需要将操作转变成原始的汇编指令来执行。
于是我们想: 为什么不使用符合 CKB 虚拟机当前系统架构的真实 CPU 指令集来构建自己的虚拟机?
这样一来,我们不会丢失任何添加静态验证、高级数据结构、或是加密算法的可能性,并且无论我们在 VM 中提供怎样的数据结构或算法,都可以 最大化 VM 的灵活性 。此外,通过真实的 CPU 指令集,我们可以最大限度的让开发者写出任何满足要求的合约。
额外的优势
除了 灵活性 之外,基于真实 CPU 指令集的 VM 还有其它额外的优势:
• 稳定性
为硬件设计的 CPU 指令集一旦最终确定并在芯片中使用,就难以修改,所以与通常是软件实现的 VM 指令集相比,硬件指令集显得非常稳定。这个属性与 Layer 1 区块链 VM 的诉求非常契合,因为稳定的指令集意味着较少的硬分叉,且不会牺牲灵活性。
• 运行期透明性
物理 CPU 在运行时仅需要依靠寄存器和一段内存,在使用堆栈的操作过程中,通常内存中的空间是指定的。这样一来,我们可以在程序执行期间根据 VM 中的堆栈指针来获取堆栈空间的使用情况,从而最大限度地提高运行时状态的可见性。
CKB-VM 可以调整堆栈指针、更改内存中的区域分配,甚至根据需要扩大或缩小堆栈区域大小,从而提高 VM 的灵活性。当前 CPU 指令集还可以提供过去周期的计数,从而允许查询 VM 的运行开销状态。
• 运行期开销
具有真实 CPU 指令集的 VM 可以轻松管理运行期的开销,每个指令执行时所需的 cycle 数(不考虑流水线)是固定的。 我们可以根据真实 CPU 指令集的这个特性来设计 CKB-VM 运行时的开销计算机制,这样一来,当我们应用新算法时,也可以准确地计算出所需的开销。
但是,与通过操作码或本机 VM 指令集实现加密算法的 VM 相比,使用真实 CPU 指令集存在一个关键的缺点: 性能 。
不过,根据研究和测试结果,我们可以通过适当的优化和即时(Just-In-Time,JIT)编译器实现来优化基于真实 CPU 指令集在 VM 上运行的加密算法,从而满足 CKB 应用程序的需求。在处理即时性时,我们是基于底层指令集进行处理,而不是基于像 JavaScript 这样的高级语言上处理,这样会使得 VM 具备更低的工作负载和更好的性能。
Why Not WASM?
也许有人会问:在区块链社区对 WebAssembly 有着强烈兴趣和广泛关注的情况下, CKB 为什么不直接使用 WebAssembly 呢?
WebAssembly 是一个伟大的项目,并且我们非常希望它最后能够成功。一个拥有广泛支持的沙盒环境,对于整个区块链行业,甚至整个软件业来说都是件梦寐以求的事。从长远来看,WebAssembly 也有潜力实现 CKB 所需的大部分特性,但是它并不能提供我们在《CKB-VM 诞生记(一)》中提到的 RISC-V 能为 CKB-VM 带来的所有好处,比如,目前 WebAssembly 还全都是 JIT 实现,缺少一个合理的运行期开销计算模型。
另外,RISC-V 从 2010 年开始设计,在 2011 年发布第一版规范,2012 年出现基于 RISC-V 构建的硬件;而 WebAssembly 出现于 2015 年,2017 年发布 MVP,相对来说,RISC-V 会比 WebAssembly 更加的成熟,所以至少在目前阶段,我们觉得使用 WebAssembly 并不是 CKB-VM 最好的选择。
当然,我们并不是完全放弃使用 WebAssembly,考虑到 WebAssembly 与 RISC-V 同样是底层 VM 的实现方式,而且很多设计和指令集十分相似, 我们完全有可能提供一个从 WebAssembly 到 RISC-V 的二进制转换器,从而确保 CKB 也可以利用目前区块链上基于 WebAssembly 的创新。 另外,CKB 上也能够支持仅可以编译为 WebAssembly 的语言(比如 Forest:GitHub - forest-lang/forest-compiler: A multi-syntax functional programming language that compiles to WebAssembly. )。
社区驱动的 CKB-VM
通过 CKB-VM 的设计,我们的目标是建立一个围绕 CKB 的社区,该社区可以自由地发展和适应新技术的进步,并且可以最大限度地减少人工干预(例如硬分叉)。 我们相信 CKB-VM 可以实现这一愿景。
注: CKB-VM 与 CKB 一样为开源项目,目前 CKB-VM 仍在开发过程中,尽管 CKB-VM 的大部分设计已经敲定,但某些设计也可能会在将来,因为你的贡献而有新的变动和推进。这篇文章是为了让我们的社区更加了解 CKB-VM,这样人人都可以在里面更好的玩耍并做出贡献啦!
CKB-VM:GitHub - nervosnetwork/ckb-vm: CKB's vm, based on open source RISC-V ISA
作者:肖雪洁
翻译:Kelly,校对:Ryan