智能合约的概念最早由 Nick Szabo 在 1996 年提出。但直到 2015 年以太坊平台出现才使得开发真正的智能合约成为现实。智能合约是一种自动执行的计算机应用程序,它执行合约时不需要来自第三方验证。这意味着交易双方不需要相互信任就能进行交易。这种新的开发环境催生了一种新型应用,即去中心化应用(dAPP),但给智能合约的开发者带来了一系列新的挑战。

与传统开发不同,去中心化的区块链环境里,所有节点都会运行程序,这时如果遇到死循环或者安全问题,就显得非常棘手。即便所有节点都同意回滚——这几乎不可能,也会造成巨大损失。如果部分节点没有回滚,那就会出现分叉。

Solidity 是现在区块链构建最常用的语言之一,它是由以太坊开发的面向对象的高级语言,其灵感来自 JavaScript、C++ 和 Python 等,因此在编程上提供了丰富的基础类型和复杂数据类型。并且引入了 Gas Fee 来避免死循环的出现,从而解决了停机问题。

Solidity 提供了一个强大的工具和生态系统,许多智能合约和去中心化应用都是用 Solidity 构建的,它们在以太坊网络上每天处理大量交易。但是Solidity 基于接口机制和动态调用在带来强大扩展性的同时,也带来很大的安全问题,诸如 DelegateCall 漏洞、无限增发等,引发了大量的攻击事件和漏洞。

近期 Diem 系新公链让人们重新注意到 Move 语言。Move 是由 Meta 开发的智能合约语言,早期用于支持 Libra(后改名为 Diem)项目。 Move 的设计和实现很大程度参考了 Rust,同样具有丰富的基础类型和数组。它还通过省略某些特性限制了语言的表达能力,比如动态调度和通用指针,基于 Ability+Resource 设计了一套资源管理特性,确保不可能在 Move 中出现复制或隐式丢弃任何资源。语言和 VM 层面的保障,大大降低了开发人员处理漏洞的代价和成本。

相比 Solidity,Move 最大三个优势是针对金融场景引入了面向资源编程,具有更高的安全性,增强了可组合性。

一、面向资源编程更适金融场景

Move 的核心特点是面向资源编程。这里的资源(Resource)来自于类似Rust 的所有权系统,灵感来源于线性类型(Linear Types)。

线性类型来自于线性逻辑,通常是为了表达资源转换的有效性。比如在经典的自动售货机例子中,普通逻辑针对一块钱可以买到一颗糖,会表达为最后买到了糖果的同时还保留了钱。造成 bug 的原因在于钱和糖果在这里属于资源类型,必须在所有状态变化中仔细计量而非自由支配。因此准确陈述应该是从一块钱和一块钱购买一颗糖的过程中,我们得到了一颗糖。

在编程环境中,内存管理并没有完全从程序员那里抽象独立出来,如果说代码中写了一个对象,那么该代码必须管理并释放分配给该对象的内存。所以资源可以作为一种新方法,用来跟踪某代码以管理某种数据结构或系统资源,从而在编程语言中直接表达所有权。

Move 可以定义自定义资源类型。比如将 Token 标记为 Resource 就是在告诉编程环境:这个数据结构代表了某 Token 的价值,与该数据结构进行交互的所有代码都需要遵循一系列特殊的规则,以维护该数据结构的价值。

这些规则如下:

每个 Resource 在某一时刻只能存在于一个地方。Resources 不能通过编程错误或恶意代码进行复制或意外删除。 Resource 的所有权由其存储位置决定。 只有所有者可以对 Resource 上的方法进行访问。

也就是说通过设定复制 ( copy )、可索引 ( key )、可丢弃 ( drop )、可储存 ( store )这四个属性避免资源变量被随意复制或修改。同时也可以根据属性方便的定义出任何类型的资源,从而确保该数据得到保护。

使用资源类型让智能合约尤其适用管理金融产品,既保证了所有权灵活性,也有强大的安全性(以太坊历史上最著名的智能合约 bug 就是由可重入性问题引起的)。

二、更高的安全性

Move 语言的安全性表现在三个方面:语言层面、虚拟机层面、工具层面。

语言层面

在一些中大型项目中,单个智能合约无法实现所有所需功能。因此通常采用动态方式调用,将代码按功能划分到不同的库(library)或者合约中,然后提供接口互相调用。

动态调用是一把双刃剑。在提供了灵活性的同时,也带来了挑战。比如在 Solidity 中,考虑代码复用,一般会将公共代码部署到一个 library 中。此时如果需要修改合约状态,就需要部署一个新的合约,这就涉及到合约调用合约的情况。开发人员需要考虑多种因素保障合约准确执行,还要避免循环调用可能出现的安全隐患(构造恶意合约),等于变相增加开发难度。

在 Move 语言中函数调用都是静态的。Move 的灵活性体现在支持 transaction scripts。每笔交易都包含一个脚本,包含任意代码,或者调用链上的其他 modules。module 声明了资源的类型和过程,也可以被其他的 module 进行调用。

虚拟机层面

Move 虚拟机有类似 Java 的字节码验证器。在合约运行前会进行校验,这个验证器可以检查出各种类型错误。在合约调用过程中合约的状态的安全性主要要通过编程语言内部的安全性进行隔离。

工具层面

形式化验证即将合约程序形式化为数学可验证的方式来验证安全有效性。Move 拥有团队自己开发的形式化验证工具—— Move Prover。它的基本思想是通过形式验证领域的自动定理证明求解器来验证程序是否符合某种规范。

总体而言,Move Prover 可以保护链上资产不受合约漏洞影响,同时面对监管机构审查与合规要求也有一定预测作用,让合约更加值得信赖。

三、基于模块的可组合性

智能合约可组合性对于构建高效的 Web3 生态有非常重要的意义。Move 语言的可组合性体现在模块(Module)上。对比 Solidity 生态下的合约可组合性,主要为依赖于类似远程调用下通过信息传递进行组合。

模块包含定义结构类型的库,以及对这些类型进行操作的函数。结构类型定义了 Move 的全局存储的模式,模块函数在其中定义了更新存储的规则。模块本身也被存储在全局存储中。所以在智能合约优化升级方面只需针对其组合的模块进行即可,加速合约的升级优化速度。

综合来看,作为 Diem 系新公链的核心资产,Move 语言的上述特点恰好是未来 Web3 生态建设中最迫切需要的。对于 NFT、GameFi 等新叙事会有重要影响。