Overview — Smart Contracts & Solidity
Every part so far has been building toward one moment: the moment a stranger deploys code to a public address, and from then on anyone can call it, every node runs it identically, and no one — not even its author — can quietly change what it does. That is a smart contract. It is also the sharpest possible answer to the book’s one question: how do untrusting strangers agree on the state of a shared world computer? They agree because the world computer runs the same program the same way for everybody, and the result — the new state — is committed into the same stateRoot every full node computes for itself.
This part builds the smart contract from first principles, in dependency order, and it assumes no prior Solidity knowledge. It leans hard on parts you have already read: the account model (the mutable address→record map), the EVM (the stack machine that executes bytecode), gas (the meter that makes untrusted code safe to run), and the state trie (the 32-byte commitment to all of it). If those four ideas are solid, everything here is a short walk. If they are shaky, this is the part where the shakiness shows — so glance back when a page leans on one.
What actually lives at a contract address
Section titled “What actually lives at a contract address”Start with the smallest true statement. A contract is not a running process, a server, or a daemon waiting for requests. It is inert data sitting in an account record, exactly like a wallet’s balance — except two of the account’s four fields are non-empty:
account at 0xA11ce… account at 0xC0ntract… (a contract) ┌──────────────────────┐ ┌──────────────────────┐ │ nonce : 7 │ │ nonce : 1 │ │ balance : 3.2 ETH │ │ balance : 0.0 ETH │ │ code : (empty) │ │ code : 60 80 60… │ ← bytecode: the program │ storage : (empty) │ │ storage : {0→42, …} │ ← persistent key/value memory └──────────────────────┘ └──────────────────────┘ externally owned account contract accountOur companion crate ethmini makes this precise: an account is four fields, and the presence of code is the only thing that distinguishes a contract from a wallet.
pub struct Account { pub nonce: u64, pub balance: u128, pub storage: BTreeMap<u64, u64>, // real EVM: 256-bit word → 256-bit word pub code: Vec<u8>, // empty = wallet; non-empty = contract}
impl Account { /// Sending a call to an account with code *runs* that code; /// to an account without code, a call is just a value transfer. pub fn is_contract(&self) -> bool { !self.code.is_empty() }}So a “smart contract” is precisely code + storage at an address that every node executes identically. When you send a transaction to a contract, every validator loads that account’s code, runs it on the EVM with your call data as input, applies whatever storage writes it makes, and folds the result into the block’s stateRoot. There is no privileged copy anywhere. The contract is the state, and the state is what everyone agreed on.
That is the whole of it — and the rest of this part is filling in each noun in that sentence: what the code is and where it came from, how a caller says which function to run, how storage is actually laid out, how a contract reports what it did, and how the code got to the address in the first place.
The pipeline this part follows
Section titled “The pipeline this part follows”A running contract is the end of a short pipeline. We walk it in order, because each stage depends on the one before:
Solidity source solc bytecode deploy tx live contract ┌────────────────┐ compiler ┌────────────┐ CREATE / ┌──────────────────┐ │ contract C { │ ─────────────► │ 60 80 60 40 │ ─CREATE2──► │ code+storage at │ │ uint x; │ + ABI (the │ 52 … │ │ 0xC0ntract… │ │ function set… │ call interface)└────────────┘ └──────────────────┘ └────────────────┘ every node runs it- What a contract account is — the account record above, made concrete: EOAs vs. contract accounts, why code is immutable after deployment, and what “calling” one really means. → What a Contract Actually Is
- Solidity source — a high-level language that compiles down to the EVM bytecode you met in the EVM part. We treat Solidity as a convenience over the stack machine, never as magic. → Solidity: A High-Level Language for the EVM
- The ABI and 4-byte selectors — the EVM has no notion of “functions”; a contract is one blob of code with one entry point. The ABI is the off-chain convention, and the 4-byte selector the on-chain trick, that turn one entry point into many callable functions. → The ABI and 4-Byte Function Selectors
- Storage slot layout — the
storagemap above is a flat 2²⁵⁶-slot address space. Solidity’s variables, arrays, and mappings are all just rules for computing a slot number. Getting this right is the difference between a correct contract and a fund-draining bug. → Storage Slot Layout - Events and logs — storage is expensive and unreadable from outside the chain. Events write to a separate, cheaper log structure (committed in the receipts trie) that off-chain apps index. The choice of storage vs. log is a cost decision. → Events and Logs
- Deployment via CREATE / CREATE2 — how the bytecode gets onto an address in the first place, how the address is derived, and why
CREATE2lets you know a contract’s address before it exists. → Deployment: CREATE and CREATE2 - The contract lifecycle — the whole story end to end: authored, compiled, deployed, called, upgraded (or not), and destroyed — and where each earlier page slots in. → The Contract Lifecycle
Roadmap for this part
Section titled “Roadmap for this part”Read these in order. Each page uses only ideas from the pages above it (and from the earlier parts named in the last column).
| # | Page | What it teaches | Depends on |
|---|---|---|---|
| 2 | What a Contract Actually Is | Contract account vs. EOA; code + storage at an address; what “calling” a contract does; why code is immutable | This overview; account model, EVM |
| 3 | Solidity: A High-Level Language for the EVM | Solidity as a convenience over EVM bytecode; state variables, functions, msg.sender/msg.value; what solc emits | Page 2; EVM |
| 4 | The ABI and 4-Byte Function Selectors | How one code entry point becomes many functions: the ABI encoding and keccak256(signature)[0:4] dispatch | Page 3; hashing from cryptography |
| 5 | Storage Slot Layout | The 2²⁵⁶-slot address space; how Solidity assigns slots for values, arrays, and mappings; packing and collisions | Page 3; state trie |
| 6 | Events and Logs | Events vs. storage; topics and data; the receipts trie and Bloom filter; the cost case for logging | Page 5; state & tries |
| 7 | Deployment: CREATE and CREATE2 | The deploy transaction; init code vs. runtime code; address derivation; counterfactual deployment with CREATE2 | Pages 2–6; transactions |
| 8 | The Contract Lifecycle | The end-to-end story tied together, plus upgrade patterns and SELFDESTRUCT’s changing role | All of the above |
| 900 | Revision · Smart Contracts & Solidity | A one-page recap of the whole part, ready for self-testing | — |
The cost lens
Section titled “The cost lens”Hold this in view for the entire part, because it is the second half of the book’s question — what does it cost to run one? Every contract choice you will meet has a concrete, permanent price, paid in gas by the caller and in state growth by every node forever:
- A storage write to a fresh slot is one of the most expensive ordinary operations in the EVM (thousands of gas), and it grows the state trie that every full node must store and re-hash — a cost that never goes away.
- An emitted event is far cheaper than storage and is not part of the state trie, but its gas scales with the bytes logged. Choosing an event over a storage write is a deliberate trade of on-chain readability for cost.
- A deployment pays gas per byte of runtime code stored at the address, on top of the execution cost — so contract size is money, and it is why real contracts fight to stay under the code-size limit.
The recurring exercise of this part is to look at any line of Solidity and ask: what does this cost to execute, and what does it cost the world to remember? A contract that is cheap to write can be ruinously expensive to run, and the gap between the two is exactly what this part teaches you to see.
The thread
Section titled “The thread”Tie it back to the one question. Earlier parts gave you the world computer — accounts, an execution engine, a fee market, and a 32-byte commitment to the whole state. A smart contract is the first thing you build on that computer that a stranger can trust without trusting you: because its code is public and immutable, because every node runs it identically, and because the outcome is folded into a stateRoot that anyone can independently check. The “agree on shared state” half of the question is why contracts can be trusted at all; the “what does it cost” half is why they must be designed with a gas budget in hand. Keep both halves live as you read — every page here is really answering how can untrusting strangers agree on what this code did, and who pays for it?
Start with the account itself: What a Contract Actually Is →
Check your understanding
Section titled “Check your understanding”- In one sentence, what is a smart contract in terms of an Ethereum account record — and which single field’s presence distinguishes a contract account from a wallet (EOA)?
- A smart contract is often described as a “running program,” but that phrasing is misleading. What is actually happening when someone “calls” a contract, and where does the code run?
- The part follows a pipeline from Solidity source to a live contract. Name the stages in order, and say why the ABI/selector stage is needed at all given that the EVM has no built-in notion of “functions.”
- State the cost lens in your own words, and rank these four operations from cheapest to most expensive: stack arithmetic, emitting an event, writing to a fresh storage slot, deploying a byte of runtime code.
- This part claims to build on four earlier parts. Name them, and for each, say the one idea from it that smart contracts directly depend on.
Show answers
- A smart contract is code plus persistent storage sitting at an address that every node executes identically. In the account record, a contract account has a non-empty
codefield; a wallet (externally owned account) has emptycode. The presence of code is the only structural difference — it is what makes a call run something rather than merely transfer value. - Nothing is “running” between calls — the contract is inert data (its
codeandstorage) in the world state. When a transaction targets the contract, every validating node independently loads thatcode, executes it on its own EVM with the transaction’s call data as input, applies the resulting storage changes, and folds the new state into the block’sstateRoot. The code runs on each node, not on any single server, and the agreement is that they all get the same answer. - Order: (2) what a contract account is → (3) Solidity source compiled by
solcto bytecode → (4) the ABI and 4-byte selectors → (5) storage slot layout → (6) events and logs → (7) deployment via CREATE/CREATE2 → (8) the lifecycle. The ABI/selector stage exists because the EVM sees a contract as one blob of code with one entry point; it has no concept of named functions. The 4-byte selector (keccak256(signature)[0:4]) prefixed to the call data, plus the ABI’s off-chain encoding rules, are the convention that lets one entry point dispatch to many “functions.” - The cost lens: every contract operation has a concrete price paid in gas now and, for state changes, in permanent state growth that every node must store forever — so design means budgeting how often you touch expensive operations and how much you leave on-chain. Cheapest → most expensive: stack arithmetic (~3 gas) < emitting an event (hundreds of gas) < deploying a byte of runtime code (200 gas/byte) < writing a fresh storage slot (~20,000 gas). (A single fresh
SSTOREoutweighs deploying ~100 bytes of code, which is why storage is the operation to watch.) - (1) The account model — the mutable address→record map, so a contract can be a thing that persists and remembers. (2) The EVM — the stack machine that executes the bytecode a contract’s
codefield holds. (3) Gas — the meter that makes running arbitrary untrusted code safe and bounded, and that prices every choice in this part. (4) The state trie /stateRoot— the 32-byte commitment that lets every node agree the contract’s storage changes produced the same world.