Gas 优化大师课非常规技巧将函数设为 Payable

将函数设为 Payable

分析

这是一个在 Gas 优化领域流传的、极具争议且通常被视为反模式(Anti-Pattern) 的技巧。虽然在理论上它能节省微不足道的Gas,但其带来的安全风险和代码清晰度的下降,使得它在绝大多数情况下都是一个糟糕的决定。

  1. 理论上的“优化”

核心思想: EVM 在执行一个函数调用之前,会检查该函数是否为 payable。

  • 如果函数是非 `payable` 的,EVM 会插入一个检查,确保 msg.value (交易附带的以太币) 为零。如果 msg.value 不为零,交易会立即 revert。

  • 如果函数是 `payable` 的,这个检查就会被跳过。

因此,理论上将函数标记为 payable 可以省下这个检查 msg.value 是否为零的操作码(Opcode),从而节省几单位的 Gas。

  1. 为什么这是一个极其危险的坏习惯?

将本不应接收资金的函数标记为 payable,会带来多个严重问题,其风险远远超过了它节省的那点微不足道的 Gas。

  • 极高的资金永久锁定风险:

这是最直接、最危险的后果。如果一个用户(或前端应用)在调用一个 payable 函数时,意外地附加了以太币,这些资金将被发送到合约地址。如果你的合约没有编写一个专门的提款函数来取出这些意外收到的资金,那么这些以太币将永久地被锁定在合约中,无法取回。

  • 严重降低代码的可读性和意图清晰度:

payable 关键字是一个强有力的信号,它告诉其他开发者和审计人员:“这个函数被设计用来接收和处理以太币”。将所有函数都标记为 payable会彻底摧毁这个信号,让代码变得混乱且难以理解。审计人员将无法轻易判断哪些函数是真正处理资金的,增加了审计的难度和遗漏漏洞的风险。这违反了“最小权限原则”(Principle of Least Privilege)。

  • 微不足道的 Gas 节省:

节省的 Gas 量级通常在个位数。相比于一笔交易的基础成本(21,000 Gas)和其他复杂操作的成本,这点节省可以忽略不计。为了这点微利去冒资金被锁定的风险,是完全得不偿失的。

测试

总结

对应源码

本文配套代码固定到提交 8960383;Gas 数据会随编译器、优化器参数和 EVM 版本变化。