深入解析以太坊虚拟机与 Ewasm 的未来发展

·

以太坊是一个内置图灵完备编程语言的区块链平台,任何人都可以通过以太坊智能合约创建去中心化应用程序。

“以太坊虚拟机(EVM)是处理智能合约部署和执行的核心组件”(Antonopoulos and Wood,2018)。

EVM 采用基于堆栈的架构。部署智能合约前,所有高级智能合约代码需首先编译为机器可读的字节码。EVM 通过后进先出(LIFO)机制处理字节码中的操作码序列,其运行逻辑类似于 Java 虚拟机(JVM)——每条指令以单字节操作码起始,后接参数(若有),数值按大端序排列(Scott,2009)。

本文旨在解析以太坊基于堆栈的 EVM 内部运行机制。了解这些基础知识后,我们将进一步探讨以太坊如何通过过渡到 WebAssembly(Wasm)实现更广阔的发展前景。


什么是 WebAssembly(Wasm)?

WebAssembly(简称 Wasm)是一种可在现代浏览器中运行的新型代码格式,具有卓越的性能和跨平台能力。Wasm 被设计为 C、C++ 和 Rust 等低级语言的编译目标(MDN Web Docs,2019)。


以太坊与 WebAssembly:Ewasm 的诞生

以太坊 WebAssembly(Ewasm)是基于标准 Wasm 虚拟机构建的确定性智能合约执行引擎。作为替代 EVM 的主要候选方案,Ewasm 已被纳入以太坊 2.0 “Serenity” 的路线图,甚至有提案建议将其应用于以太坊主网(ewasm,2019)。

当前 EVM 架构是限制其性能的主要因素之一(GitHub EIP48,2019)。例如,虽然 256 位字长有助于原生哈希和椭圆曲线计算(Antonopoulos and Wood,2018),但也导致从 EVM 操作码到硬件指令的转换过程异常复杂。采用更接近硬件架构的设计将显著提升以太坊性能(GitHub EIP48,2019)。

Ewasm 的另一设计目标是支持多种智能合约开发语言和工具,包括 LLVM、C、C++、Rust 和 JavaScript。理论上,任何可编译为 Wasm 的语言都可编写智能合约,只需实现 Ewasm 合约接口(ECI)和 以太坊环境接口(EEI)(ewasm,2019)。


智能合约基础

智能合约在以太坊执行环境中充当“自治代理”,当被消息或交易触发时,执行预定义的代码段,并管理自身的以太币余额及持久化键值存储(Buterin,2013)。

诸如 Solidity、Vyper 和 Lity 等高级智能合约语言均配备独立编译器,可将源代码编译为多种输出格式,包括应用程序二进制接口(ABI)、字节码流和操作码。


智能合约编译流程

在本地安装编译器前,建议先使用基于 Web 的编译环境例如 BUIDL,以节省时间。

以 Simple Storage 合约为例,使用在线编译器可立即生成 ABI 和字节码。如需通过命令行完成相同操作,可参考文末附录 A。


字节码结构解析

以字节码的前几条指令为例:

60 80 60 40 5234

根据以太坊黄皮书,操作码 0x60 对应 PUSH1 指令,其作用是将一个字节的数据压入堆栈。例如:

随后,操作码 0x52 对应 MSTORE 指令。MSTORE 是内存操作指令,用于将一个 256 位字存入内存,其执行过程会消耗堆栈顶部的两个元素:第一个元素指定存储地址(如 0x40),第二个元素为待存储数据(如 0x80)。

EVM 的字长为 256 位(Antonopoulos and Wood,2018),此处的“字”可能代表账户地址或其他数据。

接下来,操作码 0x34 对应 CALLVALUE 指令,该指令从执行环境中获取交易转账的以太币数额,并将其压入堆栈。


部署字节码与运行时字节码

需注意区分部署字节码和运行时字节码:

运行时字节码中的每个函数可通过 4 字节的函数签名识别。例如函数 set(uint256) 的签名可通过以下方式计算:

// web3.js 示例
var selectorHash = web3.sha3("set(uint256)").substring(0, 10);
// 返回 0x60fe47b1

该签名可在字节码中直接定位。


Ewasm 实施方案

从高级智能合约代码到 Ewasm 的编译路径多样且复杂。Second State 团队开发的 Soll 编译器实现了从 Solidity 到 Ewasm 的转换。

在 Crosslink(台北)和 Devcon5(大阪)等重要会议上,Second State 展示了其在 Ewasm 领域的进展:

与 Solidity 团队 Christian Reitwiessner 的讨论进一步明确了未来发展方向:在完成 Solidity→LLVM→Ewasm 原型后,重点转向实现 Yul→LLVM→Ewasm 的编译路径。


Yul:以太坊中间语言

Yul 是以太坊特定的中间语言,未来将获得 Solidity 和 Vyper 编译器的全面支持。其设计兼容 EVM 1.0、EVM 1.5 和 Ewasm,核心特性包括函数、区块、变量、字面量、循环和条件语句等(Solidity-Yul,2019)。

“Yul 后端负责生成特定字节码,保留 evm_ewasm_ 前缀区分不同目标平台”(Solidity-Yul,2019)。

从 Solidity 到 Ewasm 的编译路径

编译 Solidity 为 Yul

使用 Solidity 编译器的 --ir 选项可生成 Yul 中间表示(IR):

solc --ir contract.sol

编译 Yul 为 Ewasm

将 Yul 代码编译为 Ewasm 需完成以下步骤:

  1. 将 256 位变量拆分为 4 个 64 位变量
  2. 处理字节序转换(EVM 为大端序,Wasm 为小端序)
  3. 通过函数库实现每个 EVM 操作码的 Ewasm 等效功能

Christian Reitwiessner 在 Devcon5 演示的 代码示例 展示了 MSTORE 函数的 Ewasm 实现:

function mstore(x1, x2, x3, x4, y1, y2, y3, y4) {
  let pos := u256_to_i32ptr(x1, x2, x3, x4)
  i64.store(pos, endian_swap(x1))
  i64.store(i64.add(pos, 8), endian_swap(x2))
  i64.store(i64.add(pos, 16), endian_swap(x3))
  i64.store(i64.add(pos, 24), endian_swap(x4))
}

字节序处理

字节序转换至关重要:EVM 采用大端序,而 Wasm 规范要求小端序(webassembly.github.io,2019)。


未来发展与挑战

Ewasm 的实施仍面临多个待解决的问题:

  1. 与 EVM 1.x 的交互:Ewasm 如何访问合约存储、账户余额等状态数据仍在讨论中
  2. 确定性行为:需通过前哨合约拒绝具有非确定性特征的 Wasm 合约
  3. Gas 计量:正在研究基于静态分析的自动上限估计方案

👉 探索实时开发工具与最新进展


常见问题

什么是 Ewasm?

Ewasm 是以太坊基于 WebAssembly 虚拟机构建的智能合约执行引擎,旨在提升性能并支持多语言开发,是以太坊 2.0 的重要组成部分。

Ewasm 如何提升以太坊性能?

Ewasm 采用更接近硬件架构的设计,简化指令转换过程,同时支持更多编程语言和优化工具链,显著提高执行效率和开发灵活性。

当前哪些语言支持 Ewasm 合约开发?

理论上任何可编译为 Wasm 的语言均可使用,包括 C、C++、Rust 和 JavaScript。通过实现 ECI 和 EEI 接口,可实现与以太坊环境的交互。

字节序转换为何重要?

因为 EVM 使用大端序而 Wasm 规范要求小端序,正确转换字节序是确保数据存储和检索正确的关键。

Ewasm 会完全取代 EVM 吗?

Ewasm 是目前替代 EVM 的主要候选方案,但具体实施路径和兼容性方案仍在讨论和完善中。

如何参与 Ewasm 开发?

开发者可通过贡献代码、测试网络、参加技术会议等方式参与生态建设,关注官方文档和 GitHub 仓库获取最新信息。


结论

智能合约编译到 Ewasm 的路径多样,Yul 中间语言的使用将为现有编译器提供统一目标,并为 LLVM→Ewasm 编译器提供入口。该路径不仅适用于 Solidity 和 Vyper,还为 Rust 等语言进入以太坊生态打开大门。

“使用 Yul 可重用大多数优化器组件,是重大进步”(Reitwiessner,2019)。

随着技术发展,Ewasm 有望为以太坊带来更高性能、更强兼容性和更丰富的开发环境。


附录 A:命令行编译示例

使用 Lity 编译器编译 Simple Storage 合约:

A.1 获取部署字节码

lityc --bin simple_storage.sol

A.2 获取运行时字节码

lityc --bin-runtime simple_storage.sol

A.3 获取操作码

lityc --opcodes simple_storage.sol

A.4 获取 ABI

lityc --abi simple_storage.sol

附录 B:待讨论议题

  1. 与 EVM 1.x 状态交互:Ewasm 如何访问账户信息、区块数据等状态
  2. 确定性保证:通过前哨合约检测和拒绝非确定性代码
  3. Gas 计量机制:基于静态分析的自动上限估计方案

参考文献