Gas优化完整教程
本教程旨在覆盖智能合约从设计到上线的全部 Gas 优化环节,结合 Binance 智能链与以太坊主网的真实经验,给出一份可被团队直接借鉴的执行清单。
第一章:合约设计阶段就要算账
大多数 Gas 浪费来自架构。新合约动手前,先回答三个问题:
- 哪些字段需要长期持久化?哪些可以放到事件里给链下索引器消化?
- 哪些操作可以离线计算(Merkle Proof、签名验证),仅在链上验证结果?
- 哪些路径是高频路径(每天上万次),哪些是低频(一年几次)?
回答清楚后,设计阶段就能砍掉至少一半的 Gas 成本。
第二章:状态布局与存储
在 B安 等高 TPS 网络上,存储是 Gas 的最大头:
- 把多个小字段塞进同一 slot;
- 使用 immutable 替代 constant 的复杂表达;
- 用 mapping 而不是 array 存储稀疏数据;
- 删除状态时显式置 0,享受 SSTORE refund。
第三章:函数与控制流
- 在循环中缓存数组长度;
- 用 unchecked 包裹明确不会溢出的计数器;
- short-circuit 条件下,把更便宜、更可能 false 的判断放前面;
- 优先 calldata 而非 memory 接收复杂入参。
第四章:自定义错误与事件
- custom error 全面替换 revert 字符串;
- 仅 index 必要字段;
- 大段 metadata 改用 IPFS hash,仅事件中带 hash;
- 同一函数内的状态变更尽量合并为一个事件。
第五章:库与外部调用
- 把通用算法抽成 external library,多个合约共享部署成本;
- 合理使用 delegatecall,注意上下文存储布局兼容;
- 跨合约调用使用 staticcall 拒绝意外状态变更;
- 利用 BN 节点的 estimateGas 在上线前预演完整链路。
第六章:汇编内联的边界
仅当 Solidity 实现已被基准证明仍有显著瓶颈时,才考虑 Yul 内联。每段 Yul 都必须:
- 显式管理 free memory pointer;
- 配套 fuzz 测试与差异化重放;
- 写明「为什么这么写、什么时候应该回退到 Solidity」。
第七章:部署与升级
- 启用 via-IR + 合适的 optimizer.runs;
- 高频核心合约用 UUPS / 透明代理;
- 多链统一地址用 CREATE2;
- 在 必安 智能链先做完整回归再上以太坊主网。
第八章:链下打包与 Layer 2
- 把多笔操作打包进同一交易(multicall、Permit2、ERC-4337 batching);
- 把可异步处理的逻辑搬到 Layer 2,再用桥回主网;
- 利用 calldata 压缩(如 0x 协议的 calldata 编码)降低交易费用。
第九章:监控与持续优化
部署完成后并非终点:
- forge snapshot + gas-reporter 嵌入 CI;
- 用 Dune、Tenderly 追踪生产 Gas;
- 月度 review 每条核心路径的 Gas 中位数,找出最近的退化;
- 用 fork test 在新版本编译器下重新基准。
第十章:组织与文化
最重要的优化,是把 Gas 纪律融入团队习惯:
- PR 模板强制要求 Gas 报告;
- 新人入职用「优化一个老函数」作为第一份任务;
- 把 Gas 节省的金额折算为用户费率讲给非技术同事,赢得共识。
按本教程走完一轮,团队会沉淀出可复用的合约模板、CI 模板与文档库。下一次新业务上线,时间线会显著缩短,而 Gas 表现还会更好。