在Solidity中,优化gas使用是非常重要的,因为每一笔交易都需要消耗gas。以下是一些可以帮助你优化gas使用的技巧:
uint8代替uint256可以节省gas。calldata代替memory:在Solidity中,calldata是一个非修改的、只读的数据存储位置,用于函数参数。它只在外部函数中可用,也就是说,只有被external修饰符修饰的函数才能使用calldata。与memory相比,calldata是在EVM的执行环境中,不需要从存储或内存中读取数据。 // 不推荐
for (uint i = 0; i < array.length; i++) {
array[i] = someExternalContract.calculate(i);
}
// 推荐
uint[] memory results = someExternalContract.calculateAll(array.length);
for (uint i = 0; i < array.length; i++) {
array[i] = results[i];
}
// 不推荐
uint public lastUpdated;
function update() public {
lastUpdated = now;
}
// 推荐
event Updated(uint timestamp);
function update() public {
emit Updated(now);
}
delete关键字删除它们可以返还gas。
mapping(address => uint) public balances;
function burn(address user, uint amount) public {
require(balances[user] >= amount, "Insufficient balance");
balances[user] -= amount;
if (balances[user] == 0) {
delete balances[user];
}
}
// 不推荐
function calculate() public {
uint a = balances[msg.sender];
uint b = balances[msg.sender];
uint c = a + b;
}
// 推荐
function calculate() public {
uint balance = balances[msg.sender];
uint c = balance + balance;
}
// 定义一个库 SafeMath
library SafeMath {
function mul(uint a, uint b) internal pure returns (uint) {
if (a == 0) {
return 0;
}
uint c = a * b;
require(c / a == b, "Multiplication overflow");
return c;
}
}
contract MyContract {
using SafeMath for uint;
uint public value;
function multiply(uint amount) public {
value = value.mul(amount); // 使用SafeMath库的mul函数
}
}
staticcall比使用call更加节省gas,因为staticcall不会改变状态。
staticcall比call更加节省gas,原因有两点:
staticcall不能修改状态,因此它不会引发复杂的状态变化,也就不会消耗大量的gas。另一方面,call可以修改状态,因此它可能会引发复杂的状态变化,消耗大量的gas。staticcall只需要读取数据,因此它的计算量较小,消耗的gas也较少。另一方面,call可以执行任何操作,包括计算密集型的操作,因此它可能会消耗大量的gas。immutable和constant:如果有一个在合约生命周期内不会改变的值,那可以使用immutable或constant,这可以节省gas。
// 不推荐
address public owner;
constructor() {
owner = msg.sender;
}
// 推荐
address public immutable owner;
constructor() {
owner = msg.sender;
}
// 不推荐
uint[] public array;
function remove(uint index) public {
for (uint i = index; i<array.length-1; i++){
array[i] = array[i+1];
}
array.pop();
}
// 推荐
mapping(uint => uint) public map;
uint public size = 0;
function remove(uint index) public {
map[index] = map[size-1];
delete map[size-1];
size--;
}
require而不是assert:require和assert都可以用来检查条件,但require在失败时会返还剩余的gas,而assert则不会。
// 不推荐
function transfer(address to, uint amount) public {
assert(balances[msg.sender] >= amount);
balances[msg.sender] -= amount;
balances[to] += amount;
}
// 推荐
function transfer(address to, uint amount) public {
require(balances[msg.sender] >= amount, "Insufficient balance");
balances[msg.sender] -= amount;
balances[to] += amount;
}
声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)进行许可,使用时请注明出处。
Author: mengbin
blog: mengbin
Github: mengbin92
cnblogs: 恋水无意
腾讯云开发者社区:孟斯特