简介
以太坊虚拟机(Ethereum Virtual Machine,EVM)是一个去中心化的、跨节点一致的执行环境,负责在所有以太坊节点上安全地执行智能合约代码。节点运行 EVM 来处理交易、执行合约逻辑,并通过消耗 Gas(燃料) 来度量并限制计算资源,从而保障网络的效率与安全
前提知识
要快速理解 EVM,建议具备以下基础:
- 计算机科学常用术语:字节(byte)、内存(memory)、堆栈(stack)等
- 密码学与区块链基础:哈希函数(如 Keccak-256)、默克尔树(Merkle Tree / Patricia Trie)等概念
- 智能合约开发的基本流程(编译后生成字节码、部署到链上、通过交易触发执行)会帮助理解细节
从账本到状态机:概念上的迁移
与比特币常被比作“分布式账本”不同,以太坊更适合被看作一个分布式状态机。除了记录账号与余额之外,以太坊还维护一个可随交易变化的机器状态,并能在状态变更时执行任意机器代码(即智能合约)。这些状态变更的规则由 EVM 明确定义
数学上可以把以太坊的状态转换描述为一个确定性的函数:
Y(S, T) = S'
给定旧的有效状态 S 与一组新的有效交易 T,状态转换函数 Y(S, T) 产出新的有效状态 S'
状态(State)
以太坊的全局状态由一种称为 改进版 Merkle–Patricia Trie 的巨大数据结构保存。该结构将所有账户(包括外部拥有账户和合约账户)及其关联的数据通过哈希组织起来,最终回溯到区块链上的单一根哈希(state root)。这种设计保证了状态可证明性与高效性(例如轻客户端验证)
交易(Transactions)
交易是由账户发起并经密码学签名的指令,分为两类:
- 消息调用交易(Message Call):调用现有合约或向外部账户发送 ETH
- 合约创建交易(Contract Creation):将已编译的智能合约字节码部署为一个新的合约账户。部署后,合约字节码存储在该合约账户中;每当有交易/消息调用该合约时,EVM 会读取并执行这些字节码
EVM 的工作方式

堆栈机(Stack machine)
EVM 是一个基于堆栈的虚拟机:
- 堆栈深度上限为 1024 项
- 每个堆栈项为 256 位(与以太坊使用的 256 位加密原语保持一致,例如 Keccak-256)
- 绝大多数操作以堆栈为中心进行:入栈、出栈、二元运算(ADD、SUB、MUL、DIV、AND、OR、XOR)等
内存(Memory)
执行期间,EVM 维护一个瞬态的 内存(memory),它是一个可字节寻址的动态字节数组:
- 内存仅在交易执行期间存在(临时、非持久)
- 读取/写入内存会消耗 Gas(按增长与操作计费)
- 内存用于临时存放 ABI 编码/解码、中间数据等
存储(Storage)
合约账户拥有持久化的 storage,也是一个按键(256 位)映射到值(256 位)的字典:
- 存储持久化在链上,跨交易保留
- 读写存储的操作比内存和堆栈更昂贵(Gas 更高),是合约审计中的关键攻击面
- Storage 与账户的 Code 一同由状态树管理
合约字节码(Code)
合约的已编译字节码存放在合约账户中,部署后 不可更改(除非使用代理模式等特殊设计)。该字节码相当于传统意义上的“只读程序区域(类似 ROM)”:
- EVM 通过 program counter(PC)顺序读取字节码并执行 opcode。
- 没有 opcode 可以在运行时直接修改账户的 Code(但
SELFDESTRUCT可删除整个账户,包括其 code 与 storage)。
特有区块链操作
除了通用算术与逻辑操作外,EVM 还暴露区块链相关的 opcode,例如:ADDRESS、BALANCE、BLOCKHASH、CALL、DELEGATECALL、STATICCALL、SELFDESTRUCT 等。这些操作使合约能够访问链上与执行环境相关的信息并进行跨合约调用
Gas:资源计量与安全边界
EVM 将每个操作绑定一个 Gas 成本,用以限制计算、存储和带宽的滥用:
- 交易发送者需为交易预付 Gas(gasLimit × gasPrice 或按 EIP-1559 模型的 baseFee + tip)
- Gas 价格(激励)和 Gas 上限(可执行性)影响交易能否被矿工/验证者包含;Gas 用尽会导致交易回滚(状态回退,但已消耗的 Gas 不返还)
- 不同 opcode 的 Gas 成本不同;存储写入、合约创建等成本高昂,是程序优化与审计的重点
EVM 实现与兼容性
所有 EVM 实现需遵循以太坊黄皮书(Yellow Paper)或相关规范。随着以太坊演进(多次硬分叉与协议升级),EVM 规范也在更新。存在多种语言实现以满足不同客户端需求或性能目标:
- Py-EVM(Python)
- evmone(C++)
- ethereumjs-vm(JavaScript)
- revm(Rust)
- 以及各主流以太坊执行客户端(如 Geth、Nethermind、Erigon 等)均实现或集成自己的 EVM 执行模块
这些实现的差异常体现在性能、优化与某些边缘行为的实现细节上,但对外暴露的 EVM 行为应当保持确定性以保证跨节点一致性
