以太坊虚拟机(EVM)是以太坊区块链上智能合约的执行环境。本页面重点介绍了 EVM 在 go-ethereum 客户端中的实现,并着重介绍了其架构、执行模型和关键组件。有关使用应用程序二进制接口(ABI)进行智能合约交互的信息,请参阅 ABI 和合约交互。
EVM 是一个基于堆栈的、隔离的运行时环境,智能合约代码在此环境中执行。它被设计为沙盒化的、完全确定性的,确保在无论底层硬件或操作系统如何的情况下,相同的输入始终产生相同的输出。
来源:[core/vm/evm.go], [core/vm/interpreter.go], [core/vm/instructions.go], [core/vm/jump_table.go]
EVM 实现为一个基于堆栈的虚拟机,具有简单的指令集。它操作三个主要数据位置:
来源:[core/vm/evm.go], [core/vm/interpreter.go], [core/state/statedb.go]
核心 EVM 实现定义在 core/vm/evm.go82-128,其中 EVM 结构体包含执行上下文、状态数据库、解释器和其他设置。
解释器是实际执行合约代码的组件。
来源:[core/vm/evm.go], [core/vm/interpreter.go]
EVM 通过以下流程执行合约代码:
来源:core/vm/evm.go188-259 core/vm/interpreter.go156-322
EVM 的核心是解释器中的指令处理循环。
来源:core/vm/interpreter.go226-315
EVM 使用 Gas 来衡量计算资源。每个操作消耗一定量的 Gas,该 Gas 将从交易的 Gas 限额中扣除。
Gas 表定义在 core/vm/gas_table.go 和 params/protocol_params.go。
来源:[core/vm/gas_table.go], [params/protocol_params.go], core/vm/interpreter.go246-292
EVM 拥有丰富的指令集,分为几个类别:
| 类别 | 描述 | 示例 |
|---|---|---|
| 算术 | 基本算术运算 | ADD, SUB, MUL, DIV |
| 比较 | 数值比较 | LT, GT, EQ, ISZERO |
| 按位操作 | 位运算 | AND, OR, XOR, NOT |
| 内存 | 内存操作 | MLOAD, MSTORE, MSTORE8 |
| 存储 | 存储操作 | SLOAD, SLOAD |
| 流量控制 | 执行流程操作 | JUMP, JUMPI, JUMPDEST |
| 环境类 | 区块链信息访问 | TIMESTAMP, NUMBER, BALANCE |
| 栈 | 堆栈操作 | POP, PUSH1-PUSH32, DUP1-DUP16, SWAP1-SWAP16 |
| 日志记录 | 事件日志 | LOG0, LOG1, LOG2, LOG3, LOG4 |
| 系统 | 合约交互 | CALL, CALLCODE, DELEGATECALL, STATICCALL, CREATE, CREATE2, RETURN, REVERT |
指令集会根据活动的硬分叉而有所不同,新的操作码通过以太坊改进提案(EIP)添加。
来源:[core/vm/instructions.go], [core/vm/jump_table.go], [core/vm/opcodes.go]
每个操作码都实现为一个具有以下签名的函数:
例如,ADD 操作:
来源:core/vm/instructions.go30-34 core/vm/interpreter.go93-102
EVM 通过 StateDB 接口与以太坊状态进行交互,该接口提供了以下方法:
来源:[core/state/statedb.go], [core/vm/evm.go], [core/vm/instructions.go]
EVM 包含几个内置合约,称为预编译合约,它们提供了常用加密操作的高效实现。
| 地址 | 姓名 | 描述 |
|---|---|---|
| 0x01 | ECRECOVER | 从签名中恢复公钥。 |
| 0x02 | SHA256 | 计算 SHA-256 哈希。 |
| 0x03 | RIPEMD160 | 计算 RIPEMD-160 哈希。 |
| 0x04 | IDENTITY | 内存复制操作。 |
| 0x05 | MODEXP | 模幂运算。 |
| 0x06 | ECADD | 椭圆曲线加法。 |
| 0x07 | ECMUL | 椭圆曲线标量乘法。 |
| 0x08 | ECPAIRING | 椭圆曲线配对校验。 |
| 0x09 | BLAKE2F | BLAKE2b F 压缩函数。 |
| 0x0a | KZG POINT EVALUATION | EIP-4844(Cancun)的多项式承诺验证。 |
预编译合约实现于 core/vm/contracts.go,并根据活跃的硬分叉进行选择。
EVM 使用跳转表来定义不同以太坊硬分叉可用的操作码。
EVM 根据链规则选择合适的跳转表,以确保在不同的网络升级中行为一致。
来源:core/vm/jump_table.go50-65 core/vm/interpreter.go104-154
EVM 提供了几种合约交互方法:
EVM 通过专用数据结构管理内存和堆栈。
内存实现为一个简单的字节数组,可以根据需要进行扩展。
内存操作包括:
Set:在特定偏移量存储字节。Get:从特定偏移量检索字节。Resize:将内存扩展到特定大小。堆栈实现为一个 256 位无符号整数数组。
堆栈操作包括:
push:将项添加到堆栈顶部。pop:移除并返回堆栈顶部的项。peek:返回堆栈顶部的项而不移除它。swap:交换不同位置的项。dup:复制特定位置的项。来源:[core/vm/memory.go], [core/vm/stack.go]
以太坊虚拟机是一个定义明确、确定性的执行环境,是以太坊智能合约执行的基础。其在 go-ethereum 中的实现提供了一个完整、经过 Gas 计量、基于堆栈的虚拟机,支持从基本算术到复杂的加密原语的各种操作。
EVM 的设计确保智能合约在所有以太坊节点上执行得完全相同,提供了全球去中心化计算机所需的确定性。通过与以太坊状态的交互,EVM 实现了以太坊区别于简单区块链系统的丰富、可编程的功能。