"How does the Ethereum Virtual Machine (EVM) store smart contract data?"
#JeremyAnswers
Each smart contract has it's own permanent storage. The storage is a one impossibly large array.
The array is 2^256 elements in length and each element is 32 bytes wide.
You may have already guessed, but this array is completely virtual.
Each element in the storage array is referred to as a "slot".
The default value for a slot is 0, this does not take up any space.
Cool to know:
If a slot contains a non-zero value and it is set to 0, storage is freed and gas will be refunded for the action.
Variables are assigned to storage slots at compile time.
The order which variables appear in the contract is the order which they are allocated in the storage array.
Multiple variables can be stored in a single slot if the total size of the variables is less than 32 bytes.
Example:
uint256 a;
uint256[2] b;
uint16 c;
uint32 d;
uint16 e;
address f;
uint256 g;
a -> slot 0
b -> slot 1, 2
c -> slot 3
d -> slot 3
e -> slot 3
f -> slot 3
g -> slot 4
The total size of...
c + d + e + f = 16 + 32 + 16 + 160 = 224 bits
...so it is stored in 1 slot.
Variables that aren't fixed in size (e.g. mappings, dynamic arrays) are stored differently.
In this case the slot address of an element is determined using the hashing function keccak256.
The exact formula for determining the slot is different for dynamic arrays and mappings.
Dynamic Arrays
The slot address of the first element is:
keccak256(arraySlotAddress)
The slot address of the n-th element is:
keccak256(arraySlotAddress) + n
Mappings
The slot address for an element with key "k" is:
keccak256(k + mappingSlotAddress)
Creating a demo really helped my understanding of this.
If you want to play around with my demo project, I put it up on Github:
github.com/jeremysik/ethereum-storage-test