Skip to main content

以太坊虚拟机(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 的信息。

参考​