The storage layout of a smart contract refers to the organization of its storage variables in the contract's long-term memory. This layout is governed by specific rules that dictate how variables are allocated and accessed. The importance of understanding the storage layout cannot be overstated, as it impacts several key areas.
Storage Slots
In Ethereum, state variables are stored in a fixed-size data structure known as storage slots. Each slot is 32 bytes in size. When a contract is deployed, the EVM assigns each state variable to a specific slot. This assignment is crucial because it ensures that the state is accessible and manageable in a consistent manner.
To optimize storage usage, the EVM packs multiple smaller data items into a single storage slot. Padding may be added to align data correctly within these slots, ensuring that each item occupies the full width of the slot. This packing and padding strategy helps minimize gas costs associated with accessing and modifying contract data.
Solidity automatically assigns storage slots starting from 0 for the first state variable and increments the slot number for each subsequent variable. For mappings, arrays, and structs, the allocation is more complex.
Storage Slots
In Ethereum, state variables are stored in a fixed-size data structure known as storage slots. Each slot is 32 bytes in size. When a contract is deployed, the EVM assigns each state variable to a specific slot. This assignment is crucial because it ensures that the state is accessible and manageable in a consistent manner.
To optimize storage usage, the EVM packs multiple smaller data items into a single storage slot. Padding may be added to align data correctly within these slots, ensuring that each item occupies the full width of the slot. This packing and padding strategy helps minimize gas costs associated with accessing and modifying contract data.
Solidity automatically assigns storage slots starting from 0 for the first state variable and increments the slot number for each subsequent variable. For mappings, arrays, and structs, the allocation is more complex.
Slot 0: number (uint256)
The number variable is a uint256, which occupies a full slot (32 bytes).
It starts at slot 0 because it is the first state variable declared in the contract.
Slot 1: owner (address)
The owner variable is an address, which occupies 20 bytes.
However, since a slot is 32 bytes, the remaining 12 bytes in slot 1 will be unused.
Slot 2: data (Data struct)
The data variable is a struct of type Data, which contains two uint256 members: value and value2.
Since data is a complex data type (struct), it starts at a new slot (slot 2).
The value member of the Data struct occupies the first 32 bytes of slot 2.
The value2 member of the Data struct occupies the next 32 bytes, which is slot 3.
Slot 3: data.value2 (uint256)
As mentioned above, the value2 member of the Data struct occupies slot 3.
Slot 4 onwards: data.balances (mapping)
The balances variable is a mapping from address to uint256.
Mappings in Solidity do not have a fixed storage location. Instead, they use a combination of the slot number and the key to compute the storage location of each value.
To access a value in the balances mapping, Solidity computes the storage location using the formula:
keccak256(abi.encodePacked(key, slot))
where key is the address and slot is the slot number where the mapping starts