以太坊黄皮书学习笔记3,理解虚拟机的心脏—EVM执行模型详解

在前两篇笔记中,我们梳理了以太坊的状态世界模型和账户系统,了解了以太坊如何像一个分布式的全球计算机,维护着一个不断变化的共享状态数据库,这个“全球计算机”究竟是如何执行指令、改变状态的呢?答案就在于以太坊的执行引擎——以太坊虚拟机,本篇笔记,我们将深入黄皮书(Yellow Paper)的第9章,详细解析EVM的执行模型,这是理解以太坊智能合约运行机制的核心。

EVM执行模型:一个基于栈的抽象计算机

从本质上讲,EVM是一个基于栈的、图灵完备的虚拟机,这个描述包含了几个关键概念:

  1. 图灵完备:意味着EVM可以执行任何可计算的算法,只要给予足够的时间和资源,这也带来了“停机问题”——我们无法预先判断一个智能合约是否会无限循环,因此需要引入Gas机制来防止合约消耗无限的计算资源。
  2. 基于栈:与大家更熟悉的基于寄存器(如x86架构)或基于累加器(如MIPS架构)的处理器不同,EVM的所有计算操作都发生在一个上,栈是一种后进先出的数据结构,就像一摞盘子,最后放上去的盘子最先被取走,EVM的栈深度被限制为1024层,以防止栈溢出攻击。

EVM的执行模型,就是一条指令接一条指令地执行,每一条指令都会根据当前的状态和栈的内容,改变栈的状态、内存的状态,并最终可能改变以太坊的全球状态。

执行的“燃料”:Gas机制

在深入指令集之前,我们必须理解贯穿整个EVM执行的灵魂——Gas

Gas是以太坊网络中衡量计算、存储和带宽资源消耗的单位,每一笔交易发送时,发送者都需要设定一个Gas Limit( gas限制)和愿意支付的Gas Price( gas价格),Gas Limit是交易愿意消耗的最大Gas数量,而Gas Price是每个Gas单位的价格。

执行过程如下:

  1. Gas预支付:交易执行前,发送者账户会被扣除 Gas Limit * Gas Price 的以太币,作为“预付款”。
  2. Gas消耗:EVM在执行每一条指令时,都会根据操作的复杂度消耗一定量的Gas,简单的加法消耗很少Gas,而写入存储或进行大量循环则会消耗大量Gas。
  3. Gas退款:某些操作,比如从合约中
    随机配图
    删除一个存储变量,会返还一部分Gas,这鼓励开发者清理不再需要的数据。
  4. 结算
    • 交易成功:所有剩余的Gas(Gas Limit - 已消耗Gas)会按原价退还给发送者,成功执行的操作费(已消耗Gas * Gas Price)会作为矿工费(手续费)支付给打包该交易的矿工。
    • 交易失败:如果在执行过程中Gas耗尽(Out of Gas),所有状态回滚到交易执行前的快照,但已消耗的Gas不会退还,这是对发送者发起无效计算的一种惩罚。

Gas机制确保了网络的安全性,防止了恶意合约(如无限循环)对网络造成拒绝服务攻击。

执行环境:一个结构化的上下文

EVM的执行并非在真空中进行,而是在一个精心设计的执行环境中,黄皮书用结构体 ExecutionEnvironment 定义了这个上下文,它包含了执行当前代码所需的所有信息,主要包括:

  • caller:调用者的地址,即发起交易的账户地址。
  • value:随交易发送的以太币数量(以Wei为单位)。
  • address:当前正在执行的合约的地址。
  • code:当前正在执行的合约的字节码。
  • data:伴随交易或调用传入的数据(Calldata)。
  • gasprice:交易设定的Gas Price。
  • origin:交易的原始发起者地址,用于权限控制。
  • block相关字段:如当前区块号、时间戳、难度、Gas Limit、Coinbase(矿工地址)等,这使得智能合约能够与区块链的当前状态进行交互。

这个执行环境为每一条指令的执行提供了必要的上下文,是连接全局状态和局部计算的桥梁。

状态转换函数:从理论到实践

黄皮书中最核心、最令人望而生畏的部分之一,就是状态转换函数 S,它是一个数学化的函数,形式化地定义了从一个状态 到下一个状态 的完整过程。

σ' = S(σ, t)

t 代表一笔交易,这个函数的内部逻辑,就是EVM的执行模型,我们可以将其分解为以下几个步骤(黄皮书中的算法96):

  1. 初始化:从交易 t 中提取 caller, value, data, gasLimit 等信息,验证发送者账户的 nonce 和余额。
  2. 创建执行环境:根据交易和当前区块信息,构建 ExecutionEnvironment 结构体。
  3. 执行代码:这是核心循环,EVM从 code 的起始位置开始,逐条执行指令:
    • 取指:从程序计数器指向的内存地址读取下一条指令。
    • 译码与执行:根据指令的操作码,执行相应的操作。ADD指令会从栈中弹出两个值,相加后压回栈;SLOAD指令会从存储中读取一个值并压入栈;CALL指令则会发起一次子调用。
    • 修改状态:指令的执行会改变栈、内存或全局状态,每一步操作都会消耗相应的Gas。
  4. 处理子调用:当遇到 CALL, DELEGATECALL, CREATE 等指令时,EVM会递归地创建一个新的执行环境,开始一次新的、嵌套的执行过程,这构成了以太坊强大的组合能力。
  5. 结算:代码执行完毕或因异常终止。
    • 如果所有代码成功执行,更新所有相关账户的 nonce、余额和状态。
    • 如果执行失败(如Gas耗尽、断言失败),回滚所有由该交易产生的状态变更,但Gas费用照常扣除。

这个严谨的函数定义,确保了以太坊的状态转换是确定性和可验证的,任何一个节点,只要输入相同的初始状态和交易序列,都会通过执行这个函数得到完全相同的最终状态。

总结与思考

通过学习黄皮书对EVM执行模型的描述,我们可以清晰地看到以太坊的设计哲学:

  • 简洁而强大:一个基于栈的虚拟机,配合一套精心设计的指令集,以最小的复杂度实现了图灵完备的计算能力。
  • 安全至上:Gas机制是整个系统的安全基石,它将无限的抽象计算限制在有限的、可计量的资源消耗之内。
  • 形式化严谨:状态转换函数 S 的存在,为以太坊的确定性提供了坚实的数学证明,这是其作为“世界计算机”可信度的根本保障。

理解EVM的执行模型,是从“会用”智能合约到“看懂”智能合约的关键一步,它不仅让我们明白一笔交易背后究竟发生了什么,也为我们未来深入研究智能合约安全、优化Gas消耗以及开发区块链上层应用打下了坚实的理论基础,下一章,我们将继续探索EVM的指令集,看看这些强大的原子操作是如何组合成复杂应用的。

本文由用户投稿上传,若侵权请提供版权资料并联系删除!