在继续以太坊黄皮书的探索之旅中,本次学习笔记(第4部分)将聚焦于整个以太坊系统的“心脏”——以太坊虚拟机(Ethereum Virtual Machine, EVM),EVM是以太坊区块链上智能合约的运行环境,是“代码即法律”理念得以实现的技术基石,黄皮书第9章(以最新版本为准,章节号可能略有差异)对EVM的规范进行了详尽的定义,理解其核心机制对于深入把握以太坊的工作原理至关重要。
EVM概述:一个确定性图灵完备的虚拟机
EVM本质上是一个基于栈的虚拟机,它被设计为确定性的(Deterministic)和图灵完备的(Turing Complete)。
- 确定性:这意味着对于给定的初始状态和输入,EVM总是会产生相同的输出和最终状态,这是所有区块链节点能够对交易和智能合约的执行结果达成共识的前提,任何依赖于随机数、外部时间或其他非确定性因素的运算都会破坏共识,因此EVM严格禁止此类操作。
- 图灵完备:这意味着EVM可以执行任何可计算的任务,理论上可以模拟任何其他图灵机,为了防止无限循环等消耗网络资源的行为,EVM引入了Gas机制,对每一步计算都消耗Gas,从而使计算在有限资源内完成。
EVM核心数据结构
黄皮书对EVM的内部状态和操作数进行了精确的数学定义。
-
EVM状态(E
VM State):
- 主要由账户模型构成,包括外部账户(EOA,由私钥控制)和合约账户。
- 关键组成部分包括:
currentCoinbase:当前区块的矿工/验证者地址。currentDifficulty:当前区块的难度(在PoS后有所调整,但概念保留)。currentNumber:当前区块号。currentTimestamp:当前区块时间戳。currentGasLimit:当前区块的Gas限制。currentRandom:当前区块的随机数(在PoS中为Beacon Chain的随机数)。currentBlockHashes:可能的历史区块哈希列表(用于某些操作码)。accounts:所有账户的状态,包括余额、 nonce、代码和存储。storage:合约账户的存储空间,是一个键值对映射(bytes32 => bytes32)。memory:EVM的内存,是一个字节数组,用于临时存储计算过程中的数据,是线性的,并且会在交易结束后被重置。stack:EVM的操作数栈,是一个后进先出(LIFO)的结构,用于执行操作码时的参数传递和中间结果存储,栈的最大深度为1024。
-
执行环境(Execution Environment):
定义了执行特定代码(如交易调用)时的上下文,包括上述的EVM状态、调用者、被调用者、Gas限制、value(转账金额)等。
EVM操作码(Opcode)与指令集
EVM通过一系列操作码来实现其计算功能,这些操作码构成了EVM的指令集,黄皮书第9章详细列出了所有操作码及其行为、Gas消耗和堆栈/内存交互方式。
- 算术和比较操作:如
ADD(加法),SUB(减法),MUL(乘法),DIV(除法),MOD(取模),LT(小于),GT(大于),EQ(等于) 等。 - 位运算操作:如
AND(与),OR(或),XOR(异或),NOT(非),SHL(左移),SHR(右移),SAR(算术右移)。 - 堆栈、内存和存储操作:
PUSHn:将n字节的常量压入栈。POP:弹出栈顶元素。DUPn:复制栈顶第n个元素并压入栈。SWAPn:交换栈顶第n个元素与栈顶元素。MLOAD:从内存指定地址加载32字节到栈。MSTORE:将栈顶32字节存储到内存指定地址。MSTORE8:将栈顶1字节存储到内存指定地址。SLOAD:从合约存储指定地址加载32字节到栈。SSTORE:将栈顶值保存到合约存储指定地址(修改存储会消耗较多Gas)。
- 流程控制操作:
JUMP:无条件跳转到指令指定位置。JUMPI:有条件跳转,如果栈顶元素为非零则跳转。PC:获取当前指令在代码中的偏移量。JUMPDEST:标记一个有效的跳转目标。
- 环境信息操作:
BLOCKHASH:获取指定区块号的哈希。COINBASE:获取当前区块的矿工地址。TIMESTAMP:获取当前区块的时间戳。NUMBER:获取当前区块号。GASLIMIT:获取当前区块的Gas限制。CHAINID:获取当前链ID。ADDRESS:获取当前执行上下文的地址(合约地址或EOA)。CALLER:获取调用者的地址。ORIGIN:获取交易的发起者(EOA)地址。BALANCE:获取指定地址的余额。CALLVALUE:获取当前调用传递的value(以太数量)。
- 合约交互操作:
CALL:调用其他合约或发送以太。CALLCODE:在当前上下文中执行指定地址的代码。DELEGATECALL:将调用上下文(caller, value, gas)委托给指定地址的代码执行(用于代理模式)。STATICCALL:执行一个不会修改状态的调用(视图函数)。CREATE:创建一个新合约。CREATE2:以特定方式创建新合约(地址可预测)。RETURN:返回执行结果并终止当前执行。REVERT:回滚状态更改并返回错误信息(Gas退款机制)。SELFDESTRUCT:销毁合约,并将剩余余额发送到指定地址(未来可能被移除或修改)。
Gas机制:EVM的“燃料”
Gas机制是EVM能够高效、安全运行的关键,黄皮书对每个操作码的Gas消耗都进行了严格定义。
- Gas Limit:每笔交易和每个区块都有Gas限制,防止无限计算消耗网络资源。
- Gas Price:用户愿意为每单位Gas支付的以太数量,决定了交易的优先级。
- Gas消耗:执行操作码会消耗Gas,不同的操作码Gas消耗不同,存储修改(SSTORE)和内存扩展(MSTORE)等操作消耗较高。
- Gas退款:某些操作,如清除存储(将存储位置从非零置零),会返还部分Gas,以鼓励优化存储使用。
- 执行终止:当Gas耗尽时,EVM会停止执行,所有状态更改回滚(除了已支付的Gas和已记录的日志)。
交易执行与合约调用流程
黄皮书第6章(交易)和第9章(EVM)共同定义了交易执行的完整流程:
- 交易验证:验证签名、nonce、Gas Limit等。
- 初始化EVM状态:根据当前区块链状态和交易参数设置EVM的初始状态(内存、栈、账户状态等)。
- 执行操作码:从交易数据或合约代码的第一个操作码开始,逐条执行,根据操作码修改栈、内存、存储和账户状态。
- Gas消耗与检查:每执行一个操作码,扣除相应的Gas,如果Gas不足,则抛出“out of gas”异常,状态回滚。
- 结果处理:
- 如果执行成功(RETURN或正常结束),更新状态根,返回执行结果和剩余Gas(返还给发送者)。
- 如果执行失败(REVERT或异常),状态回滚(除了日志和部分Gas退款),返回错误信息和剩余Gas(部分返还)。
总结与展望
通过对黄皮书第4部分(关于EVM)的学习,我们深入理解了以太坊虚拟机的