The EVM: turning an account into a computer
Chapter 1 gave us accounts and unforgeable, signed transactions — but a transaction could still only do one hard-coded thing: move value. This chapter derives the machine that lets an account run *any* program: a stack, a way to pay for computation, and three places to keep data. Build it and the EVM falls out.
- accounts & signed transactions
By the end of chapter 1 we had a shared ledger, accounts, and transactions that are unforgeable — signed by a key only their owner holds. But look closely at what a transaction can actually do: it moves value from one account to another. That’s it. The rule is welded into the protocol. If you want anything richer — an escrow that releases when two people agree, a token that isn’t ETH, an auction — you can’t express it, because there’s nowhere to put the logic and nothing to run it. This chapter fixes exactly that, and the thing we build to fix it is the Ethereum Virtual Machine. We’ll invent it the same way as everything else: name the missing piece, add the smallest thing that supplies it, and see what breaks next.
The problem: the only verb is “transfer”
A transaction names a recipient and an amount, and the protocol applies one fixed rule: subtract here, add there. There is no way to say “only move this if X” or “do this other thing entirely,” because the account holds just a balance and a nonce — no behaviour. To make accounts programmable, the idea writes itself: give an account a code field, and give the protocol a machine that runs that code whenever the account is called.
An account with code is a contract account An account whose behaviour is defined by code stored on-chain. When it's called, the EVM executes that code deterministically on every node; it has its own balance and storage but no private key. . Now the question is what that machine looks like. It has to be dead simple, because every node on Earth must run it and get bit-for-bit the same answer — otherwise they’d disagree on the new state and the chain would split.
→ Step 2: the simplest computer that can compute anything.
Derive the machine: a stack, and nothing else
A CPU with registers is fiddly to specify and easy to disagree on. So reach for the most minimal model that’s still Turing-complete: a stack machine A computer with no named registers or variables. Instructions take their operands from the top of a last-in-first-out stack and push results back onto it. Simple to specify exactly — which is why the EVM is one. . There are no variables and no registers — just a last-in-first-out stack of values. Each instruction (an opcode A one-byte EVM instruction, e.g. 0x01 = ADD, 0x60 = PUSH1, 0x02 = MUL. The contract's code is just a string of these bytes; the EVM reads them one at a time. ) is one byte: it pops what it needs off the top and pushes what it produces back on.
That sounds abstract until you watch it. Here’s the program for (2 + 3) × 4 — five opcodes — running one step at a time. Watch the stack:
Notice what just happened. ADD didn’t need to be told where 2 and 3 were — they were simply the top two items, and it replaced them with 5. That’s the whole trick: because operands always come from the top of the stack, each opcode’s behaviour is trivial to define, and any node running the same bytes gets the same result. Chain enough of these one-byte instructions together and you can compute anything.
→ Step 3: make every step cost something.
Gas: computation you pay for, and that always halts
You cannot, in general, look at a program and decide whether it will ever stop — that’s the halting problem, and it’s not a gap we can engineer around. So don’t try. Instead, attach a price to every opcode and make each transaction carry a budget. Executing an instruction spends from that budget; when the budget hits zero, execution stops immediately. That budget is gas A unit metering EVM work. Every opcode has a fixed gas cost; a transaction supplies a gas limit and pays for the gas it burns. When gas runs out, execution halts and reverts — which is what makes unbounded loops safe. .
This one move solves two problems at once. It makes computation paid-for, so spamming the network with heavy work costs real money; and it makes execution bounded, because a finite budget can only buy finitely many steps. An infinite loop is no longer dangerous — it just burns through its gas and halts.
- 1 a fixed price per instruction — 3 for ADD, 20000 to write a fresh storage slot
- 2 the budget the sender attaches; hit it and execution reverts
→ Step 4: three places for data, by lifetime.
Three data locations, priced by how long they last
Different data has different lifetimes, and lifetime is what should set the price. So the EVM gives code three distinct places to put values, and the whole design is that cost tracks permanence.
- The stack The working surface where opcodes take operands and leave results. Max 1024 items, each a 256-bit word. Effectively free, but exists only for the current call. is for the values an instruction needs this very moment.
- memory A linear, byte-addressable scratch space that starts empty each call and grows as needed. Cheap to use, but discarded when the call returns. is a scratchpad for the duration of a call — building up a return value, hashing a blob of bytes.
- storage The contract's permanent key→value store, committed to the state trie and held on every node's disk. Reads and especially writes (SSTORE) are the priciest common operations, because everyone stores it forever. is the contract’s permanent memory — the only place data survives from one transaction to the next.
Because storage is written to every node’s disk and kept forever, it’s deliberately the most expensive resource in the machine — orders of magnitude pricier than touching the stack. That single price gap is the seed of a surprising number of later upgrades: pricing cold vs. warm access so first-touch reflects the real disk cost, and transient storage for data that only needs to live for one transaction. Keep the gap in mind — we’ll come back to it in Part III.
→ Step 5: run some bytecode yourself.
The real thing, one step at a time
Everything above is animated to teach the shape. This is the actual machine: a real EVM implementation running real bytecode. Step through the presets — the same (2 + 3) × 4, a store-and-load, a RETURN, and a countdown loop — and watch the stack, memory, storage, gas, and program counter move on every instruction. Edit the bytecode and it re-runs.