Efficient Use of Storage Pointers
This tutorial explores how using storage pointers instead of copying data to memory can result in substantial gas savings. Storage pointers allow developers to directly reference storage without unnecessary copying of data, leading to more efficient smart contract execution.
In Solidity, the default behavior when interacting with complex data types like structs from mappings is to copy them into memory. However, this can be inefficient when only a subset of the data is needed. By using storage pointers, we can directly reference and manipulate these data types in storage, thus avoiding the gas costs associated with memory operations.
代码演示
Below are two versions of a contract. The first one uses memory for temporary storage of data, while the optimized version uses storage pointers to reduce gas consumption.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract UserActivityUnoptimized {
struct User {
uint256 id;
string name;
uint256 lastSeen;
}
mapping(uint256 => User) public users;
constructor() {
users[0] = User(0, "John Doe", block.timestamp);
}
// Returns the number of seconds since the user was last seen.
function secondsSinceLastSeen(uint256 userId) public view returns (uint256) {
User memory user = users[userId];
return block.timestamp - user.lastSeen;
}
}
contract UserActivityOptimized {
struct User {
uint256 id;
string name;
uint256 lastSeen;
}
mapping(uint256 => User) public users;
constructor() {
users[0] = User(0, "John Doe", block.timestamp);
}
// Optimized function using a storage pointer.
function secondsSinceLastSeenOptimized(uint256 userId) public view returns (uint256) {
User storage user = users[userId];
return block.timestamp - user.lastSeen;
}
}