跳到主要内容

以太坊虚拟机(EVM)

以太坊网络存在的唯一目的是保持以太坊区块链这个状态机的单一、连续、不间断和不可改变的运行。它是所有 Ethereum 账户和智能合约以及数据的生存环境。在任何给定的区块,以太坊有一个且只有一个全球接受的 "状态"。以太坊虚拟机(EVM)定义了从区块到区块计算新的有效状态的规则。

前提条件

要理解 EVM,需要对字节、内存和堆栈有一些基本了解。

熟悉一些加密技术,如哈希函数,可能也会有所帮助。

以太坊作为一个状态机

像比特币这样的区块链通常被描述为 "分布式账本",它利用密码学的基本工具使去中心化的货币存在。

加密货币可以像 "正常 "货币一样行事,因为有规则规定人们可以和不可以修改这个账本。例如,一个比特币地址不能花费比它之前收到的更多的比特币。这些规则是在比特币上进行的所有交易的基础,类似的还有其他区块链。

虽然以太坊也有它的原生加密货币--以太币,但它也实现了我们所看到的一个更强大的功能--智能合约。对于这个更复杂的功能,我们需要一个比 "分布式账本 "更有力的比喻。

与分布式账本相比,以太坊可以被描述为一个分布式的状态机。状态机本质上是任何可以从一个状态改变到另一个状态的机器,以响应某些输入。

一个简单的状态机是一个投币式旋转门,通常出现在地铁或火车站,以防止人们进入,除非他们使用硬币支付或有票。

旋转门的初始状态是锁定。在锁定状态下,如果你继续推动它,它将保持锁定。如果你插入一枚硬币,它就会进入解锁状态。如果你继续投币,它就保持在解锁状态。一旦你在解锁状态下推动(有人通过),它又变成锁定状态。

对于以太坊,状态要复杂得多。它是用一个大的数据结构来描述的,其中包含了区块链的所有状态。状态如何在区块之间变化的具体规则是由 EVM 定义的。

以太坊状态转换

在高层次上,EVM 的行为类似于数学上的状态转换函数。鉴于当前的状态和一组新的有效交易,它产生一个新的状态。输出是确定性的,这意味着对于相同的输入,它将总是产生相同的输出。

Y(S, T) = S'

给出旧的有效状态 S,和一组新的有效交易 T,状态转换函数 Y 产生新的有效状态 S'。

以太坊的状态被存储为一个真正的大数据结构,称为 Merkle Patricia Trie。你不需要确切了解它的结构,但如果你想了解,你可以阅读给定的链接。

EVM 层

EVM 作为一个层存在于以太坊的软件栈中。

以太坊节点包含 EVM 的实现,然后 EVM 可以在其上执行 EVM 代码。EVM 代码是经过编译的智能合约字节码,可以被执行。

EVM 代码的生成

EVM 指令(OPCODES)

EVM 本身表现为一个堆栈机,堆栈的最大深度为 1024 项。堆栈中的每个项目是一个 256 位(32 字节)的字。

在执行过程中,EVM 保持一个瞬时存储器,作为一个 32 字节的寻址字节数组,它在事务之间不持续存在。当一个新的事务被执行时,暂存器被清空。

然而,智能合约确实在区块链中保持自己的状态。这种状态也被建模为 Merkle Patricia Trie。这通常被称为交易执行期间的 EVM 存储。

EVM 有逻辑存在,允许它执行 EVM 操作码,它在堆栈上执行标准操作,如 XOR、ADD、AND、SUB、MUL 等。EVM 还实现了一些区块链特有的堆栈操作,如 BALANCE 和 BLOCKHASH。

当智能合约被编译成字节码(用十六进制表示)时,它被编译成 EVM 操作码。这些操作码是在 EVM 上执行的。

EVM 的实施

所有 EVM 的实现必须遵守以太坊黄皮书中描述的规范。在以太坊的历史上,EVM 经历了多次修订,现在存在多种不同编程语言的 EVM 实现。

所有的以太坊客户端都包括一个 EVM 实现。除此以外,还有多种独立的实现方式。

以太坊客户端(含 EVM)

  • Geth | 编程语言 = Go
  • OpenEthereum | 编程语言 = Rust
  • Nethermind | 编程语言 = C# (.NET)
  • Besu | 编程语言 = Java
  • Erigon | 程式语言 = Go

独立的 EVM 实现

  • Py-EVM | 编程语言 = Python
  • evmone | 编程语言 = C++
  • ethereumjs-evm | 程式化语言 = Javascript
  • Enclave EVM | 编程语言 = C++

资源

以下是推荐的,但可选择的阅读/观看资料,以了解更多关于 EVM 的信息。

参考