深入了解 Solidity 错误第一篇, EVM 中的错误分类。
由 Zach Vessels 在 Unsplash 上拍摄
今天文章将开启 "深入 Solidity "系列文章中的一个新子系列:”深入了解 Solidity 错误“ ,主要讨论 Solidity 和基于 EVM 的执行环境中的错误。本文是第一篇文章, ”深入了解 Solidity 错误“ 将一共包含 5 篇文章。
备注:这个系列是从 编译器和 EVM 层角度去理解错误,在语言层面如何进行错误处理可以阅读 学习 Solidity -错误处理
在智能合约领域,错误是非常致命的。如果没处理好,会导致错误和漏洞。如果处理错误,则会导致智能合约卡死和无法使用。
在直接进入 Solidity 之前,我们先来了解一下 EVM 在发生糟糕或错误的事情时是如何处理的,以及 EVM 内置了哪些不同类型的错误。
"如果说调试是清除软件错误的过程,那么编程一定是把错误放进去的过程" - Edsger W. Dijkstra
本文将介绍:
EVM 运行智能合约字节码时,会使用程序计数器 (PC) 一个接一个地运行每个操作码。
程序计数器(PC)编码了 EVM 下一步应读取(并运行)的指令(存储在合约代码中)。每执行一条指令后,程序计数器(PC)都会递增一个字节("PUSHN "指令和 "JUMP"/"JUMPI "指令除外,在这些指令中,程序计数器(PC)会被修改为字节码中的 "JUMPDEST" 目标)。
把 EVM 想象成路上的司机。当司机遇到一些带有方向、信号和限制的交通标志时,他知道下一步该做什么或不做什么。
只要 PC 遇到有效的操作码,EVM 就会继续在合约的当前执行环境中运行操作码。
但有些操作码可以指示停止执行。当执行停止时,我们称之为 EVM halts(见黄皮书)。
但执行可以成功的停止,也可以出错的停止。如果执行成功停止,区块链的状态就会更新。否则,任何状态变化都会被还原,交易也不会在区块链上记录。这是由于以太坊的原子性。交易要么完全完成,要么根本没有做。不存在"部分完成 "的概念。
当程序计数器运行到以下两个操作码之一时,EVM 将停止执行并成功退出:
STOP
(操作码 0x00
):成功退出执行。RETURN
(操作码 0xf3
):成功离开当前上下文+从内存中返回一些数据(=从内存中指定位置偏移开始的特定字节数)。相反,当程序计数器运行到以下两个操作码之一时,EVM 将停止执行并错误退出:
REVERT
:还原所有状态变化。一些数据(在内存中指定)和剩余Gas将返回给调用者。INVALID
:这是 EVM 指定的无效指令。所有状态变化被还原,所有剩余Gas被消耗。调用者不会得到任何Gas返还。当 EVM 遇到错误时,运行时停止执行,导致 EVM 回退对状态所做的所有更改。
对于 EVM 来说,如果预期效果没有发生(或发生了意外效果),默认情况下没有安全的方法来继续执行。回退可保持交易的原子性。如 Solidity 文档所述:
最安全的操作是还原所有更改,并使整个交易(或至少调用)没有影响
如上一节所示,当程序计数器遇到操作码 "REVERT" 或 "INVALID"时,就会发生错误。但实际上,这些并不是唯一的情况!在 EVM 执行环境中,其他因素也可能导致错误。
我们将在接下来的章节中看到,根据黄皮书,实际上有两种类型的停止操作:
在黄皮书中被称为"异常/正常停止状态 "。
正常与异常停止状态错误(来源:以太坊黄皮书)
在 Solidity 中编写智能合约时,会遇到三大类错误。
运行时错误在 Remix 中被定义...
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!