MODULE 2 · GAS 机制
Lesson 6: Gas 估算与优化
📖 阅读 ~12 分钟🧪 2 个实验❓ 2 道测验
eth_estimateGas:预估交易成本
发送交易之前,你可以用 eth_estimateGas RPC 方法预估 Gas 消耗。钱包(MetaMask)在每笔交易前都自动调用它。
// eth_estimateGas 的工作原理
1. 在当前状态上模拟执行交易(不上链)
2. 记录消耗的 Gas
3. 返回估算值(通常会加一点余量)
// 注意:估算可能不准,因为:
- 状态在估算和实际执行之间可能改变
- 合约逻辑可能依赖区块号、时间戳
- 其他用户的交易可能先执行,改变状态
⚠️ 估算失败 = 交易会 revert
如果 eth_estimateGas 返回错误,说明交易在当前状态下会失败。MetaMask 会提示"交易可能失败"—— 这就是它在做 Gas 估算并发现了 revert。
Cold vs Warm 访问
EIP-2929(柏林升级)引入了 冷/暖访问的概念:同一笔交易中,首次访问一个地址或 storage slot 更贵(cold),后续访问更便宜(warm)。
| 操作 | Cold(首次) | Warm(后续) |
| SLOAD(读 storage) | 2,100 gas | 100 gas |
| BALANCE / EXTCODESIZE | 2,600 gas | 100 gas |
| CALL / STATICCALL | 2,600 gas | 100 gas |
💡 为什么区分冷暖
Cold 访问需要从磁盘加载数据到内存;warm 访问数据已在内存中。区分定价让 Gas 更公平地反映实际计算成本。这也是为什么访问列表 (Access List)可以节省 Gas —— 它预声明要访问的地址/slot。
Solidity Gas 优化技巧
🥇 Top 1: 减少 Storage 读写
// ❌ 坏:每次循环都读写 storage
for (uint i = 0; i < arr.length; i++) {
total += arr[i]; // SLOAD × N 次
}
storedTotal = total; // SSTORE
// ✅ 好:用 memory 变量缓存
uint256 len = arr.length; // SLOAD 1 次
uint256 sum = 0; // memory,几乎免费
for (uint i = 0; i < len; i++) {
sum += arr[i];
}
storedTotal = sum; // SSTORE 1 次
🥈 Top 2: 变量打包
// ❌ 浪费 3 个 slot
uint256 amount; // slot 0 (32B)
bool active; // slot 1 (32B 只用了 1B)
address owner; // slot 2 (32B 只用了 20B)
// ✅ 只用 2 个 slot
uint256 amount; // slot 0
address owner; // slot 1 (20B)
bool active; // slot 1 (打包! +1B)
🥉 Top 3: 用 calldata 代替 memory
// ❌ memory: 复制数据到内存,消耗 Gas
function process(uint[] memory data) external { ... }
// ✅ calldata: 直接读取输入数据,不复制
function process(uint[] calldata data) external { ... }
// 对于只读的外部函数参数,calldata 更便宜
更多优化技巧
短路运算
把便宜的条件放前面:if (a && expensiveCheck())
节省:跳过不必要的计算
用 error 代替 require string
error Unauthorized(); 比 require(x, "msg") 便宜
节省:~50 gas + 部署时的字节码
unchecked 算术
确定不会溢出时,用 unchecked { i++; }
节省:~20 gas/次(省去溢出检查)
immutable / constant
不变的值用 immutable 或 constant,不占 storage
节省:2100 gas/读(避免 SLOAD)
Gas 费用的美元换算
// 公式:
费用(USD) = gasUsed × gasPrice(gwei) × ETH价格(USD) ÷ 10⁹
// 例:Uniswap swap @ 10 gwei, ETH=$2500
费用 = 150,000 × 10 × 2500 ÷ 1,000,000,000
= $3.75
// 同样的 swap 在 L2 (Arbitrum, 0.01 gwei)
费用 = 150,000 × 0.01 × 2500 ÷ 1,000,000,000
= $0.00375 ← 便宜 1000 倍
🔍 Gas 省钱策略
时机选择:周末和 UTC 深夜 Gas 通常最便宜。
链的选择:不需要 L1 安全性的操作放到 L2(Arbitrum/Base/Optimism)。
批量操作:多个操作合并为一笔交易,分摊 21,000 基础 Gas。
🧪 动手实验
🔬 实验 1:多链 Gas 价格对比
对比以太坊 L1 和 L2 的实时 Gas 价格差异。
chainlab tool gas
计算:在当前 Gas 价格下,一笔 Uniswap swap(150k gas)在各链上分别花多少钱?
🔬 实验 2:查看市场行情辅助计算
获取当前 ETH 价格,结合 Gas 价格算出美元成本。
chainlab tool prices
用公式:gasUsed × gasPrice(gwei) × ETH价格 ÷ 10⁹ 亲手算一下。
❓ 自测
📝 本课小结
核心要点
1. eth_estimateGas 通过模拟执行预估 Gas,估算失败 = 交易会 revert
2. Cold 访问比 warm 访问贵 20 倍(2100 vs 100 gas)
3. Gas 优化三板斧:减少 SSTORE/SLOAD、变量打包、用 calldata
4. constant/immutable 避免 SLOAD,unchecked 省去溢出检查
5. 费用(USD) = gasUsed × gasPrice × ETH价格 ÷ 10⁹
←
上一课
Lesson 5: EIP-1559 与 Gas
Module 2 完成!下一模块
Module 3: Solidity 开发
→