Skip to the content.

← Back to Homepage

Internals : This doc explains the internals of data locations. While General Notes mentions some differences, this doc delves into more explanation.

Internally, data locations are of 4 types.

  1. storage: The actual store on the blockchain. State variables here persist after any execution. Highest gas cost to manipulate.
  2. Memory is data during execution. It can only be created inside functions as local variables. Miner’s RAM/Stack is where memory data lives. After each function call completes it is wiped. Costs less gas than storage
  3. calldata is the input data generated by the user and sent as a transaction. All the parameters the user intended to give the contract are located in the calldata. It’s the data field in a transaction.
  4. stack is the function stack and is also the default location to store value types inside a function.

Organisation of storage :

  1. Dynamic Arrays : After allocating fixed types as above, we are now on pth 32 byte slot. For dynamic arrays, this slot contains number of elements in this dynamic arrays i.e length. p here is the pointer/memory address value. Actual array data is stored at keccak256(p). That is, while location p contains number of elements of dynamic array, hash of p is where the array actually starts. Now elements in array itself are stored as general above rules. Fit in?pack em. Can’t fit? new slot. Check out byte1[] vs bytes and string below.
  2. Mappings : ** After allocation of fixed types, let’s say we ended up on pth slot. This slot **stays empty. Let’s say we want to access element with k as key. The formula is

keccak256(h(k) . p) where . is concatenation and h(k) is a function based on actual type of key.

​ If key is a value type, h(k) applies a padding to k to make it a 32 byte sized value.

​ If key is a string or byteX, h(k)just computes keccak256 hash of unpadded data.

Remember that mappings here are different from C and other langs. While other langs store keys of a mapping and access values based on that internally, solidity lacks a concept of key. Wait wut?

Yeah, what solidity does is that it does not actually store the (key, value) pair but it stores keccak256(key), value pair. Hence at low level even solidity does not know/have info on our keys. It just believes that when querying, whatever key we supplied will exist. When it doesn’t it returns zero.

Hence, you can’t delete a mapping as solidity does not implicitly store info on keys. We can delete a mapping when we have info on keys, which is manually reaching out to slot and making it 0 or deleting it.

Note : Sound any bells? The whole thing EVM is trying to achieve is to avoid collision as dynamic types are always expanding/reducing. That’s why dynamic types are hashed at pth slot to get a storage far away from fixed types and other dynamic types.

Organisation of memory :

Range Size Purpose
0x00 to 0x3f 64 Bytes Scratch space for Hashing
0x40 to 0x5f 32 Bytes Free memory pointer (current allocated memory size)
0x60 to 0x7f 32 Bytes Zero slot

bytes, string vs byte1[]:

When used in memory:

In memory due to absence of packing, byte1[] has the worst efficiency as each element is placed in it’s own slot i.e 1 byte is used in whole 32 byte slot. bytes or string on the other hand are not treated as arrays and retain the general tight packing even inside memory. Also in calldata.

When used in storage:

While bytes1[] is stored in storage based on general array packing rules, the storage encoding of bytes depends on the length. If the length of bytes is at most 31 bytes, it is stored adjacent to the array length slot p. If the length is more than 32 bytes, bytes is treated in the same way as an array and it’s data is stored at keccak256(p) i.e hash of the inital length/array slot.