Storage Options
Stack
- Solidity automatically stores value-type local variables (like
uint, bool, address) on the EVM stack.
- Value types are primitive types that hold data directly, not as a pointer.
- Examples of value types:
uint, int, bool
address
bytes1 to bytes32
enum
- The stack is limited (1024 slots, each 32 bytes or 256 bits).
- It is possible to swap the topmost element with one of the 16 elements below it
- All other operations take the topmost two (or one, or more, depending on the operation) elements from the stack and push the result onto the stack.
- it is possible to move stack elements to storage or memory in order to get deeper access to the stack, but it is not possible to just access arbitrary elements deeper in the stack without first removing the top of the stack.
- These are stored on the stack, and assembly has direct access to them.
function add(uint a, uint b) public pure returns (uint) {
return a + b; // a, b are stored in the stack
}
//inline assembly example
function example(uint x) public pure returns (uint) {
assembly {
x := add(x, 1) // reads and writes directly
}
return x;
}
Memory
- Volatile, non-persistent space used during function execution.
- Good for structs, arrays, and strings that you want to modify.
- Contract obtains a freshly cleared instance for each message call.
- Memory is linear and can be addressed at byte level, but reads are limited to a width of 32 bytes / 1 word(256 bits), while writes can be either 8 bits or 256 bits wide.
- Memory is expanded by a word (256-bit), when accessing (either reading or writing) a previously untouched memory word (i.e. any offset within a word). At the time of expansion, the cost in gas must be paid.
- Memory is more costly the larger it grows (scales quadratically)
function doubleArray(uint[] memory input) public pure returns (uint[] **memory**) {
for (uint i = 0; i < input.length; i++) {
input[i] *= 2;
}
return input;
}
Calldata
- Read-Only, Gas-Efficient for External Inputs