存储操作基本成本
contract GasOptimization {
// Storage variable declaration (no initialization cost)
uint256 public storedData;
存储新变量消耗20000 Gas,修改已有变量仅需5000 Gas,而读取存储槽的数据只需200 Gas。这样的费用差异相当显著。在编写智能合约时,了解各种操作所需的Gas费用至关重要,这样才能合理规划存储活动。例如,如果项目预算有限,就应尽量减少频繁存储新变量的次数。
存储变量若未初始化,则不会产生 Gas 成本。这是一个实用的方法。开发者可以先声明变量,等到需要时再进行初始化。这样做可以大大减少 Gas 的消耗,有助于项目节省费用,同时也能避免不必要的资源浪费。
struct PackedData {
uint8 data1; // Smaller data types can be packed together
uint8 data2;
}
PackedData public packedData;
内存使用策略
函数内巧妙运用内存临时变量。相较于存储,内存的 Gas 成本较低。处理临时数据时,利用内存存储能显著降低 Gas 消耗。保存计算过程中的中间结果,内存同样适用。
Solidity在存储方面效率很高,使用小数据类型进行组合可以节约空间和计算资源。恰当搭配各种数据类型,可以使存储更加紧密,降低不必要的成本,进而提高合约的运行效率。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
contract GasRefundExample {
// Example storage variables
uint256 public value1;
uint256 public value2;
// Function to update values and free storage slot
function updateValuesAndFreeStorageSlot(uint256 _newValue1, uint256 _newValue2) external {
// Perform some operations with the values
value1 = _newValue1;
value2 = _newValue2;
// Clear the storage slot by zeroing the variables
// This refunds 15,000 gas
assembly {
sstore(value1.slot, 0)
sstore(value2.slot, 0)
}
}
// Function to selfdestruct and refund gas
function destroyContract() external {
// Ensure the refund doesn't surpass half the gas used
require(gasleft() > gasleft() / 2, "Refund cannot surpass half the gas used");
// Selfdestruct and refund 24,000 gas
selfdestruct(payable(msg.sender));
}
}
事件数据存储
存储数据在事件中更经济。事件形式轻便,记录信息时成本较低,有助于减少项目中的 Gas 费用。适用于记录用户操作日志等情况。
事件数据无法被链上其他智能合约获取。这暴露了其限制性。开发者在使用事件存储数据时,需注意信息是否需与其他合约共享,以免干扰业务流程。
Gas 退款机制
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
contract Parent {
uint256 public parentVar;
constructor(uint256 _parentVar) {
parentVar = _parentVar;
}
}
// Child contract inherits from Parent
contract Child is Parent {
uint256 public childVar;
constructor(uint256 _parentVar, uint256 _childVar) Parent(_parentVar) {
childVar = _childVar;
}
}
// Example of using the Child contract
contract Example {
Child public myChild;
constructor(uint256 _parentVar, uint256 _childVar) {
// Creating an instance of Child initializes both parentVar and childVar
myChild = new Child(_parentVar, _childVar);
}
function getParentVar() external view returns (uint256) {
// Accessing parentVar from the Child contract
return myChild.parentVar();
}
function getChildVar() external view returns (uint256) {
// Accessing childVar from the Child contract
return myChild.childVar();
}
}
明白Solidity的Gas退款功能至关重要。这是提升Gas使用效率的技巧之一。一旦达到特定条件,便可以申请退款,从而减少开支。
释放存储槽能够获得 Gas 的返还。若将不再使用的存储槽归零,便可以顺利退还 Gas。进行这一操作时,需选择恰当的时间和地点,以保证合约的稳定运行。
数据类型选择
选择合适的打包方式对提升存储效率、降低 Gas 费用极为关键。不同数据类型在存储时 Gas 消耗各异,需根据实际需求进行合理挑选。
// 高效使用内存数组
function sumValues(uint256[] memory values) external pure returns (uint256) {
uint256 sum;
for (uint256 i = 0; i < values.length; i++) {
sum += values[i];
}
return sum;
}
处理32字节数据,使用bytes32类型最为合适。相较于字符串这类需要动态分配存储空间的类型,bytes32在节省Gas方面有显著优势,尤其是在处理等量数据时。
contract EfficientVariables {
// Avoid public variables, use private visibility
uint256 private myPrivateVar;
合约优化技巧
简化输出可以提升函数效率。给输出起名有助于减少临时变量的使用,进而节约资源和时间成本,增强智能合约的运行效率。
// Use events rather than storing data
event ValueUpdated(uint256 newValue);
公共变量若隐式创建getter函数,可能会提升开销。需留意公共变量的运用,削减多余的getter函数,以减小合约体积和降低Gas消耗。通过参数优化和修饰符逻辑处理等方式,同样可以达到节省Gas的效果。
你都已经学会了这些改进方法了吗?在实际进行开发工作时,你是否曾遭遇过关于交易费用的难题?
// Use return values efficiently
function calculateProduct(uint256 a, uint256 b) external pure returns (uint256 product) {
// Naming the return value directly
product = a * b;
}
// Update private variable efficiently and emit an event
function updatePrivateVar(uint256 newValue) external {
// 直接更新,不需要本地变量
myPrivateVar = newValue;
// 触发日志更新
emit ValueUpdated(newValue);
}
// 获取私有变量
function getPrivateVar() external view returns (uint256) {
// Access the private variable directly
return myPrivateVar;
}