Protocol Deep Dives

Ethereum Virtual Machine (EVM) Internals: Bytecode, Gas Economics & State Trie Mechanics

By NorwegianSpark Editorial — written with AI assistance and reviewed by the NorwegianSpark SA editorial team | Last updated: 2026-03-06

A person working at a laptop with a phone in hand at a café table

This article contains affiliate links. We may earn a commission at no extra cost to you. Full disclosure

An exhaustive analysis of stack execution, memory models, persistent storage slots, EIP-1559 dynamic base fees, and Modified Merkle Patricia Trie state proofs.

The EVM Architectural Machine Model: Stack, Memory & Persistent Storage

The Ethereum Virtual Machine (EVM) is a quasi-Turing-complete, deterministic, stack-based runtime environment that executes the state transition logic of the Ethereum network. Unlike standard register-based CPU architectures (such as x86-64 or ARM64) that operate on 32-bit or 64-bit hardware registers, the EVM operates exclusively on a native word size of 256 bits (32 bytes). This 256-bit word size was intentionally selected to natively accommodate 256-bit cryptographic hashing outputs (Keccak-256) and elliptic curve scalar arithmetic without requiring multi-word precision overhead.

The EVM execution environment manages four distinct memory regions with radically different volatility, addressing, and cost profiles:

  1. The Stack: A standard Last-In-First-Out (LIFO) stack with a maximum depth limit of 1024 words. Each stack element is 256 bits wide. Opcodes operate primarily on the top items of the stack. Because standard EVM instructions (such as DUP1 through DUP16 and SWAP1 through SWAP16) can only access items within the top 16 stack slots, operations exceeding this depth trigger the infamous Solidity compiler error Stack Too Deep.
  2. Memory: A volatile, linearly expandable byte-array that exists only during the lifetime of a specific message call execution frame. Memory is byte-addressable and initialized to zero. When memory expands past 32 bytes, the protocol imposes an expansion gas penalty that grows quadratically with size:

Costmem(a)=3×a+a2512

where a is the memory size in 32-byte words. This quadratic cost curve strictly prevents malicious smart contracts from exhausting the RAM of physical validator nodes.

  1. Storage: A persistent, key-value mapping associating 2256 32-byte keys to 2256 32-byte values for each smart contract account. Storage persists permanently across blocks and is cryptographically committed to the global state trie. Because storage mutations must be written to disk by every full node, storage access opcodes (SLOAD and SSTORE) are among the most expensive operations in the entire EVM gas schedule.
  2. Calldata: An immutable, read-only byte array containing the hexadecimal payload passed with the transaction (typically containing the 4-byte function selector followed by ABI-encoded arguments).

Contract Storage Slot Layout & Dynamic Mapping Hashing Arithmetic

Because storage is a flat 2256-element key-value array, the Solidity compiler assigns state variables to storage slots deterministically according to their order of declaration:

  • Value Types: Primitive types (such as uint256, address, bool) smaller than 32 bytes are packed into a single 32-byte storage slot when consecutive, reading from right to left (low-order to high-order bytes), optimizing expensive SSTORE writes.
  • Fixed-Size Arrays: Fixed-size arrays of length N allocate N contiguous storage slots starting at the variable's base slot p.
  • Dynamic Arrays: For a dynamic array declared at slot p, slot p stores only the integer length of the array. The actual array elements are stored contiguously starting at the slot computed by hashing the parent slot index:

Slotelem(i)=Keccak256(p)+i

  • Mappings: A mapping declared at slot p stores no length (mappings do not store their keys on-chain). For a key k, the value is stored at the 256-bit slot derived from the concatenated hash:

Slotval(k,p)=Keccak256(kp)

For nested mappings mapping(k1 => mapping(k2 => v)), the slot is computed recursively:

Slot=Keccak256(k2Keccak256(k1p))

This cryptographic pseudo-random distribution guarantees that dynamic arrays and mapping keys will never collide across the vast 2256 addressable storage universe.

Gas Economics, Berlin Warm/Cold Access & EIP-1559 Mechanism

Gas serves as the fundamental resource metering currency of the EVM, solving the Turing halting problem by guaranteeing that infinite computational loops cannot freeze the network. Every transaction specifies a gas limit; if the execution exhausts the allocated gas before completion, the EVM reverts all state changes while still collecting the consumed gas fee to compensate miners/validators for computational expenditure.

EIP-2929 (introduced in the Berlin hard fork) revolutionized EVM storage pricing by introducing the concept of Warm vs. Cold access to deter state-access DoS attacks:

  • COLD_SLOAD_COST: 2,100 gas for the first time a storage slot is read in a transaction.
  • WARM_SLOAD_COST: 100 gas for subsequent reads of the same storage slot within the same transaction context.
  • COLD_ACCOUNT_ACCESS_COST: 2,600 gas for the first time an external contract address is called or checked.

In London (EIP-1559), Ethereum overhauled the transaction fee market by replacing the legacy first-price auction with a dual-parameter dynamic pricing mechanism:

FeePerGas=BaseFee+min(PriorityFee,MaxFeePerGasBaseFee)

The BaseFee is adjusted deterministically on a block-by-block basis according to target block gas elasticity (target: 15M gas, hard cap: 30M gas). If a block exceeds the 15M target, the base fee increases by up to 12.5% for the next block:

BaseFeen+1=BaseFeen×(1+18GasUsednGasTargetGasTarget)

Crucially, 100% of the BaseFee is permanently burned (destroyed from the total ETH supply), while only the optional PriorityFee (tip) is awarded to block proposers. This burn mechanism directly links EVM transactional throughput to deflationary monetary pressure on the underlying asset.

The Global State Trie: Modified Merkle Patricia Trie Architecture

The global state of Ethereum is committed to a cryptographically authenticated data structure known as the Modified Merkle Patricia Trie (MPT). The MPT combines the deterministic key-path indexing of a Radix Trie (prefix tree) with the cryptographic integrity verification of a Merkle Tree.

Every Ethereum block header contains three 32-byte Merkle roots:

  1. stateRoot: The root hash of the global State Trie mapping all 20-byte account addresses to account state tuples:

AccountState=(nonce,balance,storageRoot,codeHash)

  1. transactionsRoot: The Merkle root of all transactions included in the block.
  2. receiptsRoot: The Merkle root of all execution receipts, containing event logs and post-transaction status codes.

To optimize path depth and prevent explosive trie growth, the MPT uses four specialized node types:

  • Null Node: An empty trie node.
  • Leaf Node: A 2-item node [encoded_path, value] representing a terminal key-value pair.
  • Extension Node: A 2-item node [encoded_path, child_hash] that collapses common intermediate prefix paths into a single hop, drastically reducing trie depth.
  • Branch Node: A 17-item node [v0, v1, ..., v15, value] with 16 hex nibble children plus a value slot.

Using these cryptographic roots, any light client can verify an account balance or storage slot with a compact Merkle proof (O(logN) branch traversal hashes) without downloading the multi-hundred-gigabyte raw state database.

Message Calls, DELEGATECALL & Context Preservation Dynamics

The EVM executes contract inter-communication through a suite of specialized call opcodes:

  • CALL: Instantiates a new execution sub-context with its own stack and memory, executing target code in the storage and msg.sender context of the target contract.
  • STATICCALL: Introduced in EIP-214, behaves like CALL but strictly reverts if the called code attempts any state-mutating operation (SSTORE, LOG, CREATE, SELFDESTRUCT), guaranteeing read-only safety.
  • DELEGATECALL: Introduced in EIP-7, executes the target contract's bytecode within the caller's storage, balance, and msg.sender context.

DELEGATECALL is the fundamental building block of all modern proxy architectures, upgradability patterns, and modular diamond standards (EIP-2535). However, because the target implementation executes directly against the proxy's storage slots, any discrepancy between the implementation and proxy storage variable layouts causes catastrophic storage collision bugs that can permanently compromise contract ownership.

Frequently asked questions

What is the EVM "Stack Too Deep" error and how is it resolved?

The EVM only allows direct stack manipulation on the top 16 elements. Exceeding this limit causes compiler errors. It is resolved by scoping variables in sub-blocks, using structs, or storing intermediate values in memory.

Why does EIP-1559 burn the base fee instead of giving it to validators?

Burning the base fee removes economic incentives for validators to collude or artificially simulate fake transactions to keep gas prices high, creating an efficient and predictable fee market.

How does DELEGATECALL preserve msg.sender and storage?

DELEGATECALL loads code from an external contract but executes it in the current contract's environment, preserving msg.sender, msg.value, and directly reading/writing the calling contract's storage slots.

Sources

No contributor to this article holds a professional cryptography or security credential. Every technical claim above is sourced to primary protocol documentation rather than to personal authority — follow the sources and verify anything you intend to act on.

Not financial advice. Crypto assets are volatile and can lose value. This article describes how protocols work, not what you should buy.

Content on AICryptoCoin is for informational purposes only and does not constitute financial advice. Always do your own research and consult a qualified financial advisor before making investment decisions.