Skip to content

Commit c771a9b

Browse files
committed
Add study notes for 2025-08-19
1 parent b2f98bf commit c771a9b

1 file changed

Lines changed: 308 additions & 0 deletions

File tree

Sillyzhe.md

Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)