跳至内容
0%

Solidity 错误处理

作者 Shray Jain

发布于 2022年10月4日1 分钟阅读

Solidity 中的错误处理是如何工作的?

Solidity 使用状态回退异常来处理错误,这种异常会撤销当前调用中对状态所做的所有更改,同时向调用者报告错误。

Solidity 是一种面向对象的编程语言,用于在 Ethereum 等区块链上实现智能合约,它拥有大量函数用于解决编译期或运行期可能出现的底层问题。虽然语法错误检查发生在编译期,但运行时错误较难捕获,且主要发生在合约执行过程中。运行时错误的例子包括除以零类型的错误、数组越界错误等。

实际上,Solidity 中的错误处理确保了原子性这一特性。当智能合约调用因错误而终止时,所有状态更改(即对变量、余额等所做的改动)都会被撤销,一直沿调用链向上撤销。

需要注意的是,开发者可以通过声明接口直接与其他合约交互。在 Ethereum 区块链上,交易是原子性的,这意味着交易要么完全执行,要么对状态没有任何影响,并被完全回退。

Solidity 错误处理的三个主要函数是什么?

Solidity 中的错误处理原则上由三个特殊函数管理:assert、require 和 revert。在 0.4.10 版本之前,Solidity 只提供了一个 throw 语句。

Solidity 的设计目标是面向 Ethereum 虚拟机(EVM),并受到 C++、Javascript 和 Python 的影响。使用 Solidity,开发者可以创建用于投票、众筹、多签钱包甚至盲拍等用途的合约。

在实践中,这意味着开发者必须编写多个测试函数来检查底层数值并抛出错误,而这种方式并未针对 gas 进行优化。在 Solidity 0.4.10 版本发布时,引入了新的错误处理结构 assert、require 和 revert,而 throw 则被弃用。

require 函数是什么?

require 函数用于在执行前验证输入和条件。例如,如果条件为 false,require 函数会立即停止执行。换句话说,require 相当于一个门控检查修饰符,阻止逻辑进一步执行函数,从而产生错误。require 非常适合用于逻辑流程门控以及验证函数的用户输入。

require 语句声明了运行函数所需满足的前提条件,这些条件应在代码执行前得到满足。require 函数接受一个参数,经过求值后,require 会返回一个布尔值 true 或 false。如果因条件为 false 而终止执行,未使用的 gas 会返还给调用者,状态也会恢复到原始状态。此外还可以添加自定义字符串消息。

以下是 Solidity 中 require 语句的示例:

基本示例演示了如何使用 require 语句
基本示例演示了如何使用 require 语句

require 语句的使用场景

出于实际考虑,开发者可以在以下场景中使用 require

  1. 验证来自外部合约的响应
  2. 在最终执行前验证状态条件
  3. 验证用户输入

revert 语句是什么?

revert 不对任何条件进行求值,也不依赖任何状态或语句。revert 语句与 require 语句类似,revert 函数可以处理与 require 函数相同类型的错误,但它更适合用于复杂的逻辑门控。

如果调用了 revert 语句,未使用的 gas 会被返还,状态也会恢复到原始状态。添加自定义消息的能力与 require 函数相同。

以下是 Solidity 中 revert 语句的示例:

assert 函数是什么?

assert 是一个用于检查那些永远不应为 false 的代码的函数,在防止不可能出现的情况方面起着重要作用。如果 assert 函数返回布尔值 true,则会显示终止性 bug,程序将不会执行。

requirerevert 函数不同,assert 不会返还任何未使用的 gas,相反,assert 函数会先消耗掉全部 gas,然后再将程序恢复到原始状态。有趣的是,在拜占庭分叉之前,requireassert 函数的行为完全相同,但会编译为不同的操作码。

assert 类型异常

  1. 一个值被对零取模或除以零
  2. 调用了函数的零初始化变量
  3. 将负值或过大的值转换为枚举
  4. 访问数组时使用了负数或超出预期范围的索引

assert 语句示例:

assert 语句的使用场景

理论上,assert 的使用频率应低于 require 函数。开发者应考虑在以下场景中使用 assert 函数:

  • 在更改后验证合约状态
  • 避免出现永远不应发生的情况
  • 检查溢出和下溢参数
  • 检验不变量

require 与 revert 与 assert 的对比

以下是对 Solidity 三个错误处理函数——requirerevertassert——的简要总结说明。

require

  • 用于函数开始处
  • 验证非法输入
  • 在执行前验证状态条件
  • 返还剩余 gas

revert

  • 与 require 相同
  • 适用于更复杂的逻辑流程门控(即复杂的 if-then 语句块)
  • 返还剩余 gas

assert

  • 用于函数结尾处
  • 验证不可能发生的情况
  • 对静态代码分析工具至关重要
  • 不返还剩余 gas

如何进一步了解 require 和 Solidity 错误处理

想要进一步了解 Solidity 错误处理的开发者,可以报名参加 Alchemy University 的免费 Solidity 开发者速成课程。这是一个为期 7 周的免费训练营,帮助 web2 开发者和完全新手学习如何编写 Solidity 智能合约。如果开发者对开发完全陌生,Alchemy University 的3 周 JavaScript 速成课程是开始 Ethereum 训练营之前的绝佳先修课程。

Background gradient

构建区块链应用

Alchemy 将最强大的 Web3 开发者产品和工具与资源、社区及专业支持结合在一起。