Ethereum & the EVM
Bitcoin proved you could agree on a ledger without a coordinator. Ethereum generalized it: instead of a fixed set of transaction types, it gives you a Turing-complete virtual machine, so the rules for moving state can be arbitrary programs. That single change turned a payments network into a platform, and it's why "EVM-compatible" has become the closest thing the space has to a standard.
The Ethereum Virtual Machine is a stack-based, deterministic, single-threaded machine that every node executes identically. It has no I/O, no clock beyond block data, no randomness, and no concurrency — all deliberate, because thousands of independent machines must arrive at the same state root. What it does have is a metering system: every opcode costs gas, the sender pays for it, and an execution that runs out of gas reverts. That's what makes running untrusted code on a public network economically safe.
TL;DR
- Two account types: EOAs (controlled by a private key) and contract accounts (controlled by code).
- The EVM is deterministic, single-threaded, and sandboxed — no network, no filesystem, no true randomness.
- Gas meters execution.
gas_used × gas_priceis the fee; running out reverts all state changes but still costs the gas spent. - EIP-1559 splits fees into a burned base fee (set by protocol, responds to congestion) and a priority fee (tip to the proposer).
- Only EOAs initiate transactions. Contracts act only when called; nothing runs on a schedule.
- Storage is the expensive resource — an SSTORE to a new slot costs 20,000 gas; arithmetic costs 3.
- The mempool is public, which makes transaction ordering an attack surface (MEV).
- Proof of stake since the Merge; account abstraction (ERC-4337, EIP-7702) is reshaping what a "wallet" means.
Quick Example
Reading and writing chain state with viem, the modern TypeScript client:
The read/write asymmetry is the most important thing in that snippet: reads are free local queries against a node's state, writes are signed transactions that cost money, take time, and can fail.
Core Concepts
Accounts
Every state change begins with an EOA signing a transaction. A contract can call other contracts, but the chain of calls always originates from an EOA paying gas. There is no cron, no background job, no self-triggering contract — automation on Ethereum means someone off-chain sends a transaction (keepers, relayers, or the user).
The EVM execution model
The 256-bit word size exists because it matches keccak-256 output and elliptic-curve field sizes. It has a practical consequence developers meet constantly: uint8 is not cheaper than uint256 on the stack, and packing small types into one storage slot is what saves gas.
Gas
Gas decouples computational cost from the volatile price of the currency. Each opcode has a fixed gas cost; the market prices gas.
The lesson is unambiguous: storage dominates. Optimizing gas is almost entirely about touching fewer storage slots, packing what you do store, and moving data into events or calldata where possible.
EIP-1559 fees
The practical benefit over the old first-price auction is far better fee estimation: the base fee is known in advance for the next block, so wallets can predict cost instead of guessing.
Transaction lifecycle
Step 2 is where an entire adversarial economy lives. Your pending transaction is visible to everyone before it executes.
MEV
Maximal Extractable Value is profit available from choosing the order, inclusion, or exclusion of transactions in a block.
Defenses that actually work: set tight slippage limits on swaps, use a private transaction relay (Flashbots Protect and similar) so your transaction skips the public mempool, use commit-reveal for anything auction-like, and avoid designs whose profitability depends on ordering.
Ecosystem Standards
The ERC standards are what make wallets, explorers, and marketplaces interoperate:
Account abstraction
Traditional EOAs are rigid: one key, no recovery, gas must be paid in ETH, and every action needs a separate signature. Account abstraction makes the account itself programmable.
- ERC-4337 introduces
UserOperations in a separate mempool, processed by bundlers, enabling smart-contract wallets with social recovery, session keys, batched actions, and paymasters that let a dapp sponsor gas or accept payment in any token. - EIP-7702 lets an existing EOA temporarily execute as a smart account within a transaction, bringing much of the same capability to the addresses people already have.
For application developers this is the most consequential UX change in years: sponsored gas and batched approve-and-swap in one signature remove the two biggest onboarding obstacles.
Best Practices
Simulate before sending
simulateContract (or eth_call against the pending state) runs the transaction without committing it and surfaces the revert reason. Sending blind means paying gas to learn that a require failed.
Never build a fee estimate on a fixed gas price
Gas prices vary by orders of magnitude. Use estimateFeesPerGas per transaction, add a buffer to maxFeePerGas so a base-fee spike doesn't strand the transaction, and expose the estimate to the user before they sign.
Wait for the confirmation depth the value deserves
One confirmation is not final. For anything that triggers irreversible off-chain action, wait for a depth appropriate to the value at risk — and on Ethereum, consider waiting for finality rather than a confirmation count.
Read from events, not by scanning storage
Contract events are indexed and cheap to query; reconstructing history by reading storage across blocks is not feasible at scale. For any real application, run or subscribe to an indexer (The Graph, Ponder, or your own log-following service) and serve the UI from a normal database. See Web3 Frontends.
Handle nonce management explicitly in backends
An EOA's transactions execute in strict nonce order. A backend sending concurrent transactions from one account will produce gaps or replacements. Serialize sends per account, or use a transaction manager that tracks and re-broadcasts.
Use a dedicated RPC provider, and more than one
Public RPC endpoints rate-limit aggressively and behave inconsistently. Use a provider (Alchemy, Infura, QuickNode) with a fallback configured, and treat RPC as a dependency that will fail — because it does.
Keep chain data off the critical read path
A UI that awaits an RPC round trip for every value is slow and fragile. Cache aggressively, serve reads from an indexer, and reserve direct chain reads for values that must be current at the moment of signing.
Common Mistakes
Assuming contracts run on their own
Using tx.origin for authorization
Hardcoding gas prices
Sending a swap without slippage protection
Reconstructing state by scanning blocks in the client
Ignoring decimals
FAQ
What does "EVM-compatible" actually mean?
That the chain runs the same bytecode and exposes the same JSON-RPC interface, so Solidity contracts, wallets, block explorers, and libraries work unchanged. Arbitrum, Optimism, Base, Polygon, Avalanche C-Chain, BNB Chain, and dozens more are EVM chains. This compatibility is the single strongest practical reason to learn EVM development — the skills transfer across most of the ecosystem.
Why is Ethereum so expensive?
Because L1 block space is deliberately scarce: every node must execute and store everything, so capacity is limited to what an ordinary machine can keep up with. Fees ration that capacity. The answer is not to raise L1 capacity — that would centralize validation — but to move execution to layer 2, where transactions cost cents while still settling to Ethereum. Most application development today targets an L2 for this reason.
What changed with the Merge?
Ethereum switched from proof of work to proof of stake, cutting energy use by over 99% and replacing miners with validators who stake ETH and can be slashed for misbehavior. For application developers the changes were mostly subtle: block times became a fixed 12 seconds, block.difficulty became block.prevrandao, and finality became explicit rather than probabilistic. Contract code did not need changes.
Should I run my own node?
Usually not. Providers give you reliable, geographically distributed RPC without operating a machine that needs a terabyte of fast SSD and constant maintenance. Run your own when you need censorship resistance, guaranteed privacy of your queries, archive-level historical data, or very high request volume where provider costs exceed hosting costs.
How do I get test ETH?
From a faucet on a testnet — Sepolia is the current standard for application testing, with Holesky used for staking and infrastructure work. Faucets are often rate-limited and occasionally require a mainnet balance to prevent abuse. Local development is better served by Anvil (Foundry) or Hardhat's node, which give you funded accounts, instant blocks, and mainnet forking.
What is mainnet forking and why does everyone use it?
Your local node fetches state on demand from a real chain, so you can test against live protocols — real Uniswap pools, real token balances, real oracle prices — without deploying anything or spending money. It's the single most useful testing technique in EVM development, because most contract bugs appear at integration boundaries with other protocols rather than in isolated unit tests.
Related Topics
- Blockchain Fundamentals — Consensus, finality, and what a chain guarantees
- Solidity — The language that compiles to EVM bytecode
- Smart Contract Security — Reentrancy, access control, and MEV defenses
- Layer 2 Scaling — Where most Ethereum activity now happens
- Web3 Frontends — Wallets, viem, and indexing
- Zero-Knowledge Proofs — The basis of validity rollups
- Solana — A different execution model for comparison
- TypeScript — The language of most Ethereum tooling
- Blockchain & Web3 — The full hub