Skip to content

Latest commit

 

History

History
244 lines (186 loc) · 7.68 KB

Data-Locations.md

File metadata and controls

244 lines (186 loc) · 7.68 KB

Solidity Tutorial : all about Data Locations

You will find this topic probably as the most challenging. The table below is an overview of each data location available, with mention if read and write to it is allowed. For more details on each data location, read the section for each data location below.

Data Location 🔍 Read ✏️ Write
Storage
Memory
Calldata
Stack
Code

When to use the keywords storage, memory and calldata?

Any variable of complex type like array, struct, mapping or enum must specify a data location.

Storage

Storage refers to the contract's storage.

You can pass the keyword storage to a value you don't want to be cloned.

Storage is long-term but expensive !


Memory

In Ethereum, the memory holds temporary values (said not persisting), like function parameters.

Relative to the execution of the transaction of the transaction of the constructor.

Variables with the keyword memory assigned to them are therefore not persisting and temporary.

Moreover, memory variables are erased between external function calls.

Memory is short and cheap !


CallData

CallData is almost free but has a limited size !

Stack

The Stack hold small local variables. However, it can hold only a limited number of values. The Stack in Ethereum has maximum size of 1024 elements.

Finishes once a function finishes its execution.


Data Location Rules for function and return parameters

The table below give the possible data locations for function parameters, depending on the function visibility.

For contract

Function visibility storage memory calldata
external not allowed ✅ (since 0.6.9)
public not allowed ✅ (since 0.6.9)
internal ✅ (since 0.6.9)
private ✅ (since 0.6.9)

For library

Function visibility storage memory calldata
external
public
internal
private

Data Location in Function Body

Inside functions, all three data locations can be specified, no matter the function visibility. However, some specific rules exist for assignment between references, or to the data at the data location directly. The tables below summarize them.

For storage:

storage references can be assigned a:
state variable directly
state variable via storage reference
memory reference
calldata value directly
calldata value via calldata reference

For memory:

memory references can be assigned a:
state variable directly
state variable via storage reference
memory reference
calldata value directly
calldata value via calldata reference

For calldata:

calldata references can be assigned a:
state variable directly
state variable via storage reference
memory reference
calldata value directly
calldata value via calldata reference

Data Locations - Behaviours

There are two main things to consider when specifying the data location inside the function body: the effect, and the gas usage.

Let's use a simple contract as an example to better understand. The contract holds a mapping of struct items in storage. To compare the behaviour of each data location, we will use different functions that use different data location keywords.

  • a getter using storage.
  • a getter using memory.
  • a setter using storage.
  • a setter using memory.
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

contract Garage {
    struct Item {
        uint256 units;
    }
    mapping(uint256 => Item) items;

    // gas (view) 24025
    function getItemUnitsStorage(uint _itemIndex) public view returns(uint) {
        Item storage item = items[_itemIndex];
        return item.units;
    }

    // gas (view) 24055
    function getItemUnitsMemory(uint _itemIndex) public view returns (uint) {
        Item memory item = items[_itemIndex];
        return item.units;
    }
}

Getter with storage vs memory

Let's debug the opcodes.

; getItemUnitsStorage = 30 instructions
PUSH1 00   ; 1) manipulate + prepare the stack
DUP1
PUSH1 00
DUP1
DUP5
DUP2
MSTORE     ; 2.1) prepare the memory for hashing (1)
PUSH1 20
ADD
SWAP1
DUP2
MSTORE     ; 2.2) prepare the memory for hashing (2)
PUSH1 20
ADD
PUSH1 00
SHA3       ; 3) compute the storage number to load via hashing
SWAP1
POP
DUP1
PUSH1 00
ADD
SLOAD      ; 4) load mapping value from storage
SWAP2
POP
POP
SWAP2
SWAP1
POP
JUMP
JUMPDEST

; getItemUnitsMemory = 47 instructions
PUSH1 00
DUP1
PUSH1 00
DUP1
DUP5
DUP2
MSTORE
PUSH1 20
ADD
SWAP1
DUP2
MSTORE
PUSH1 20
ADD
PUSH1 00
SHA3
PUSH1 40  ; <------ additional opcodes start here
MLOAD     ; 1) load the free memory pointer
DUP1      ; 2) reserve the free memory pointer by duplicating it
PUSH1 20
ADD       ; 3) compute the new free memory pointer
PUSH1 40
MSTORE    ; 4) store the new free memory pointer
SWAP1
DUP2
PUSH1 00
DUP3
ADD
SLOAD     ; 5) load mapping value from storage
DUP2
MSTORE    ; 6) store mapping value retrieved from storage in memory
POP
POP ; <------------ additonal opcodes end here
SWAP1
POP
DUP1
PUSH1 00
ADD
MLOAD
SWAP2
POP
POP
SWAP2
SWAP1
POP

References