FABRKNT
Reth Fundamentals — Your First Steps with Alloy
Inside the EVM
Lesson 6 of 11·CONTENT12 min25 XP

Treat this page as a workbench, not a blog post. The goal is to extract a reusable mental model from the source and carry it into the rest of the Fabrknt stack.

Course
Reth Fundamentals — Your First Steps with Alloy
Lesson role
CONTENT
Sequence
6 / 11

Lesson 6 — The EVM is a stack machine

Question

You've been talking to Ethereum "from outside" via Alloy. Now peek inside the EVM — what the Ethereum Virtual Machine is and how it works. The EVM is a stack machine — no registers, no memory addresses — just "push and pop" computation.

Principle (minimum model)

  • Stack machine vs register machine. Stack = one place to put values (the top); register = named places (R0, R1, ...). The EVM has a 1024-deep stack only.
  • Five memory regions. Stack (1024 deep, current computation) / Memory (volatile, within a tx) / Calldata (read-only, tx input) / Storage (persisted, blockchain state) / Code (read-only, contract bytecode).
  • Opcode = a 1-byte instruction. 0x01 ADD / 0x60 PUSH1 / 0x52 MSTORE / 0x55 SSTORE. ADD pops two stack values and pushes the sum.
  • Gas. Every opcode has a cost. A tx has a gas limit; if exhausted, execution halts. Storage writes are the most expensive (they're persisted).
  • Why a stack machine? Smaller instruction set + simpler operand encoding → fewer consensus bugs, easier to verify and to compile to ZK circuits. Trade-off: runtime efficiency vs native register code.

Worked example + steps

The EVM is a stack machine

The Ethereum Virtual Machine is a stack machine. It has no general registers and no calling conventions in the C sense — almost everything happens on a stack.

The three "places"

Every EVM instruction reads or writes one of these:

PlacePropertyPurpose
StackLIFO, max 1024 deepOperands and results
MemoryVolatile within a txTemporary scratch space
StoragePersistent (expensive)Contract state

How ADD works

The ADD opcode takes two values from the top of the stack, adds them, and pushes the result back:

Before: stack [..., 7, 5]
ADD
After:  stack [..., 12]

That's it: pop, pop, add, push.

The real Revm Stack

This isn't theory — it's a struct in crates/interpreter/src/interpreter/stack.rs:

pub const STACK_LIMIT: usize = 1024;

#[derive(Debug, PartialEq, Eq, Hash)]
pub struct Stack {
    /// The underlying data of the stack.
    data: Vec<U256>,
}

That's the entire structure: a vector of U256 values, with a hard limit of 1024. The methods you'll see called all over the interpreter:

pub fn new() -> Self
pub fn push(&mut self, value: U256) -> bool
pub fn pop(&mut self) -> Result<U256, InstructionResult>
pub fn peek(&self, no_from_top: usize) -> Result<U256, InstructionResult>
pub fn popn<const N: usize>(&mut self) -> Option<[U256; N]>
pub fn dup(&mut self, n: usize) -> bool
pub fn swap(&mut self, n: usize) -> bool

Read it carefully:

  • push(...) -> booltrue if pushed, false on overflow (more than 1024). The interpreter's macros check this and bail to StackOverflow.
  • pop(...) -> Result<...> — explicit underflow detection, returned as InstructionResult::StackUnderflow.
  • popn<const N: usize>() — pop N values at once, returning a fixed-size array. The const generic means the compiler unrolls the pop loop. This is what makes popn_top! fast.

How ADD actually works

Pop two, sum, push back. Pseudocode:

Before: stack [..., 7, 5]
ADD
After:  stack [..., 12]

The real add source in Revm — which the Intermediate tier dissects line by line — doesn't even pop both then push: it pops one, writes through a mutable reference to the other. Revm's interpreter is built so the EVM mental model maps directly to Rust, but with cycle-level optimizations layered on.

Why a stack machine?

  • Simplicity — small instruction set means fewer consensus bugs
  • Reproducibility — easy to re-execute and verify
  • ZK-friendliness — stack semantics map cleanly to constraint systems (you'll see this in zkEVM later)

Drill

Open crates/interpreter/src/interpreter/stack.rs in the repo. Find:

  1. The STACK_LIMIT check inside push — what does it do on overflow?
  2. The popn impl — notice how the const N lets the compiler skip the loop entirely
  3. The dup and swap methods — they don't allocate; they just shuffle indices

Now build a tiny stack machine yourself in the next lesson.

Summary (3 lines)

  • EVM = stack machine. 1024-deep stack + 5 memory regions (Stack / Memory / Calldata / Storage / Code). Only Storage is persisted.
  • 1-byte opcodes; ADD = pop 2 + push 1; wrapping arithmetic (mod 2²⁵⁶); every opcode has gas; Storage writes most expensive.
  • Stack machine choice = smaller instruction set, easier ZK circuits, harder to consensus-bug. Trade-off is raw runtime speed. Next: mini EVM stack quiz.