CFO区块链学习笔记(15):以太坊黄皮书学习笔记之执行模型

  • A+
所属分类:以太坊 学习笔记

执行模型具体说明怎么使用一系列字节代码指令和一个小的环境数据元组去改变这个系统状态。这些是通过以太坊虚拟机 (Ethereum Virtual Machine - EVM), 这个虚拟状态机来实现的。它是一个准图灵机, 说“准”是因为计算会被燃料所限制。

1. 基础.

EVM 基于栈结构, 机器的字大小(以及栈中数据的大小)是 256 位。主要是便于执行 Keccak-256 位哈希及椭圆曲线计算。

内存模型基于字寻址的字节数据。栈的最大深度为 1024。

EVM 也有一个独立的存储模型;类似内存但更像一个字节数组, 一个基于字寻址的字数组。不像易变的内存,存储是非易变的且是作为系统状态的一部分被维护。所有内存和存储中的数据会初始化为 0。

EVM 不是标准的诺依曼结构。它通过一个特别的指令把程序代码保存在一个虚拟的可以交互的 ROM 中, 而不是保存在一般性可访问的内存或存储中。

EVM 在某些情况下会有异常发生,包括堆栈溢出和非法指令。就像燃料缺乏异常那样, 不会改变状态。有异常时,EVM 立即停止并告知执行代理 (交易的处理者,或执行环境), 代理会单独处理异常

2. 费用概述.

在三个不同的情况下使用费用(命名为燃料),在这三种情况下,费用都是执行任何操作的必备条件。
第一种情况也是最普通的情况就是计算操作费用。
第二种情况,可能因为一个子消息调用或者合约创建而消耗燃料, 这是执行 CREATE, CALL and CALLCODE费用中的一部分。
第三种情况,可能因为内存使用的增多而为燃料付费。

对于一个账户的执行,内存总费用和需要的 32 字节最小倍数的内存量成正比, 所有的内存是按在一定范围中被包含的所有记忆索引(无论是读还是写)下要求的 32 位字节的最小倍数成比例的。这个为了 just-in-time (JIT) 的基础而去支付的;访问一个大于索引量 32 字节的地址, 就会需要额外的内存使用费。地址很容易超过 32 字节的限制, 但EVM 不同。综上所述,必须能够去管理这些可能发生的事件。

存储费用有一个微妙的行为——为最小化存储费用(直接与一个在所有结点上的大型状态数据通信),清除存储的执行费用指令不仅仅免除, 而且会返回一些费用;因为初始化的存储费用往往比实际使用的多, 在清除存储空间后会有返回费用, 这个返回的费用是预先支付的费用中的一部分。

3. 执行环境.

除了系统状态 和计算过程中剩余的燃料g 外, 还有一些在计算过程中需要提供的信息, 这些信息组成了元组 I :
Ia, 拥有正在执行代码的账户地址。
Io, 发起这次交易的发送者地址。
Ip, 发起这次交易中的燃料价格。
Id, 执行过程中的输入字节数组;如果这次执行是一个交易,这个就是交易数据。
Is, 触发代码执行的账户地址;如果这次执行是一个交易,则为交易发送者地址。
Iv , 以 Wei 为单位的值, 作为计算中的一部分传递给这个账户; 如果这次执行是一个交易, 这个值为转账额度。
Ib, 机器代码字节数组, 会用来执行。
IH, 当前区块的区块头。
Ie, 当前消息调用或合约创建的深度 (例如: 当前CALLs 或 CREATEs 被执行的次数)

4. 执行概述.

我们现在必须去定义函数 。在大多实际执行过程中, 将整个系统状态 和机器状态 的迭代过程建模。我们定义一个递归函数 X, 它使用这个迭代函数 O(定义状态机中单循环的结果), 定义函数 Z 用来表示当前状态是一个异常终止状态, 定义函数 H 表示当前状态是正常终止时得到的结果数据。
空序列使用 () 表示, 它不等于空的集合 ?;这对理解 H的输出结果非常重要, 当 H 的输出结果是 ? 时需要继续执行, 但当 H 的输出结果是时一个空的序列时执行应该终止。

4.1. 机 器 状 态. 机 器 状 态 定 义 为 一 个 元 组(g; pc; m; i; s) , 包括可用的燃料 g, 程序计数器 pc 2 P256 ,内存内容 m , 内存中激活的字数 (从位置 0 开始连续计数)i, 以及栈内容 s。内存内容 m表示空间大小为 2^256但内容都是 0 的空间.

4.2. 异常终止. 以下情况都会发生异常而进入终止状态: 燃料不足、无效指令(无效指令的 下角标不会进行定义)、缺少栈数据、指令 JUMP/JUMPI 的目标地址无效、新的栈大小会大于 1024。聪明的读者将很容易发现, 在整个执行过程中没有一个指令能显式触发异常而终止。

4.3. 跳转地址验证. 我们之前使用 D 作为一个函数去定义正在运行的指定代码的有效跳转地址的集合。我们使用JUMPDEST 指令表示代码可以跳转的地址。这些跳转地址都必须在有效指令边界内,并且需要在显式定义在代码中, 而不是基于 PUSH 指令操作的数据。(也不是使用隐含定义的 STOP 指令去跟踪它).

4.4. 正常停止. 数据返回停止操作 RETURN

4.5. 执行周期. 序列的最左侧的、低端的数据被添加到栈或从栈中移除;所有其它数据都被保留不变

发表评论

您必须才能发表评论!