Substrate 合约书之合约模型

831 阅读10分钟

4.png

前言

「Substrate 合约书」用于介绍 Substrate 中与 Wasm 合约体系相关的一系列知识。本书由 Patract (patract.io/)主导编写,由 Aten (github.com/atenjin)负责。… github.com/patractlabs… new window),欢迎有志之士一起为本书做出贡献。

本书当前主要以 Pallet-Contracts (即 Wasm 合约)作为主体进行介绍。因此本书内容包含:

  • 运行合约的合约平台(模块)
    • Pallet-Contracts
  • 编写合约的语言
    • ink!
    • Ask!
    • Solang
  • 帮助合约开发的工具们
    • Redspot
    • Europa
    • Elara

其中由于 Pallet-EVM(即 EVM/Solidity 体系的合约)在以太坊生态中已有比较丰富的资料,故不会在本合约书中当做重点讲解。而另外的合约体系如 Pallet-Actor,或 Libra 移植合约平台等皆处于比较早期的研究阶段,因此也不会作为本书的重点。

为了让合约开发者更好的理解 Pallet-Contracts 模块与 Wasm 合约的运行方式,本书也会涉及一些 Wasm 的介绍以及区块链合约模型的介绍。

合约模型

在已经具备合约及合约沙盒的概念后,我们就可以开始讨论合约模型的概念了。

合约沙盒只是代表运行合约的环境,而合约是以什么方式运行的,合约和合约是怎么交互的,合约是怎么与链的数据互动的,这些问题就归属于合约模型问题。

换句话说,合约模型就是合约是以什么模型运行在合约沙盒/虚拟机中的。

WechatIMG603.jpeg

如图所示,合约模型与合约虚拟机本质上是可以解耦的,其中关系只存在合约虚拟机是否能支持上层所需要的合约模型,例如:

1.Bitcoin 的虚拟机就是比特币脚本的栈执行器,由于执行器设计是非图灵完备的OP_CODE,因此对于上层的合约模型只能支持 Bitcoin 的脚本。

2.Ethereum 跟随 Bitcoin 的灵感,设计了具备图灵完备的 OP_CODE,即 EVM 虚拟机(Ethereum Virtual Machine)。但是 EVM 的 OP_CODE 比较简陋,且只有栈的设计,没有堆的概念。但是 EVM 引入了读写状态的OP_CODE,因此从虚拟机机制上对合约模型可以支持状态模型。因此EVM也被看做一个执行状态转换的状态转换机(如 Gavin Wood 撰写的以太坊黄皮书中所描述的)。

状态模型实际上是比较通用的抽象模型,绝大多数模型都可以用状态模型模拟(如在状态模型中构建 UTXO 模型),因此从理论上来说,只要继续完善 EVM 的 OP_CODE,EVM 的上层同样可以构建出其他合约模型。

3.Libra 认为区块链的核心在于资产的处理,因此提出了 Move 的虚拟机模型(Move Virtual Machine )来从虚拟机上限定合约的模型,可以理解为是一种特化逻辑过的 OP_CODE 集合。因此 MVM 的上层只能运行Move 模型。

通过以上讨论,我们可以认识到合约模型的概念,并且理解到虚拟机对上层合约模型的限制,因此接下来就可以讨论Wasm虚拟机可以运行的合约模型以及Pallet-Contracts 的合约模型构成。

Wasm 虚拟机

Wasm 是一种在基于栈的虚拟机上运行的二进制的指令格式(WebAssembly<abbreviated Wasm)>is a binary instruction format for a stack-based virtual machine, from webassembly.org/)。

因此 Wasm 的模型和主流计算机程序的模型结构比较相似。另一方面 Wasm 被设计成为了一种比较通用的形式,且设计了 WASI 并支持了运行环境自由定义 Host Function,因此虽然 Wasm 从浏览器发展而来,但是当前的使用场景已经不限于浏览器,开始在边缘计算,热更新,Serverless 平台等发挥效果。

若以指令的完备性来衡量一个虚拟机的能力,则 EVM 处于半成品的程度,限制多且不够灵活;而 JVM,Wasm 虚拟机则是比较完备的,限制少,功能性强。另一方面指令设计的合理性一定程度也会影响虚拟机的执行效率,同时虚拟机采用的实现方案也会对执行效率产生比较大的影响。

例如EVM当前只能以解释器(Interpreter)的形式运行,并且当前的实现过程体(Go, C++等版本)中没有看到针对解释器的优化,执行效率比较底下,而 JVM, Wasm 等虚拟机有采用 JIT 的模式的实现,执行效率相当高甚至逼近本地执行的性能。

注:Pallet-Contracts 当前只能使用 Wasmi(解释器)执行 Wasm 代码,因此合约的执行性能比不上使用 Wasmtime 的 Runtime 的执行性能。

而同时,Wasm 虚拟机相比于 JVM 等虚拟机,十分轻便(LightWeight),快速,可定制性强,且 Host Function 的功能给予了 Wasm 虚拟机与宿主之间交互的通道,因此和其他虚拟机相比,将 Wasm 虚拟机作为区块链合约沙盒与链的功能结合在一起比较容易。

另一方面在笔者看来,Wasm 是处于底层代码与上层代码之间比较好的一个抽象层,且其复杂性与完备性也远超于 EVM,因此比较适合区块链合约领域的需求。

因此 Wasm 虚拟机提供的沙盒环境在满足合约沙盒的前提下还满足以下2点要求:

指令完备,功能性丰富,执行效率高 有适合的接口能与宿主(这里指代运行 Wasm 的环境,即链)交互,方便宿主提供需要的功能。

EVM 的合约模型

由于 Ethereum 是存储状态的区块链,因此 EVM 的合约模型理所应当的需要基本读写状态的功能。如果把每次合约运行的过程看做一次程序的启动到执行结束的过程,那么状态数据的变化就对应着这个程序需要持久化数据的变化。 因此对于读写状态,以太坊的 EVM 提供了 SLOAD 和 SSTORE 两个指令。

另一方面以太坊描述一个账户使用了“账户模型”,即将合约和调用合约的用户都看做了一个账户,在这个账户下存在 Balance 等概念,因此 EVM 提供了CALLER,ORIGIN,CALLVALUE等等一系列指令来描述这种模型。

同时由于在 EVM 的抽象体系中,认为合约与用户是一致的,因此出现了“合约调用合约”的模型,即 CALL,DELEGATECALL 等指令,由此带来了合约的可组合性,造就了 Ethereum 繁荣的生态。而在 EVM 中,一个合约依托于一个 EVM 进行运行,因此合约调用合约是在一个 EVM 中启动了另一个 EVM 并加载指令进行执行。

当然 EVM 虚拟机设计的初衷就是为了解决比特币脚本的非图灵完备问题,为了解决这个问题并保证停机问题不发生,引入了指令的 Gas 计费模型 因此总结以上可以得到,EVM 的合约模型具备以下特性:

1.处理数据的模型是状态机模型,状态的变更靠外界调用触发(类比于调用了状态变更函数的过程); 2.合约模型中需要链相关的特性; 3.将合约与用户看做一致,允许合约调用合约; 4.引入指令计费模型。

Pallet-Contracts 的合约模型

这里直接下结论:Pallet-Contracts 虽然使用了 Wasm 虚拟机来执行代码,但是其合约模型基本与 EVM 合约模型一致。

也就是说 Pallet-Contracts 的合约模型同样具备以下4点特性:

处理数据的模型是状态机模型; 合约模型中需要链相关的特性; 将合约与用户看做一致,允许合约调用合约; 引入指令计费模型。

并且,在以上4种特性的基础上,增加了“存储租赁模型”:

  • Rent 存储租赁计费

在上文已经称述了合约执行的环境和合约模型是可以解耦的,EVM 由于设计的比较早还没有解耦这个层次的概念,因此在指令中 SLOAD,SSTORE 及类似和链相关的指令是与 EVM 其他指令合并一起的。而 Wasm 本来并非为区块链设计,因此一定不存在这些和链环境相关的指令。

因此 Wasm 的 Host Function 即是用来完成这件事情的。链作为 Host 宿主,只需要把他认为合约可能会用到的方法提供给 Wasm 虚拟机,让他导入这些函数对象,在合约的执行过程中即可以使用。因此通过 Host Function,Pallet-Contracts 合约模块就可以具备1,2,4功能,并将提供3需要的部分功能,同时第5点特性(租赁计费)也可以引入。

并且其中第3点功能的实现方式也与 EVM 一致,当出现合约调用合约的部分时,通过 Host Function 从 Wasm 回到了 Pallet-Contracts 模块,并启动了一个新的 Wasm 虚拟机去执行被调用的合约。(该部分在以后的文章中会描述)

因此总结而言,Pallet-Contracts 的合约模型具备如下特性:

1.合约模型与 EVM 的合约模型一致,并在此基础上增加了存储计费模型 2.与链交互的实现通过 Wasm 的 Host Function 特性实现

使用 Wasm 虚拟机实现其他合约模型

刚才简要描述了 Pallet-Contracts 是如何在 Wasm 虚拟机上实现合约模型的,由于前文已经解释了虚拟机与合约模型是可以解耦的,因此实际上在 Wasm 虚拟机上同样可以实现其他的合约模型。

例如我们可以考虑将 Move 虚拟机也移植到 Wasm 虚拟机中,其有两种可能的实现方式:

1.类比于将 EVM 的实现体在 Runtime 的 Wasm 环境运行,可以将 MVM 的实现体也编译成Wasm的形式(例如命名为 Pallet-MVM),在 Runtime Wasm 中运行。

基于这种实现,Move 依然可以按正常方式编译,并和Solidity的编译结果运行于 Pallet-EVM 一致,将 Move 的编译结果运行在例如 Pallet-MVM 的平台上。

2.将 MVM 与所有权,链相关的特性抽象一层,做成和 Pallet-Contracts 的形式,并设计将 Move 语言编译的中间码 IR 编译到 Wasm。

基于这种实现,可以将 Move 编译成为 Wasm,并在 Wasm 虚拟机中运行。

其他合约模型

EOS 的合约模型

EOS 的合约模型与 EVM 类似,同时强化了账户模型的概念。因此 EOS 使用 Wasm 的方式也是基于 Wasm 的执行,并通过 Host Function 引入与链相关的功能。

EOS和EVM模型的主要区别在于,EOS 的合约调用合约的过程是以发交易的形态调用,并且 EOS 的资源模型是抵押模型。当前普遍认为正是 EOS 的抵押模型最后导致 EOS 没有走向成功。

异步合约模型

pallet-actor是 Substrate 尝试实现异步合约模型的一个开端,当前没有什么进展。pallet-actor 的模型打算使用Wasm虚拟机作为运行环境,并在此基础上添加异步的功能以提升性能。

当前也有其他少数对异步合约模型的研究,但是皆处于比较初步的阶段。

About Patract

Patract 为 Wasm 合约生态的开发提供解决方案。我们帮助开发链上合约模块和 Runtime 支持,并且为开发者提供覆盖开发、测试、调试、部署、监控、数据提供和前端开发等阶段的全栈工具和服务支持。

How to join Patract

对于开发者,可以访问官网 (patract.io),熟悉测试链和工具套件。欢迎加入官方开发群: Element (app.element.io/#/room/#Pat… Discord(discord.gg/wJ8TnTfjcq)