Solidity 错误处理
作者 Shray Jain
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:
- 验证来自外部合约的响应
- 在最终执行前验证状态条件
- 验证用户输入
revert 语句是什么?
revert 不对任何条件进行求值,也不依赖任何状态或语句。revert 语句与 require 语句类似,revert 函数可以处理与 require 函数相同类型的错误,但它更适合用于复杂的逻辑门控。
如果调用了 revert 语句,未使用的 gas 会被返还,状态也会恢复到原始状态。添加自定义消息的能力与 require 函数相同。
以下是 Solidity 中 revert 语句的示例:
assert 函数是什么?
assert 是一个用于检查那些永远不应为 false 的代码的函数,在防止不可能出现的情况方面起着重要作用。如果 assert 函数返回布尔值 true,则会显示终止性 bug,程序将不会执行。
与 require 和 revert 函数不同,assert 不会返还任何未使用的 gas,相反,assert 函数会先消耗掉全部 gas,然后再将程序恢复到原始状态。有趣的是,在拜占庭分叉之前,require 和 assert 函数的行为完全相同,但会编译为不同的操作码。
assert 类型异常
- 一个值被对零取模或除以零
- 调用了函数的零初始化变量
- 将负值或过大的值转换为枚举
- 访问数组时使用了负数或超出预期范围的索引
assert 语句示例:
assert 语句的使用场景
理论上,assert 的使用频率应低于 require 函数。开发者应考虑在以下场景中使用 assert 函数:
- 在更改后验证合约状态
- 避免出现永远不应发生的情况
- 检查溢出和下溢参数
- 检验不变量
require 与 revert 与 assert 的对比
以下是对 Solidity 三个错误处理函数——require、revert 和 assert——的简要总结说明。
require
- 用于函数开始处
- 验证非法输入
- 在执行前验证状态条件
- 返还剩余 gas
revert
- 与 require 相同
- 适用于更复杂的逻辑流程门控(即复杂的 if-then 语句块)
- 返还剩余 gas
assert
- 用于函数结尾处
- 验证不可能发生的情况
- 对静态代码分析工具至关重要
- 不返还剩余 gas
如何进一步了解 require 和 Solidity 错误处理
想要进一步了解 Solidity 错误处理的开发者,可以报名参加 Alchemy University 的免费 Solidity 开发者速成课程。这是一个为期 7 周的免费训练营,帮助 web2 开发者和完全新手学习如何编写 Solidity 智能合约。如果开发者对开发完全陌生,Alchemy University 的3 周 JavaScript 速成课程是开始 Ethereum 训练营之前的绝佳先修课程。
相关概览

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


