@@ -15,6 +15,314 @@ timezone: UTC+8
1515## Notes
1616
1717<!-- Content_START -->
18+ # 2025-08-19
19+
20+ ## 优化 Gas
21+
22+ ### 1\. 存储优化策略
23+
24+ 存储操作是 EVM 中最昂贵的操作之一,优化它们可以极大的降低 Gas 成本。
25+
26+ ** 使用 packing 打包变量** :
27+
28+ ``` ts
29+ // 未优化: 3个槽位,每次写入 20000 Gas
30+ uint256 a ; // 槽位 0
31+ uint8 b ; // 槽位 1
32+ bool c ; // 槽位 2
33+
34+ // 优化后: 1个槽位,单次写入 20000 Gas
35+ struct PackedData {
36+ uint8 b ; // 1字节
37+ bool c ; // 1字节
38+ uint240 _unused ; // 填充剩余空间
39+ }
40+ uint256 a ; // 槽位 0
41+ PackedData d ; // 还是槽位 0
42+
43+ ```
44+
45+ ** 优化存储布局** :
46+
47+ * 将频繁一起访问的变量放在同一槽位
48+ * 利用Solidity的紧凑存储特性
49+ * 对结构体字段排序,实现最紧凑布局
50+
51+ ** 减少存储写入次数** :
52+
53+ ``` ts
54+ // 未优化: 2次SSTORE (40,000+ Gas)
55+ function updateValues(uint256 a , uint256 b ) external {
56+ value1 = a ;
57+ value2 = b ;
58+ }
59+
60+ // 优化: 使用内存变量累积更改,1次SSTORE (~20,000 Gas)
61+ function updateValues(uint256 a , uint256 b ) external {
62+ Values memory values = Values (a , b );
63+ combinedValues = values ;
64+ }
65+
66+ ```
67+
68+ ** 使用映射替代数组** :
69+
70+ ``` ts
71+ // 未优化: 数组需要按顺序存储,增加元素可能需要复制整个数组
72+ uint256 [] public values ;
73+
74+ // 优化: 映射不要求连续存储,节省重新排列成本
75+ mapping (uint256 => uint256 ) public values ;
76+ uint256 public valueCount ;
77+
78+ function addValue(uint256 value ) external {
79+ values [valueCount ] = value ;
80+ valueCount ++ ;
81+ }
82+
83+ ```
84+
85+ ** 缓存存储变量到内存** :
86+
87+ ``` ts
88+ // 未优化: 多次访问存储变量 (每次SLOAD消耗~2100 Gas)
89+ function sumStorageArray() public view returns (uint256 ) {
90+ uint256 sum = 0 ;
91+ for (uint256 i = 0 ; i < myArray .length ; i ++ ) {
92+ sum += myArray [i ];
93+ }
94+ return sum ;
95+ }
96+
97+ // 优化: 将存储数组加载到内存中 (一次性SLOAD成本 + 低成本内存访问)
98+ function sumStorageArray() public view returns (uint256 ) {
99+ uint256 [] memory array = myArray ;
100+ uint256 sum = 0 ;
101+ for (uint256 i = 0 ; i < array .length ; i ++ ) {
102+ sum += array [i ];
103+ }
104+ return sum ;
105+ }
106+
107+ ```
108+
109+ ### 计算优化策略
110+
111+ 计算优化可减少合约的 Gas 消耗。
112+
113+ ** 使用位操作替代算术运算** :
114+
115+ ``` ts
116+ // 未优化: 乘法/除法 (5 Gas)
117+ uint256 n = x * 2 ;
118+ uint256 m = y / 2 ;
119+
120+ // 优化: 位操作 (3 Gas)
121+ uint256 n = x << 1 ;
122+ uint256 m = y >> 1 ;
123+
124+ ```
125+
126+ ** 使用 unchecked 块** : 自 Solidity 0.8.0 起,可使用 unchecked 跳过溢出检查,在确定不会溢出的场景中节省 Gas:
127+
128+ ``` ts
129+ // 带溢出检查 (~15 Gas/迭代)
130+ for (uint256 i = 0 ; i < length ; i ++ ) {
131+ // 代码
132+ }
133+
134+ // 无溢出检查 (~5 Gas/迭代)
135+ for (uint256 i = 0 ; i < length ;) {
136+ // 代码
137+ unchecked { i ++ ; }
138+ }
139+
140+ ```
141+
142+ ** 短路求值优化** :
143+
144+ ``` ts
145+ // 未优化: 即使第一个条件为false,仍会评估所有条件
146+ function processIfValid(uint256 value ) public {
147+ bool condition1 = expensiveCheck1 (value );
148+ bool condition2 = expensiveCheck2 (value );
149+ bool condition3 = expensiveCheck3 (value );
150+
151+ if (condition1 && condition2 && condition3 ) {
152+ // 处理有效值
153+ }
154+ }
155+
156+ // 优化: 使用短路求值避免不必要的检查
157+ function processIfValid(uint256 value ) public {
158+ if (expensiveCheck1 (value ) && expensiveCheck2 (value ) && expensiveCheck3 (value )) {
159+ // 处理有效值
160+ }
161+ }
162+
163+ ```
164+
165+ ** 避免不必要的计算** :
166+
167+ ``` ts
168+ // 未优化: 在循环中重复计算不变量
169+ function processList(uint256 [] memory values ) public {
170+ for (uint256 i = 0 ; i < values .length ; i ++ ) {
171+ values [i ] = values [i ] * values .length + someConstant ;
172+ }
173+ }
174+
175+ // 优化: 提取循环不变量
176+ function processList(uint256 [] memory values ) public {
177+ uint256 length = values .length ;
178+ uint256 factor = length + someConstant ;
179+ for (uint256 i = 0 ; i < length ; i ++ ) {
180+ values [i ] = values [i ] * factor ;
181+ }
182+ }
183+
184+ ```
185+
186+ ### 数据类型和操作优化
187+
188+ ** 使用较小的整数类型** :
189+
190+ ``` ts
191+ // 未优化: 默认使用uint256,即使较小值足够
192+ function processSmallNumbers(uint256 small1 , uint256 small2 ) public {
193+ require (small1 <= 100 );
194+ require (small2 <= 100 );
195+ // 处理小数字
196+ }
197+
198+ // 优化: 使用恰当大小的整数类型
199+ function processSmallNumbers(uint8 small1 , uint8 small2 ) public {
200+ // uint8最大值为255,足够容纳100
201+ // 处理小数字
202+ }
203+
204+ ```
205+
206+ ** 固定长度数组优于动态数组** :
207+
208+ ``` ts
209+ // 未优化: 动态数组需要额外存储长度
210+ uint256 [] public dynamicArray ;
211+
212+ // 优化: 固定长度数组不需要存储长度
213+ uint256 [10 ] public fixedArray ;
214+
215+ ```
216+
217+ ** 使用 bytes 替代 string** :
218+
219+ ``` ts
220+ // 未优化: 存储字符串
221+ string public identifier = " Contract ID" ;
222+
223+ // 优化: 对于32字节以内的数据,bytes32比string更高效
224+ bytes32 public identifier = " Contract ID" ;
225+
226+ ```
227+
228+ ** 优化枚举类型** :
229+
230+ ``` ts
231+ // 未优化: 默认枚举从0开始
232+ enum Status {
233+ Active ,
234+ Pending ,
235+ Inactive ,
236+ Cancelled ,
237+ }
238+
239+ // 优化: 将最常用的值放在前面(0和1),因为较小的值编码成本更低
240+ enum Status {
241+ Active ,
242+ Pending ,
243+ Inactive ,
244+ Cancelled ,
245+ }
246+
247+ ```
248+
249+ ### 函数调用优化
250+
251+ ** 减少外部调用** :
252+
253+ ``` ts
254+ // 未优化: 多次外部调用
255+ function processMultiStep() external {
256+ externalContract .step1 ();
257+ externalContract .step2 ();
258+ externalContract .step3 ();
259+ }
260+
261+ // 优化: 批量处理减少调用次数
262+ function processMultiStep() external {
263+ externalContract .processAll ();
264+ }
265+
266+ ```
267+
268+ ** 使用 internal 而非 public 函数** :
269+
270+ ``` ts
271+ // 未优化: public函数增加参数验证和ABI编码成本
272+ function helperFunction(uint256 x ) public pure returns (uint256 ) {
273+ return x * x ;
274+ }
275+
276+ // 优化: internal函数避免不必要的开销
277+ function helperFunction(uint256 x ) internal pure returns (uint256 ) {
278+ return x * x ;
279+ }
280+
281+ ```
282+
283+ ** 避免函数参数过多** :
284+
285+ ``` ts
286+ // 未优化: 多参数函数
287+ function complexOperation(uint256 param1 , uint256 param2 , address param3 , bytes memory param4 , bool param5 ) external {
288+ // 操作
289+ }
290+
291+ // 优化: 使用结构体减少参数数量
292+ struct OperationParams {
293+ uint256 param1 ;
294+ uint256 param2 ;
295+ address param3 ;
296+ bytes memory param4 ;
297+ bool param5 ;
298+ }
299+
300+ function complexOperation(OperationParams memory params ) external {
301+ // 操作
302+ }
303+
304+ ```
305+
306+ ** 优化修饰器使用** :
307+
308+ ``` ts
309+ // 未优化: 复杂修饰器带有额外逻辑
310+ modifier complexCheck () {
311+ require (condition1 ());
312+ require (condition2 ());
313+ require (condition3 ());
314+ _ ;
315+ }
316+
317+ // 优化: 使用函数而非修饰器处理复杂条件
318+ function checkConditions() internal view {
319+ require (condition1 () && condition2 () && condition3 (), " Conditions not met" );
320+ }
321+
322+ // 在函数中调用: checkConditions();
323+
324+ ```
325+
18326# 2025-08-18
19327
20328在以太坊里,Gas 是每个人必须理解的核心概念。本文主要讨论如何估算和优化 Gas,帮助开发者们能够写出更节能的区块链应用。
0 commit comments