How Ethereum Works: The EVM and Smart Contracts
A technical walkthrough of Ethereum's execution model — the EVM, gas, accounts, and how smart contracts actually run.
Ethereum in One Sentence
Ethereum is a decentralized virtual computer — a global state machine replicated across thousands of nodes, where state transitions are triggered by transactions and enforced by consensus.
The Account Model
Ethereum has two types of accounts:
| Type | Controlled by | Has code? | Examples |
|---|---|---|---|
| EOA (Externally Owned) | Private key | No | Your wallet |
| Contract | Code | Yes | Uniswap, USDC |
Both account types store:
balance— ETH in weinonce— transaction counter (prevents replays)storageRoot— hash of contract's persistent storagecodeHash— hash of bytecode (empty for EOAs)
The EVM (Ethereum Virtual Machine)
The EVM is a stack-based, 256-bit virtual machine. It processes opcodes that manipulate a stack, memory, and persistent storage.
// This Solidity...
uint256 x = 5 + 3;
// ...compiles to EVM opcodes:
PUSH1 0x05 // push 5 onto stack
PUSH1 0x03 // push 3 onto stack
ADD // pop both, push result (8)Storage vs Memory vs Stack
| Location | Scope | Cost | Size |
|---|---|---|---|
| Stack | Current call | Cheapest | 1024 slots |
| Memory | Current call | Cheap | Unbounded (grows) |
| Storage | Persistent | Expensive | 2^256 slots |
Gas: The Cost of Computation
Every EVM opcode costs gas. Gas has two purposes:
- Compensate validators for computation
- Prevent infinite loops (if you run out of gas, execution reverts)
// Gas-expensive: writing to storage (SSTORE = 20,000 gas)
mapping(address => uint256) public balances;
// Gas-cheap: reading from storage (SLOAD = 100 gas)
uint256 bal = balances[msg.sender];After EIP-1559, gas fees split into a base fee (burned) and a priority tip (to validators). You no longer bid blindly — the base fee adjusts algorithmically to target 50% block fullness.
Writing a Smart Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
contract SimpleVault {
mapping(address => uint256) private _balances;
event Deposit(address indexed user, uint256 amount);
event Withdraw(address indexed user, uint256 amount);
function deposit() external payable {
_balances[msg.sender] += msg.value;
emit Deposit(msg.sender, msg.value);
}
function withdraw(uint256 amount) external {
require(_balances[msg.sender] >= amount, "Insufficient balance");
_balances[msg.sender] -= amount;
// Checks-Effects-Interactions: update state BEFORE external call
(bool ok, ) = msg.sender.call{value: amount}("");
require(ok, "Transfer failed");
emit Withdraw(msg.sender, amount);
}
function balanceOf(address user) external view returns (uint256) {
return _balances[user];
}
}The Transaction Lifecycle
- You sign a transaction with your private key
- Broadcast it to the mempool
- A validator picks it up and includes it in a block
- The EVM executes the transaction, updating state
- The new state root is committed to the chain
Consensus: Proof of Stake
Since the Merge (2022), Ethereum uses Proof of Stake:
- Validators stake 32 ETH as collateral
- They're randomly selected to propose and attest to blocks
- Dishonest behavior is penalized via slashing (losing staked ETH)
The switch from PoW to PoS reduced Ethereum's energy consumption by ~99.95%.
Conclusion
Ethereum's power comes from combining a global state machine, a Turing-complete VM, and crypto-economic incentives into a trustless execution environment. The EVM's gas model and account structure are the primitives everything else — DeFi, NFTs, DAOs — is built on.