Solidity is a statically typed programming language used for writing smart contracts on various blockchain platforms. Understanding data locations is crucial when working with variables in Solidity, as it determines where the data is stored and how it can be accessed. It also helps us to evaluate how gas is being used in our contract.
In this blog, we will go over the various data locations and how they affect your code.
The Data Locations
Solidity has mostly three data locations:
Storage
Memory
Calldata
Each location has its specific purpose and usage within the context of smart contracts.
Storage Data Location
The storage location is the persistent data location. This is used to store the state variables in a contract. This means they are accessible throughout the contract. The data is stored directly on the blockchain.
Storage is also the most expensive data location in terms of gas since these values are stored directly on-chain. So the best practice would be to not make unnecessary storage variables. You can think of the Storage location as the HDD of your laptop.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
contract dataLocations {
uint256 num1; //storage type
uint256 num2; //storage type
address public owner; //storage type
}
Memory Data Location
The memory data location is used for temporary storage during contract execution. It is commonly used for function parameters and local variables. It is cleared after the execution of the parent function. This means they are only accessible inside the scope of their function.
Variables stored in the memory location generally cost less gas since they are not written to the blockchain. You may think of these variables as data in your RAM. Once you switch off your system, the data in the RAM is cleared.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
contract dataLocations {
function test() public pure{
//num3 scope starts
uint num3; //memory type
}
//num3 scope over
}
By default any variable defined inside a function will be of type Memory. However, here’s the catch:
All value-type variables that are defined inside a function get stored in the Memory location by default.
But the reference type variables have to explicitly state where they must be stored- storage, memory or calldata.
Now what are these Types?
Solidity variables are divided into 2 types:-
Value Types: Data values are stored directly in the location where the variable is declared. These generally consist of the primitive datatypes such as: uint, int, bool, address and fixed-size arrays.
Reference Types: Data values reference a storage location and the variables hold a pointer to the actual data. Consists of complex data structures like: dynamic arrays, structs, strings, and mappings.
function test(uint num3) external pure returns (uint, string memory)
{
return (num3, "SOL");
}
Here the variable num3 need not be explicitly declared as ‘memory’ since it is a value type. However, the string variable needs to be declared as memory storage as it is a reference type.
Calldata Location
Calldata is a special data location that holds function arguments. It can only be used for variables being passed as parameters or return types in a function. It should be noted that a variable marked as calldata is not mutable. Once declared as an argument its data cannot be changed.
It is used primarily for optimizing gas usage and preventing accidental modifications to the input data. Hence, they are ‘read-only’ data.
struct score{
uint256 marks;
string subject;
}
function processStruct(MyStruct calldata input) external {
// Access and use the struct from calldata
}
Calldata is generally used by public and external functions. This means private and internal functions tend to make use of storage and memory locations.
Here’s a brief wrap-up of what we learnt:
Hopefully, now you have a better understanding of how data is stored in Solidity. These should be considered while trying to optimize your code.
Thank you for reading! 🎉