Every transaction on an EVM-based blockchain, whether a simple value transfer or a complex contract interaction, triggers a state transition. The EVM processes this transaction as a series of low-level opcodes, which are the fundamental operations the machine understands—like ADD, MSTORE, or CALL. These opcodes manipulate three key areas of machine state: the stack, memory, and storage. The stack is a last-in-first-out (LIFO) data structure used for computations, memory is volatile byte-array space cleared between calls, and storage is persistent key-value storage tied to a contract's address.
How to Understand EVM Execution Flow
Introduction to EVM Execution
The Ethereum Virtual Machine (EVM) is the deterministic, sandboxed runtime environment that executes smart contracts on Ethereum and other compatible chains. Understanding its execution flow is fundamental for developers building decentralized applications.
The execution flow begins when a transaction is included in a block. The EVM initializes a new execution context with the transaction's data. It then fetches the contract bytecode from the target address and begins interpreting it opcode by opcode. Each opcode consumes a specific amount of gas, a unit of computational work. For example, an SSTORE operation is more expensive than an ADD. If the transaction runs out of gas before completion, all state changes are reverted, but the gas is still consumed—this is a critical security and economic feature.
During execution, the EVM handles internal transactions through the CALL, STATICCALL, DELEGATECALL, and CREATE opcodes. A CALL creates a new sub-context, allowing a contract to interact with another. DELEGATECALL is particularly important for proxy patterns and upgradeable contracts, as it executes code from another contract but within the storage context of the caller. Understanding these call semantics is essential for debugging and securing complex contract interactions.
The final output of EVM execution is a set of logs (emitted events) and a potential state root update. Logs are inexpensive, non-executable data stored on-chain for external clients to query. The state root is a cryptographic commitment to the entire world state, including updated account balances and contract storage. Tools like the EVM debugger in Hardhat or Foundry's forge test --debug allow developers to step through this execution flow opcode-by-opcode, which is invaluable for optimization and security analysis.
How to Understand EVM Execution Flow
A foundational guide to the step-by-step process of transaction execution on the Ethereum Virtual Machine, from user intent to state change.
The Ethereum Virtual Machine (EVM) is the deterministic, sandboxed runtime environment that executes all smart contract code on Ethereum and compatible blockchains. Understanding its execution flow is essential for developers to write efficient, secure contracts and debug transaction failures. The process begins when a user signs and broadcasts a transaction containing data like a recipient address, value in ETH, and optional calldata for contract interactions. This transaction is then propagated across the peer-to-peer network, awaiting inclusion in a block by a validator.
Once a validator includes the transaction in a block, the EVM execution begins. The EVM is a stack-based machine that processes operations in a linear sequence. It loads the transaction's calldata, which specifies the function to call and its arguments. For a simple ETH transfer, the execution is straightforward: the sender's balance is debited and the recipient's is credited. For contract calls, the EVM fetches the contract's bytecode from its address in the world state and begins interpreting the opcodes. Key components involved are the program counter, stack, memory, and storage, each with specific roles during computation.
Execution continues opcode by opcode until it either completes successfully or encounters an error, such as running out of gas or hitting a REVERT instruction. A successful execution results in a state transition: the world state (account balances, contract storage) is permanently updated. All changes are atomic; if execution fails, any intermediate state changes are rolled back, but the gas used up to that point is still consumed as a fee. This gas mechanism prevents infinite loops and allocates network resources fairly. The final state root is then committed to the new block, making the transaction's effects immutable and verifiable by all network participants.
The EVM Execution Pipeline
A step-by-step breakdown of how the Ethereum Virtual Machine processes a transaction, from bytecode to state change.
When you submit a transaction to an Ethereum-compatible network, it triggers a deterministic sequence of operations known as the EVM execution pipeline. This pipeline is the core computational engine for all smart contracts. It begins with the transaction being included in a block and ends with a permanent update to the blockchain's global state. Understanding this flow is critical for debugging, gas optimization, and writing secure smart contracts.
The pipeline starts with bytecode execution. Your Solidity or Vyper code is compiled down to EVM opcodes, which are low-level instructions like ADD, SSTORE, or CALL. The EVM is a stack-based machine, meaning most operations pop values from and push results to an in-memory stack. For example, to add two numbers, you would push them onto the stack with PUSH1 instructions, then execute the ADD opcode, which consumes the two top items and pushes the result.
Execution occurs within the context of an EVM instance. This instance is initialized with key components: the program counter tracking the current opcode, the stack (1024 items max), the volatile memory (a byte array), and the contract's persistent storage. Gas is deducted for each opcode based on its computational cost. If gas is exhausted, execution halts with an "out of gas" error, reverting all state changes except for the gas spent.
A critical phase is state transition. The EVM's execution can read from and write to the world state, which maps account addresses to their balance, nonce, storage, and code. Successful execution of a transaction results in a new, valid state root for the block. If execution fails (e.g., a failed require() statement), the EVM triggers a revert, rolling back all state changes made during that call while still consuming gas up to the point of failure.
To see this in practice, consider a simple function call. The transaction data contains a function selector and arguments, which the EVM uses to jump to the correct code segment. Tools like the Ethereum Execution Specification (EELS) or debug traces in Foundry (forge test --debug) let you step through this process opcode-by-opcode, observing stack, memory, and storage changes in real-time, which is invaluable for low-level development.
Core EVM Components
The EVM executes smart contract code in a deterministic, sandboxed environment. Understanding its core components is essential for debugging, optimization, and security.
Execution Context & Memory
Each contract call creates a fresh execution context with isolated memory regions. The stack (1024 items max) holds temporary values for computations. The memory is a volatile, expandable byte array used for data during a single call. The storage is a persistent key-value store on-chain, costing ~20,000 gas per write.
- Calldata is a read-only byte array containing the function selector and arguments.
- Returndata holds the output of the last external call.
State Trie & Merkle Proofs
The EVM's global state is stored in a Merkle Patricia Trie. Each account (address) is a leaf in this tree, and its storage is a separate sub-trie. The root hash of this state trie is committed to each block header.
- Light clients can verify account states using Merkle proofs without storing the full chain.
eth_getProofRPC call returns proofs for an account's balance, nonce, codeHash, and storage slots.- This structure enables secure and efficient state verification for Layer 2s and bridges.
How to Understand EVM Execution Flow
This guide explains the sequential steps the Ethereum Virtual Machine (EVM) takes to process a transaction, from bytecode to state change.
The EVM is a stack-based, quasi-Turing-complete virtual machine that executes smart contract bytecode. Every transaction triggers an execution cycle that begins with the EVM loading the contract's bytecode into memory. The core components involved are the program counter (PC), which tracks the current instruction; the stack, a last-in-first-out data structure holding 256-bit words for computations; and the memory, a volatile byte array for temporary data storage. Persistent data is stored separately in the contract's storage, a key-value database.
Execution proceeds by fetching, decoding, and executing opcodes one by one. Common opcodes include PUSH (add data to stack), ADD/MUL (arithmetic), SLOAD/SSTORE (storage access), and JUMP (control flow). For example, adding two numbers involves PUSH1 0x0a, PUSH1 0x14, then ADD, which pops the two values, computes the sum, and pushes the result back onto the stack. The EVM charges gas for each opcode, with complex operations like SSTORE costing significantly more than simple arithmetic.
A critical phase is message call execution, initiated by the CALL family of opcodes (CALL, DELEGATECALL, STATICCALL). When CALL is executed, the EVM creates a new, isolated execution context for the target contract. It manages state changes, gas allocation, and value transfer between the caller and callee. Failed operations within a call can trigger a revert, rolling back all state changes in that context unless the call was made with DELEGATECALL, which executes code in the context of the caller's storage.
Execution concludes with either a successful stop or a revert. A successful execution finalizes all state changes, deducts the used gas from the sender's balance, and pays the gas fee to the block validator. A revert, triggered by the REVERT opcode or an out-of-gas error, rolls back all state modifications made in the current call frame but consumes all gas provided up to that point. The final output and remaining gas are returned to the initiator, completing the deterministic state transition defined by the transaction.
Common EVM Opcodes and Gas Costs
Gas costs for frequently used EVM opcodes as of the London hardfork (EIP-1559).
| Opcode (Mnemonic) | Gas Cost (Base) | Description | Stack Input -> Output |
|---|---|---|---|
ADD | 3 | Addition operation | [a, b] -> [a + b] |
MUL | 5 | Multiplication operation | [a, b] -> [a * b] |
SSTORE (cold) | 2100 | Store word to new storage slot | [key, value] -> [] |
SSTORE (warm) | 100 | Store word to accessed storage slot | [key, value] -> [] |
SLOAD (cold) | 2100 | Load word from new storage slot | [key] -> [value] |
SLOAD (warm) | 100 | Load word from accessed storage slot | [key] -> [value] |
CALL | 2600 | Message call to another account | [gas, addr, value, inOffset, inSize, outOffset, outSize] -> [success] |
SHA3 | 30 | Compute Keccak-256 hash | [offset, size] -> [hash] |
BALANCE | 2600 | Get balance of an address | [addr] -> [balance] |
Gas Calculation and Refunds
Understanding how the Ethereum Virtual Machine executes transactions and calculates gas costs is fundamental for writing efficient and cost-effective smart contracts.
Every Ethereum transaction requires gas, a unit of computational work. The EVM processes transactions in a deterministic, step-by-step flow, charging gas for each operation. This flow begins with the execution environment—a sandboxed context containing the transaction data, sender, recipient, and the current world state. The EVM then fetches and executes the contract's bytecode opcodes sequentially. Each opcode, like ADD or SSTORE, has a predefined gas cost specified in the Ethereum Yellow Paper. The total gas used is the sum of all opcode costs incurred during execution.
Gas calculation is not static; it involves dynamic costs based on state access. For example, the SSTORE opcode's cost depends on whether you are setting a storage slot from zero to non-zero (20,100 gas), changing an existing value (2,900 gas), or resetting to zero (which triggers a gas refund). Similarly, reading a non-existent storage slot (SLOAD) costs 2,100 gas, while reading an existing one costs 100 gas. The EVM tracks these costs in real-time, halting execution with an "out of gas" error if the provided gasLimit is exceeded before the transaction completes.
A critical but often misunderstood feature is the gas refund mechanism. When a transaction frees up storage (e.g., by setting a storage slot to zero with SSTORE), it becomes eligible for a refund. The EVM tracks refunds separately during execution, but they are only applied after execution finishes. The maximum refund is capped at 50% of the total gas used. This means you cannot get more gas back than you spent. Refunds incentivize cleaning up state but do not reduce the upfront gas required for a transaction, which must still be within the block's gas limit.
To analyze gas usage, developers use tools like the EVM's built-in debug_traceTransaction RPC method or external tracers. These tools reveal the precise execution trace, listing each opcode, its gas cost, and the stack depth. For instance, a trace will show that a contract call (CALL) costs at least 700 gas (the base cost) plus memory expansion and value transfer fees. Understanding this trace is essential for optimizing contracts, identifying expensive loops, and minimizing unnecessary storage operations that drive up costs.
When a transaction ends, the final gas cost is calculated: gasUsed = totalGasCost - min(refund, totalGasCost / 2). The sender pays gasUsed * gasPrice in ETH, which is burned post-EIP-1559. Any remaining gas (gasLimit - gasUsed) is refunded at the original gasPrice. This flow ensures users pay for computation and storage they consume, while refunds partially offset the cost of cleaning the blockchain state. Mastering this process allows developers to write more efficient code and users to submit transactions with accurate gas estimates.
Memory, Storage, and Execution Context
Understanding the Ethereum Virtual Machine's execution flow is fundamental for writing efficient and secure smart contracts. This guide explains the distinct roles of memory, storage, and the execution context.
Every Ethereum transaction triggers the execution of a smart contract within the Ethereum Virtual Machine (EVM). This execution occurs in a temporary, isolated environment known as the execution context. This context contains critical state: the program counter, the gas remaining, the stack, and the contract's memory. It is ephemeral; once execution finishes, the context is discarded. The only persistent changes are those written to the contract's storage, which is a key-value store permanently recorded on the blockchain.
The EVM has three primary data areas: storage, memory, and the stack. Storage is a persistent, key-value store mapped to the contract's address. It is expensive to use, costing 20,000 gas for an initial write and 5,000 for a subsequent update. Memory is a volatile, expandable byte array used for temporary data during a function call. It is much cheaper but is wiped clean after execution. The stack is a last-in-first-out (LIFO) data structure with a maximum depth of 1024 items, used for holding local variables and intermediate computations during opcode execution.
The execution flow begins when a transaction is mined. The EVM loads the contract's bytecode and initializes the execution context. Opcodes are processed sequentially, manipulating the stack, memory, and interacting with storage via dedicated opcodes like SSTORE and SLOAD. For example, a simple function that increments a counter would SLOAD the value from storage, perform the addition on the stack, and then SSTORE the new value back. Understanding this flow helps optimize gas costs by minimizing storage operations and efficiently using memory.
Execution can involve message calls to other contracts using CALL or DELEGATECALL. These create new, nested execution contexts. A critical distinction is that DELEGATECALL preserves the original contract's storage context, allowing for proxy patterns and upgradeable contracts. Failed operations, such as a revert or running out of gas, will roll back all state changes made within that execution context, but gas spent up to that point is not refunded.
To analyze execution, developers use tools like the EVM Playground or debug transactions in Tenderly and Etherscan. By stepping through opcodes, you can observe the exact state of the stack and memory at each step. Writing efficient contracts requires mindful data placement: use memory for temporary arrays, storage for long-term state, and leverage fixed-size variables to optimize stack usage and minimize gas consumption.
Tools for Analyzing Execution
Understanding the EVM's step-by-step execution is critical for debugging, gas optimization, and security auditing. These tools provide visibility into opcodes, storage, and transaction flow.
Frequently Asked Questions
Common developer questions about the Ethereum Virtual Machine's transaction lifecycle, from submission to state change.
The Ethereum Virtual Machine (EVM) is a global, deterministic state machine that executes smart contract code. When a transaction is submitted, the EVM processes it through a defined flow:
- Transaction Validation: The network checks the signature, nonce, and sender balance.
- Gas Calculation: The EVM computes the maximum
gasLimitthe sender is willing to pay. - Execution Context: A new EVM instance is created with the transaction data,
msg.sender, andmsg.value. - Opcode Execution: The contract's bytecode is executed step-by-step. Each opcode (e.g.,
ADD,SSTORE) has a predefined gas cost. - State Transition: If execution succeeds, the world state (account balances, storage) is updated. If it runs out of gas or reverts, all changes are discarded, but the sender may still pay for gas used.
The EVM's stack-based architecture and isolation ensure deterministic outcomes across all nodes.
Further Resources
These resources expand on how EVM execution works at the opcode, transaction, and client level. Each card focuses on a different layer of the execution flow so you can move from theory to hands-on debugging.
Conclusion and Next Steps
You have now traced the complete journey of a transaction through the EVM, from the initial RPC call to the final state update.
Understanding the EVM execution flow is foundational for smart contract development, security auditing, and building robust infrastructure. The key stages are: - Transaction Propagation: A signed transaction is broadcast to the network. - Block Inclusion: A validator selects it for a new block. - Pre-Execution Validation: The EVM checks nonce, gas, and signature. - Bytecode Execution: The contract's opcodes are processed in a sandboxed environment. - Gas Accounting & State Changes: Gas is consumed for each operation, and the world state is updated if execution succeeds. - Transaction Finality: The result is committed to the blockchain.
To deepen your practical knowledge, instrument and observe the flow directly. Use tools like the EVM's built-in tracing. For example, run a transaction with debug_traceTransaction on a local node (Geth, Erigon) to get a step-by-step opcode trace, gas costs, and stack/memory state. Analyze a simple contract interaction, like an ERC-20 transfer, to see how the CALL opcode works and how storage is updated. Reviewing these traces helps you understand gas optimization and debug complex failures.
For next steps, explore advanced topics that build on this foundation. Study gas optimization techniques by analyzing opcode costs. Learn about different EVM clients (Geth, Nethermind, Erigon) and their implementation nuances. Dive into the formal specification in the Ethereum Yellow Paper. To apply this knowledge, consider contributing to client development, writing gas-efficient contracts, or building tools like debuggers and analyzers that interact directly with the EVM's execution layer.