Solidity面试题更新 2026-08-03

在 Solidity 智能合约开发中,错误处理机制是怎样的?请详细说明 require、assert 与 revert 这三者在用法、适用场景和底层实现上的主要区别。

考察说明

考查开发者对 Solidity 错误处理机制的掌握,以及能否区分 require、assert 和 revert 的适用场景与底层差异。

回答思路

  1. 【回答框架 1】Solidity 提供三种主要错误处理方式:require、assert 和 revert。require 用于验证外部输入和条件,不满足时回滚交易并消耗剩余 gas(Solidity 0.8 之前);assert 用于检查内部不变量,失败通常表示合约存在 bug,在 0.8 之前会消耗所有 gas;revert 则主动触发回滚,可附带错误消息。
  2. 【回答框架 2】require 和 revert 在语义上更接近:require 本质是条件失败时执行 revert。revert 通常用于复杂条件或需要自定义错误信息的场景,而 require 则更简洁,适合单一条件检查。assert 应仅用于认为不可能失败的不变量,例如数学运算溢出(0.8 前)或状态一致性检查,失败通常意味着代码有严重错误。
  3. 【回答框架 3】在 0.8 版本后,算术溢出自动检查,assert 仍用于不变量,但消耗行为因编译版本和优化设置而异。在实际开发中,应优先使用 require 和 revert 进行输入校验和业务逻辑检查,避免使用 assert 处理可预期的错误条件。
  4. 【回答框架 4】错误处理还需关注 gas 消耗:require 失败时返还剩余 gas(0.8 前),而 assert 会消耗所有 gas(0.8 前),这影响合约的经济性。此外,revert 支持错误字符串和自定义 error 类型,更利于调用方捕获和调试,且自定义 error 更节省 gas。
  5. 【回答框架 5】设计合约时,应区分外部输入校验(require/revert)和内部一致性检查(assert),并合理利用自定义 error 提高可读性和效率。同时注意 0.8 版本后不再需要 SafeMath 进行溢出检查,但 require 和 revert 仍用于业务逻辑验证。
  6. 【关键点 1】require 用于验证外部输入和条件,失败时回滚交易并返还剩余 gas(0.8 前)。
  7. 【关键点 2】revert 用于主动触发回滚,支持错误消息和自定义 error 类型,适合复杂条件。
  8. 【关键点 3】assert 仅用于检查内部不变量,失败通常表示合约存在 bug,在 0.8 前耗尽所有 gas。
  9. 【关键点 4】Solidity 0.8 后算术溢出自动检查,assert 仍用于不变量,但消耗行为与版本相关。
  10. 【关键点 5】优先使用 require 和 revert 进行输入校验和业务逻辑检查,避免使用 assert 处理可预期错误。
  11. 【易错点 1】误将 assert 用于外部输入校验,可能导致 gas 浪费和错误信息不明确。
  12. 【易错点 2】忽视 0.8 版本引入的自动溢出检查,仍依赖 SafeMath 库造成冗余。
  13. 【易错点 3】认为 require 和 revert 在 gas 消耗上完全相同,实际上 revert 可携带更丰富的错误信息,消耗可能更高。