【开发提效工具】gas优化报告的详细使用方法
之前文章中提到了在 hardhat 中使用 gas reporter 来优化 gas,因为篇幅有限,所以另开一篇文章来详细介绍 gas reporter 的使用场景及优化策略。
作用
Gas Reporter 是一个 Hardhat 插件,用于分析智能合约的 Gas 消耗,帮助开发者:
- 量化函数成本:精确测量每个函数调用消耗的 Gas。
- 优化合约代码:定位高 Gas 消耗的函数,针对性优化。
- 预估费用:根据当前 Gas 价格估算实际费用(支持 ETH/USD 等货币单位)。
安装与配置
-
安装插件
npm install --save-dev hardhat-gas-reporter
-
配置文件 (
hardhat.config.js
)require("hardhat-gas-reporter"); // 引入插件 module.exports = { solidity: "0.8.20", gasReporter: { enabled: true, // 开启报告 currency: "USD", // 费用单位(ETH/USD/EUR等) gasPrice: 20, // Gas 单价(单位:Gwei,默认取当前网络价格) coinmarketcap: process.env.COINMARKETCAP_KEY, // API 获取实时价格 outputFile: "gas-report.txt", // 输出到文件 noColors: true, // 文件输出时禁用颜色 excludeContracts: ["MockToken"] // 排除特定合约 } };
运行 gas 报告
-
执行测试时生成报告
npx hardhat test
报告会在测试完成后自动打印在控制台。
-
示例输出
·----------------------------|----------------------------|-------------|----------------------------· | Solidity Contract · Method · Min (Gas) · Max (Gas) · Avg (Gas) · ·----------------------------|----------------------------|-------------|-------------|-------------· | MyContract · transfer · 28912 · 51234 · 43210 · | MyContract · approve · 2345 · 2345 · 2345 · ·----------------------------|----------------------------|-------------|-------------|-------------· ·-------------------------|---------------------------|-------------· | Network · Eth Price (USD) · Gas Price · ·-------------------------|---------------------------|-------------· | sepolia · $1,800 · 20 Gwei · ·-------------------------|---------------------------|-------------·
报告解读
-
核心字段
- Method: 合约函数名称。
- Min/Max/Avg Gas: 单次调用消耗的 Gas 范围及平均值。
- Eth Price: 当前 ETH 价格(需配置
coinmarketcap
API)。 - Gas Price: 当前网络的 Gas 单价(Gwei)。
- Cost (USD): 根据 Gas 消耗和 ETH 价格计算的预估费用。
-
关键指标
- Storage 操作: 存储(SSTORE/SLOAD)是 Gas 消耗的大头。
- Calldata 使用: 减少 calldata 体积可降低 Gas(如使用
bytes
压缩数据)。 - 循环复杂度: 避免大循环和嵌套逻辑。
gas 优化常用策略
1. 减少存储(Storage)操作
// 优化前:多次修改存储变量
function updateValue(uint256 newValue) public {
value = newValue; // 第一次 SSTORE(消耗 Gas)
lastUpdate = block.timestamp; // 第二次 SSTORE(更高 Gas)
}
// 优化后:合并存储变量或使用 Memory
struct State {
uint256 value;
uint256 lastUpdate;
}
State private state;
function updateValue(uint256 newValue) public {
state = State(newValue, block.timestamp); // 单次 SSTORE
}
2. 使用常量(constant
/immutable
)
// 优化前:每次读取需 SLOAD
address public owner;
// 优化后:编译时确定值,Gas 为 0
address public constant OWNER = 0x...;
3. 变量打包(Packing)
// 优化前:浪费存储槽
uint128 a;
uint256 b; // 单独占用一个槽
uint128 c;
// 优化后:将 a 和 c 打包到同一槽
uint128 a;
uint128 c;
uint256 b;
4. 使用 unchecked
块
// 优化前:安全但消耗更多 Gas
function increment(uint256 x) public pure returns (uint256) {
return x + 1;
}
// 优化后:明确无需溢出检查时节省 Gas
function increment(uint256 x) public pure returns (uint256) {
unchecked { return x + 1; }
}
5. 避免重复计算
// 优化前:重复计算相同值
function calculate(uint256 a, uint256 b) public pure {
uint256 sum = a + b;
require(sum > 100, "Invalid sum");
return sum * 2;
}
// 优化后:缓存中间结果
function calculate(uint256 a, uint256 b) public pure {
uint256 sum = a + b;
require(sum > 100, "Invalid sum");
uint256 result = sum * 2;
return result;
}
之前还写过一篇gas优化必须掌握的知识点 这里可以算是对 gas 优化内容的补充,需要的同学自行查阅。
版权声明
本文仅代表作者观点,不代表区块链技术网立场。
本文系作者授权本站发表,未经许可,不得转载。
上一篇:追踪区块链网络表现的组合指标 下一篇:更安全的签名 - EIP712 结构化签名
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。