The Ethereum Virtual Machine (EVM) provides a simple key-value store where both keys and values are 32 bytes. Solidity, as a high-level language, abstracts this simplicity and allows developers to use complex data types like arrays, mappings, and structs. Here's how it works:
Storage Layout in Solidity
Storage Slots: In Solidity, each state variable is assigned a storage slot. Simple variables (like integers or addresses) are stored in single storage slots. For more complex data types, Solidity uses a deterministic way to assign and compute the location of each element.
Mappings: Mappings are stored in a way that allows efficient lookups. The value of a mapping at a particular key is stored at a pseudo-random slot derived from keccak256(key . slot)
, where slot
is the position of the mapping in the contract storage and key
is the mapping key. This ensures that each key maps to a unique storage location.
Arrays: For dynamic arrays, Solidity stores the length of the array at the slot assigned to the array. The elements of the array are stored at subsequent slots, starting from keccak256(slot)
, where slot
is the position of the array in storage. For fixed-size arrays, the elements are stored contiguously starting from the array's slot.
Structs: Structs are stored by flattening their members and assigning consecutive storage slots to each member. The first member is stored at the slot assigned to the struct, the second member at the next slot, and so on.
Storage Example
Consider the following Solidity contract:
pragma solidity ^0.8.0;
contract Example {
uint256 public number; // Slot 0
mapping(address => uint256) public balances; // Slot 1
uint256[] public numbers; // Slot 2
struct Person {
uint256 id;
string name;
}
Person public person; // Slot 3
}
number
is stored in slot 0.
balances
is stored at keccak256(abi.encode(address, 1))
.
numbers
has its length stored in slot 2, and elements start at keccak256(2)
.
person
has its members stored starting at slot 3 and the next available slots.
Deterministic Storage Layout
Solidity's approach to storage layout is standardized and deterministic, meaning the same source code will always result in the same storage layout, regardless of the compiler version (as long as it follows the Solidity specification). This standardization is necessary for interoperability and contract upgrades.
EVM Data Types
The EVM itself does not define high-level data types. It only understands 256-bit words and provides basic operations to interact with these words. High-level data types like integers, arrays, structs, etc., are abstractions provided by the Solidity compiler. These types are interpreted and managed at runtime by the compiled bytecode, which maps them to the EVM's 256-bit storage.
Summary
- The Solidity compiler provides the mechanism to store complex data types in the EVM's key-value storage.
- The storage layout is deterministic and standardized to ensure interoperability.
- The EVM does not have high-level data types; it uses 256-bit words, with high-level data type management handled by the Solidity compiler and runtime.