How Ethereum Virtual Machine (EVM) Works: Architecture and Opcodes Explained

Introduction

The Ethereum Virtual Machine (EVM) is the computational engine powering Ethereum’s smart contracts, processing billions of dollars in transactions daily. Understanding its architecture— Stack, Memory, Storage, and Opcodes—is essential for developers aiming to optimize smart contract performance.

👉 Explore advanced blockchain tools to streamline your Ethereum development workflow.


Core Components of the EVM

1. Ethereum Virtual Machine (EVM) Overview

The EVM is a deterministic, sandboxed runtime environment embedded in Ethereum clients like Geth and Nethermind. It executes bytecode derived from high-level languages (e.g., Solidity) and updates Ethereum’s global state via:
Stack: LIFO structure handling 256-bit operands (max 1024 elements).
Memory: Volatile, linear storage for temporary data (e.g., arrays).
Storage: Persistent state (256-bit key-value pairs) tied to contract accounts.
Program Counter (PC): Tracks the next opcode to execute.
Gas: Measures computational cost per opcode (e.g., SSTORE costs more than ADD).

Example: A stack underflow error occurs if an opcode like ADD lacks sufficient operands.


2. EVM Opcodes: The Building Blocks

Opcodes are low-level instructions (1-byte each) that manipulate EVM components:

Common Opcodes

Category Examples Function
Arithmetic ADD, MUL Perform calculations.
Control Flow JUMP, JUMPI Enable conditional logic.
Memory/Storage MLOAD, SSTORE Read/write data.

Ethereum-Specific Opcodes

  • CREATE: Deploys a new contract.
  • CALL: Invokes another contract’s function.

👉 Master EVM opcodes with interactive tutorials.


From Solidity to Bytecode: A Step-by-Step Example

1. Compiling a Smart Contract

Consider this Solidity contract:
solidity
contract SimpleStorage {
uint storedData;
function set(uint x) public { storedData = x; }
function get() public view returns (uint) { return storedData; }
}

Compiled bytecode (simplified):
6080604052... // PUSH1 80, PUSH1 40, MSTORE, etc.

2. Bytecode to Opcode Translation

  • 60 80PUSH1 0x80 (pushes 0x80 onto the Stack).
  • 52MSTORE (stores the value in Memory).

Try it: Use evm.codes to decompile bytecode.


Transaction Execution Flow

  1. Transaction Decoding
  2. Fields: to (recipient), data (calldata), gasLimit.
  3. Example calldata: 0x60fe47b1... (first 4 bytes = function selector for set()).

  4. EVM Execution Steps

  5. Validate signature and nonce.
  6. Create Stack/Memory context.
  7. Execute opcodes sequentially (e.g., PUSH, SSTORE).

Gas Tip: Storage ops (SSTORE) cost ~20,000 gas vs. ADD (3 gas).


FAQs

1. Why does the EVM use a Stack?

The Stack’s LIFO design ensures deterministic execution, critical for consensus.

2. How is Memory different from Storage?

  • Memory: Temporary (resets post-transaction), cheaper.
  • Storage: Persistent, modifies blockchain state.

3. What causes “Out of Gas” errors?

Transactions exceeding the gasLimit or complex opcodes (e.g., loops) drain gas.

4. Can I inspect EVM execution?

Yes! Tools like EVM.Codes simulate opcode steps.


Conclusion

The EVM’s architecture—powered by opcodes and gas economics—enables secure, decentralized computation. Dive deeper by experimenting with bytecode decompilers or exploring Ethereum’s Yellow Paper.

👉 Boost your Ethereum skills with curated developer resources.


Additional Resources