智能合约中的错误处理演进

0x01 为什么要关注错误处理

在智能合约开发中,错误处理看起来是个小事,但实际上它直接影响到:

  • Gas 消耗:错误信息存储在链上是要花钱的
  • 调试体验:好的错误信息能让问题定位事半功倍
  • 合约大小:Solidity 0.8.4 之前,大量的 require 字符串会显著增加合约字节码大小

前段时间 review 团队代码的时候发现,很多同学还在用传统的 require + 字符串的方式处理错误,其实从 Solidity 0.8.4 开始,我们有了更好的选择。

0x02 传统的 require 方式

最常见的写法是这样的:

function withdraw(uint256 amount) external {
    require(balances[msg.sender] >= amount, "Insufficient balance");
    require(amount > 0, "Amount must be greater than zero");
    require(!paused, "Contract is paused");

    balances[msg.sender] -= amount;
    payable(msg.sender).transfer(amount);
}

这种写法的问题:

  • 每个字符串都会被存储在合约字节码中
  • 字符串越长,部署成本越高
  • revert 的时候,字符串会被 ABI 编码,增加 gas 消耗

0x03 Custom Errors 登场

Solidity 0.8.4 引入了 Custom Errors,用法如下:

error InsufficientBalance(address account, uint256 requested, uint256 available);
error ZeroAmount();
error ContractPaused();

function withdraw(uint256 amount) external {
    if (balances[msg.sender] < amount) {
        revert InsufficientBalance(msg.sender, amount, balances[msg.sender]);
    }
    if (amount == 0) revert ZeroAmount();
    if (paused) revert ContractPaused();

    balances[msg.sender] -= amount;
    payable(msg.sender).transfer(amount);
}

好处很明显:

  • 省 Gas:Custom Error 使用 4 字节的 selector 而不是完整字符串
  • 可携带参数:能传递上下文信息,比如余额不足时告诉你实际有多少
  • 类型安全:编译期就能检查参数类型

0x04 Gas 对比

我做了个简单测试,同样的逻辑:

方式 部署 Gas revert Gas
require + 字符串 ~45,000 ~2,400
Custom Error ~32,000 ~1,200

省了大约 30% 的部署成本和 50% 的 revert 成本。在 L2 上可能感知不强,但在主网上,这些都是真金白银。

0x05 实践建议

  1. 新项目直接用 Custom Errors,没有理由再用 require 字符串了
  2. 命名要有意义,让调用方看到错误名就知道发生了什么:
// 好
error SlippageExceeded(uint256 expected, uint256 actual);

// 不好
error Error1();
  1. 善用参数,传递足够的上下文信息:
error TransferFailed(address token, address from, address to, uint256 amount);
  1. 配合 NatSpec 使用,方便生成文档:
/// @notice Thrown when user tries to withdraw more than their balance
/// @param account The account attempting withdrawal
/// @param requested Amount requested
/// @param available Actual balance
error InsufficientBalance(address account, uint256 requested, uint256 available);

0x06 总结

Custom Errors 是 Solidity 错误处理的一次重要演进。它不仅省 Gas,还提供了更好的调试体验和类型安全。如果你的项目还在用 require + 字符串的老方式,是时候升级了。

唯一需要注意的是,一些老的工具链可能对 Custom Errors 的解析支持不够好,但随着生态的发展,这已经不是问题了。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容