性能优化指南
性能优化是Web3应用开发中的重要环节。本章将介绍智能合约和DApp的主要优化技术。
合约优化
1. Gas优化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79 | // 1. 存储优化
contract StorageOptimization {
// 不好的实践
bool public flag1;
bool public flag2;
bool public flag3;
// 好的实践:打包布尔值
uint8 public flags;
// 设置标志
function setFlag(uint8 index, bool value) public {
require(index < 8, "Invalid index");
if (value) {
flags |= (1 << index);
} else {
flags &= ~(1 << index);
}
}
// 获取标志
function getFlag(uint8 index) public view returns (bool) {
require(index < 8, "Invalid index");
return (flags & (1 << index)) != 0;
}
}
// 2. 循环优化
contract LoopOptimization {
// 不好的实践
function badLoop(uint256[] memory array) public pure returns (uint256) {
uint256 sum = 0;
for (uint256 i = 0; i < array.length; i++) {
sum += array[i];
}
return sum;
}
// 好的实践:缓存数组长度
function goodLoop(uint256[] memory array) public pure returns (uint256) {
uint256 sum = 0;
uint256 length = array.length;
for (uint256 i = 0; i < length; i++) {
sum += array[i];
}
return sum;
}
// 更好的实践:使用unchecked
function betterLoop(uint256[] memory array) public pure returns (uint256) {
uint256 sum = 0;
uint256 length = array.length;
for (uint256 i = 0; i < length;) {
sum += array[i];
unchecked { i++; }
}
return sum;
}
}
// 3. 函数优化
contract FunctionOptimization {
// 不好的实践:重复计算
function badCalculation(uint256 x, uint256 y) public pure returns (uint256) {
return (x + y) * (x + y);
}
// 好的实践:缓存计算结果
function goodCalculation(uint256 x, uint256 y) public pure returns (uint256) {
uint256 sum = x + y;
return sum * sum;
}
// 使用internal代替public
function internalFunction(uint256 x) internal pure returns (uint256) {
return x * x;
}
}
|
2. 内存优化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 | // 1. 内存管理
contract MemoryManagement {
// 不好的实践:过多的内存分配
function badMemory(uint256[] memory array) public pure returns (uint256[] memory) {
uint256[] memory temp1 = new uint256[](array.length);
uint256[] memory temp2 = new uint256[](array.length);
uint256[] memory result = new uint256[](array.length);
for (uint256 i = 0; i < array.length; i++) {
temp1[i] = array[i] * 2;
temp2[i] = temp1[i] + 1;
result[i] = temp2[i];
}
return result;
}
// 好的实践:重用内存
function goodMemory(uint256[] memory array) public pure returns (uint256[] memory) {
uint256[] memory result = new uint256[](array.length);
for (uint256 i = 0; i < array.length; i++) {
result[i] = (array[i] * 2) + 1;
}
return result;
}
}
// 2. 字符串优化
contract StringOptimization {
// 不好的实践:频繁的字符串连接
function badString(string memory a, string memory b) public pure returns (string memory) {
return string(abi.encodePacked(a, " ", b));
}
// 好的实践:使用bytes
function goodString(bytes memory a, bytes memory b) public pure returns (bytes memory) {
bytes memory result = new bytes(a.length + b.length + 1);
uint256 i;
for (i = 0; i < a.length; i++) {
result[i] = a[i];
}
result[i] = 0x20; // 空格
for (uint256 j = 0; j < b.length; j++) {
result[i + 1 + j] = b[j];
}
return result;
}
}
|
计算优化
1. 批量处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 | // 1. 批量转账
contract BatchTransfer {
IERC20 public token;
constructor(address _token) {
token = IERC20(_token);
}
// 不好的实践:单个转账
function singleTransfer(
address[] memory recipients,
uint256[] memory amounts
) public {
require(
recipients.length == amounts.length,
"Length mismatch"
);
for (uint256 i = 0; i < recipients.length; i++) {
token.transfer(recipients[i], amounts[i]);
}
}
// 好的实践:批量转账
function batchTransfer(
address[] memory recipients,
uint256[] memory amounts
) public {
require(
recipients.length == amounts.length,
"Length mismatch"
);
uint256 total = 0;
for (uint256 i = 0; i < amounts.length; i++) {
total += amounts[i];
}
token.transferFrom(msg.sender, address(this), total);
for (uint256 i = 0; i < recipients.length; i++) {
token.transfer(recipients[i], amounts[i]);
}
}
}
// 2. 批量操作
contract BatchOperation {
struct Operation {
address target;
uint256 value;
bytes data;
}
// 批量执行
function batchExecute(Operation[] memory operations) public payable {
for (uint256 i = 0; i < operations.length; i++) {
Operation memory op = operations[i];
(bool success, ) = op.target.call{value: op.value}(op.data);
require(success, "Operation failed");
}
}
}
|
2. 并行计算
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101 | // 1. 任务分片
contract TaskSharding {
struct Task {
uint256 id;
uint256 startIndex;
uint256 endIndex;
bool completed;
bytes result;
}
mapping(uint256 => Task) public tasks;
uint256 public taskCount;
// 创建任务
function createTask(
uint256 startIndex,
uint256 endIndex
) public returns (uint256) {
taskCount++;
tasks[taskCount] = Task({
id: taskCount,
startIndex: startIndex,
endIndex: endIndex,
completed: false,
result: new bytes(0)
});
return taskCount;
}
// 执行任务
function executeTask(uint256 taskId) public {
Task storage task = tasks[taskId];
require(!task.completed, "Task already completed");
// 执行计算
bytes memory result = performComputation(
task.startIndex,
task.endIndex
);
task.result = result;
task.completed = true;
}
// 执行计算
function performComputation(
uint256 startIndex,
uint256 endIndex
) internal pure returns (bytes memory) {
// 实现具体的计算逻辑
return new bytes(0);
}
}
// 2. 工作池
contract WorkerPool {
struct Worker {
address account;
uint256 capacity;
bool active;
}
mapping(address => Worker) public workers;
address[] public workerList;
// 注册工作者
function registerWorker(uint256 capacity) public {
require(!workers[msg.sender].active, "Already registered");
workers[msg.sender] = Worker({
account: msg.sender,
capacity: capacity,
active: true
});
workerList.push(msg.sender);
}
// 分配任务
function assignTask(
bytes memory data
) public view returns (address) {
uint256 bestCapacity = 0;
address bestWorker = address(0);
for (uint256 i = 0; i < workerList.length; i++) {
address worker = workerList[i];
if (
workers[worker].active &&
workers[worker].capacity > bestCapacity
) {
bestCapacity = workers[worker].capacity;
bestWorker = worker;
}
}
return bestWorker;
}
}
|
网络优化
1. 事件优化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 | // 1. 事件索引
contract EventOptimization {
// 不好的实践:过多的索引
event BadEvent(
address indexed user,
address indexed token,
address indexed recipient,
uint256 amount,
uint256 timestamp
);
// 好的实践:合理的索引
event GoodEvent(
address indexed user,
address indexed token,
uint256 amount,
uint256 timestamp
);
// 批量事件
event BatchEvent(
address indexed user,
address[] tokens,
uint256[] amounts
);
}
// 2. 事件批处理
contract EventBatching {
struct Operation {
address user;
uint256 amount;
uint256 timestamp;
}
event BatchOperations(Operation[] operations);
// 批量记录
function logOperations(Operation[] memory operations) public {
emit BatchOperations(operations);
}
}
|
2. RPC优化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74 | // 1. 调用优化
contract RPCOptimization {
// 不好的实践:多次调用
function badCall(address[] memory targets) public view returns (uint256[] memory) {
uint256[] memory results = new uint256[](targets.length);
for (uint256 i = 0; i < targets.length; i++) {
(bool success, bytes memory data) = targets[i].staticcall(
abi.encodeWithSignature("getValue()")
);
require(success, "Call failed");
results[i] = abi.decode(data, (uint256));
}
return results;
}
// 好的实践:批量调用
function goodCall(
address[] memory targets,
bytes[] memory data
) public view returns (bytes[] memory) {
bytes[] memory results = new bytes[](targets.length);
for (uint256 i = 0; i < targets.length; i++) {
(bool success, bytes memory result) = targets[i].staticcall(data[i]);
require(success, "Call failed");
results[i] = result;
}
return results;
}
}
// 2. 缓存优化
contract CacheOptimization {
struct Cache {
uint256 value;
uint256 timestamp;
uint256 ttl;
}
mapping(bytes32 => Cache) public cache;
// 获取或更新缓存
function getOrUpdate(
bytes32 key,
uint256 ttl
) public returns (uint256) {
Cache storage entry = cache[key];
if (
entry.timestamp + entry.ttl > block.timestamp &&
entry.ttl > 0
) {
return entry.value;
}
// 获取新值
uint256 newValue = fetchValue();
entry.value = newValue;
entry.timestamp = block.timestamp;
entry.ttl = ttl;
return newValue;
}
// 获取值
function fetchValue() internal pure returns (uint256) {
// 实现获取值的逻辑
return 0;
}
}
|
练习题
- 实现一个Gas优化的合约:
| // 练习:实现Gas优化
contract GasOptimization {
// 你的代码
}
|
- 创建内存优化的数组操作:
| // 练习:实现内存优化
contract MemoryOptimization {
// 你的代码
}
|
- 实现批量转账:
| // 练习:实现批量转账
contract BatchTransfer {
// 你的代码
}
|
- 创建工作池:
| // 练习:实现工作池
contract WorkerPool {
// 你的代码
}
|
- 实现事件优化:
| // 练习:实现事件优化
contract EventOptimization {
// 你的代码
}
|
参考资源
- Solidity Gas优化
- 以太坊Gas优化
- Web3性能优化
- DApp优化指南
- 智能合约最佳实践