BlockVM core guide

The EVM, one opcode and state change at a time.

The Ethereum Virtual Machine is a deterministic, stack-based execution environment with a mature compatibility surface. Learn how bytecode, stack, memory, storage, calls, and gas fit together.

A compact machine with a large ecosystem

The EVM executes contract bytecode against Ethereum-style account state. Its core model is intentionally narrow: a program counter steps through opcodes, most operations consume and produce 256-bit stack words, temporary memory expands during a call, and persistent storage belongs to an account.

The design is more than an instruction set. EVM compatibility also includes transaction encoding, call behavior, logs, revert data, gas accounting, precompiles, contract creation, and conventions captured by application binary interfaces. A chain can support familiar Solidity tooling while still differing in fees, precompiles, opcode availability, finality, or surrounding protocol behavior.

Stack, memory, storage, and calldata

Stack

The operand stack is the immediate workspace. Arithmetic, comparisons, jumps, and environmental instructions read values from the top and push results back. Stack depth and access patterns influence compiler output and make raw bytecode feel different from a register machine.

Memory

Memory is a byte-addressed, temporary area for the current message call. Contracts use it for ABI decoding, return data, hashing input, and intermediate structures. It begins empty and incurs additional cost as the highest accessed region grows.

Storage

Storage is persistent and tied to the executing contract's address. Reads and writes are comparatively expensive because they affect shared state. Layout choices matter for packing, upgrade safety, and the cost of frequently accessed values.

Calldata and return data

Calldata is read-only input supplied to a call. Return data carries a callee's result or revert payload back to the caller. Treating these regions distinctly helps explain why high-level language locations such as memory, storage, and calldata are not interchangeable.

Gas is part of semantics

Every instruction has a gas cost, but the total is context-sensitive. Memory expansion, warm versus cold access, storage transitions, call depth, value transfer, refunds, and transaction data can all affect the amount charged. Gas does three jobs at once: bounds execution, prices resource use, and determines whether a call can continue.

An out-of-gas exception reverts the current call's state changes while consuming the allocated gas. A deliberate REVERT also rolls back changes but can return structured error data and preserve unused gas. The distinction matters for debugging and for composing contracts that catch or propagate failures.

Developer habitEstimate gas after testing realistic state transitions. A clean-room call against empty storage can look very different from a warm, nested production path.

Calls, context, and contract creation

Message calls can execute another account's code, transfer value, and return data. The call family changes execution context in important ways. A regular call uses the callee's address and storage; a delegate-style call executes the callee's code while retaining the caller's storage, sender, and value context. That power enables libraries and proxies but makes storage layout and authorization boundaries critical.

Contract creation runs initialization code, then stores the returned runtime bytecode at the new address. The constructor itself is not part of the deployed runtime unless its logic is deliberately encoded there. Factory patterns, deterministic addresses, and minimal proxies all build on this split between creation and runtime code.

Reading an EVM execution trace

A useful trace answers four questions: which opcode ran, which call frame was active, what gas remained, and what state or memory changed. Start at the transaction boundary, then expand nested calls rather than reading thousands of opcode rows linearly.

  1. Confirm the sender, target, value, calldata, and initial gas.
  2. Locate the first revert or exceptional halt in the deepest failing frame.
  3. Decode the function selector and arguments for that frame.
  4. Inspect storage reads and writes around the failure.
  5. Walk back through returned data and caller-side checks.

For a deeper walkthrough, read Ethereum Virtual Machine explained, then build a repeatable local workflow in the local EVM development stack guide.

Keep following the execution path.

Move from architecture vocabulary into detailed articles on bytecode, proofs, rollups, security, and developer workflow.

Browse field notes