Memory#
The Memory is a list of bytes. Each byte can be accessed individually.
Similar to RAM, it starts of by being completely empty. It is also volatile, which means that after execution the memory is reset.
Each memory cell can hold 1 byte (8 bits). A number between 0 and 255.
We will represent Memory as a simple list that can be accessed by an index or offset
.
An offset of 2
would mean that we get the byte stored at index 2
. Combined with a size
we can get a block of bytes. Offset 2
and size 5
would return the bytes from index 2
to index 7
.
class SimpleMemory:
def __init__(self): self.memory = []
def access(self, offset, size): return self.memory[offset:offset+size]
def load (self, offset): return self.access(offset, 32)
def store (self, offset, value): self.memory[offset:offset+len(value)] = value
Expanding the size of Memory consumes gas non-linearly. Making it more costly to create larger and larger Memory space.
Lets add the gas expansion calculation to the Memory
class Memory(SimpleMemory):
def store(self, offset, value):
memory_expansion_cost = 0
if len(self.memory) <= offset + len(value):
expansion_size = 0
# initialize memory with 32 zeros if it is empty
if len(self.memory) == 0:
expansion_size = 32
self.memory = [0x00 for _ in range(32)]
# extend memory more if needed
if len(self.memory) < offset + len(value):
expansion_size += offset + len(value) - len(self.memory)
self.memory.extend([0x00] * expansion_size)
memory_expansion_cost = expansion_size**2 # simplified!
super().store(offset, value)
return memory_expansion_cost
Lets create a some Memory
memory = Memory()
We store 4 values at offset 0
memory.store(0, [0x01, 0x02, 0x03, 0x04]);
load
will always return 32 bytes if it can
memory.load(0)
[1,
2,
3,
4,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0]
Advanced#
This is the actual way how the gas cost for a memory expansion is calculated.
def calc_memory_expansion_gas(memory_byte_size):
memory_size_word = (memory_byte_size + 31) / 32
memory_cost = (memory_size_word ** 2) / 512 + (3 * memory_size_word)
return round(memory_cost)