Skip to content

🗓️ Week 15 TLDR - More opcodes!

State of mainnet Analysis

I am using a Reth node to connect to the mainnet. Last week, I conducted a sample analysis and verified the generated data, leading to two interesting outcomes:

  1. I found a bug in Reth's tracer.
  2. I identified gaps in my memory expansion formula. After re-reading the yellow paper, I added 18 more opcodes that interact with memory.

Now, a total of 21 opcodes provide greater insight into EVM memory usage, which will be discussed next.

The Function of EVM Memory

EVM instructions access data from five locations: Stack, bytecode, storage, calldata, and memory. Among these, bytecode and calldata are read-only. Storage retains permanent data and is therefore costly. For intermediate, ephemeral data, we rely on two locations: Stack and Memory.

The EVM stack is limited to 32 bytes in size and can hold a maximum of 1,024 elements, resulting in a total capacity of 32 KB of data.

EVM Stack

Instructions requiring fewer than 32 bytes read data from the stack, while those generating less than 32 bytes of output write data to the stack. The ADD instruction both reads from and writes to the stack.

Stack Addition

Conversely, other instructions like Keccak256 can accept arbitrary-sized inputs and generate 32 bytes of output (stored on the stack), while instructions like CALL can take arbitrary inputs and produce arbitrary-sized outputs.

Memory is a byte array of size 32×2256132 \times 2^{256} - 1, which these instructions can leverage to store more than 32 bytes of data.

EVM Memory

Instructions that access memory can be classified based on their functions:

  1. Perform arbitrary computations:
  • KECCAK256
  1. Move data to or from memory:
  • CALLDATACOPY (Calldata ➡️ Memory)
  • CODECOPY (Code ➡️ Memory)
  • EXTCODECOPY (Code ➡️ Memory)
  • MSTORE (Stack ➡️ Memory)
  • MLOAD (Memory ➡️ Stack)
  • MSTORE8 (Stack ➡️ Memory)
  • MCOPY (Memory ➡️ Memory)
  • CALL (Contract account ➡️ Memory)
  • CALLCODE (Contract account ➡️ Memory)
  • DELEGATECALL (Contract account ➡️ Memory)
  • STATICCALL (Contract account ➡️ Memory)
  1. Create new contract account:
  • CREATE
  • CREATE2
  1. Return outcome of EVM execution:
  • RETURN
  • REVERT
  1. Store logs:
  • LOG0
  • LOG1
  • LOG2
  • LOG3
  • LOG4

Thus, any instructions that take more than 32 bytes of memory as input or output will benefit from repricing memory.

Through this analysis, I have discovered several EVM quirks that have been oddly rewarding. I am waiting on Reth to fix the issue so I can run the final analysis.

In other news

I plan to contribute to execution spec tests and stay updated on EOF developments. I am also reading The Art of Doing Science and Engineering, which I highly recommend!