Lesson 3 — Ethereum's PoS — Casper FFG + LMD-GHOST
Question
Ethereum PoS is the canonical production deployment of a hybrid consensus design. Casper FFG provides finality; LMD-GHOST provides fork choice. They are two separate protocols composed. Read how they cooperate.
Principle (minimum model)
- Casper FFG = the finality gadget. Validators attest to block pairs (source + target); 2/3 of stake-weighted attestations finalize. Two finalized checkpoints = the chain is finalized between them.
- LMD-GHOST = the fork-choice rule. Latest Message Driven Greedy Heaviest Observed Sub-Tree. Picks the heaviest sub-tree based on the latest attestation from each validator. Continuous; doesn't wait for finality.
- Together = finality + fork choice. LMD-GHOST tells you the canonical head right now; Casper FFG eventually finalizes it. Reorgs are possible within the finality window; impossible after.
- Slot + epoch structure. A slot = 12 seconds; an epoch = 32 slots = 6.4 minutes. Casper attests once per epoch; finalization usually within 2 epochs (≈12 minutes).
- Validator duties. Propose (one per slot) + attest (once per epoch) + sync-committee duty (rotating). Missing duties = small inactivity penalty; equivocating = slashing.
- Three finality levels.
latest(unconfirmed) /safe(~32 blocks back, likely finalized) /finalized(~12 minutes, irreversible). Applications pick the right level. - Inactivity leak. When > 1/3 are offline, finality stalls → every epoch the offline stake loses a small amount → eventually the chain self-heals back to > 2/3 online.
Worked example + steps
Ethereum's PoS — Casper FFG + LMD-GHOST
Ethereum doesn't run one consensus protocol. It runs two, stacked. LMD-GHOST decides which block is "the head right now"; Casper FFG decides "what's actually final and can never be reorged." Why two? Because at ~1 million validators, you can't do BFT-style instant finality without melting the network — but you also can't ship a chain where nothing ever truly settles. The hybrid is the compromise.
This lesson takes the hybrid apart so you can read the spec and know what each half is doing.
12 seconds × 32 slots × 2 epochs = 12.8 minutes. The next 4 sections explain why this number.
1. The two protocols
| Protocol | Role | Cadence | Output |
|---|---|---|---|
| LMD-GHOST | Fork choice — "what's the head?" | Every slot (12s) | Probabilistic head |
| Casper FFG | Finality gadget — "what's final?" | Every epoch (~6.4 min) | Finalized checkpoint |
LMD-GHOST runs continuously, picks the tip. Casper FFG runs at epoch boundaries, finalizes older blocks. Both rely on the same validator set — the ~1M ETH stakers.
2. LMD-GHOST in 60 seconds
Latest Message Driven, Greedy Heaviest Observed Sub-Tree. (The mouthful unpacks below.)
Each slot, validators do two things:
- Propose (if it's your slot) — broadcast a block
- Attest — vote on which block you think is the head (an attestation is a signed message naming a block)
The fork choice rule: for each block, count attestations in its subtree (weighted by stake). Pick the subtree with most weight.
Block A (proposed slot N)
├── Block B (slot N+1) ← 60% of attestations in subtree
│ └── Block D (slot N+2)
└── Block C (slot N+1, conflicting fork) ← 40% of attestations
The chain picks B as canonical. C is orphaned.
Key properties:
- "Latest Message": only count each validator's most recent attestation (prevents long-range bribery via old votes)
- "Heaviest Sub-Tree": count the subtree's weight, not just the immediate child (this is the GHOST part — gives weight to uncle confirmations)
The defense: selfish mining. Longest-chain lets a miner with 30% hashpower secretly build a chain and reveal it to orphan others. Heaviest-subtree forces stake-weighted attestations to make this much harder.
3. Casper FFG in 60 seconds
Friendly Finality Gadget.
Every 32 slots (one epoch ~ 6.4 min), the protocol picks the start of that epoch as a checkpoint. Validators vote on which checkpoint they justify.
The rule:
- Justification: 2/3+ of validators (by stake) vote to justify a checkpoint
- Finalization: a justified checkpoint is finalized when the next checkpoint is also justified
So finality takes 2 epochs minimum. After finalization:
- Cannot be reorged — finalized blocks are permanent
- Cannot be slashed away — even Byzantine validators can't undo finality
This is the BFT half of the hybrid. The 2/3+ rule is exactly the 3f+1 quorum from Lesson 1.
This is surround voting or double voting — both are slashable. Penalty depends on correlated slashing (how many other validators were slashed in the same window). Minimum: 1 ETH. Maximum: full stake (32 ETH) if many validators were slashed together.
4. Slashing conditions
Two slashable offenses:
| Offense | What it looks like | Why it's bad |
|---|---|---|
| Double voting | Sign two votes for the same epoch but different checkpoints | Could split-finalize two conflicting checkpoints |
| Surround voting | Sign vote A then sign vote B that "surrounds" A | Can't both be valid without forks |
The math: if no validator double-votes or surround-votes, you can prove safety. So slashing makes attacks economically irrational — attempt = guaranteed loss of stake.
Slashing is cryptographically detectable. Anyone can submit a slashing proof to the chain; the validator's stake gets burned automatically. No trusted oracle needed.
Because an attacker needs to acquire stake (millions of ETH) and then lose it to attack. The cost of attack > value extractable. Stake is the security collateral.
5. The Engine API — where consensus talks to execution
Ethereum splits the node into two processes: a consensus client (CL — Lighthouse, Prysm, etc.) that runs the voting protocol, and an execution client (EL — Reth, Geth, etc.) that runs the EVM and stores state. They communicate over the Engine API — a JSON-RPC interface defined by the Ethereum spec, spoken locally between the two processes on the same machine.
sequenceDiagram
participant CL as Consensus Client (Lighthouse)
participant EL as Execution Client (Reth)
Note over CL: Slot N — I'm the proposer
CL->>EL: engine_forkchoiceUpdated(head, finalized, safe)
CL->>EL: engine_getPayloadV4(payloadId)
EL-->>CL: ExecutionPayload (built block)
Note over CL: Sign + broadcast block
CL->>EL: engine_newPayloadV4(payload)
EL-->>CL: PayloadStatus { VALID }
Three methods do the work:
engine_forkchoiceUpdated— CL tells EL "the chain head is X, finalized is Y, prepare a block on top of X"engine_getPayload— CL asks EL "give me the block you prepared"engine_newPayload— CL tells EL "validate this block I received from another proposer"
Reth implements the EL side of this. That's where consensus integration happens.
🔍 Find in repo. Open reth's engine crate and find the
engine_newPayloadhandler. Trace what happens when it returns VALID — what does the EL commit to disk before responding?
6. Why this matters for your L1
If you're building Tempo-class L1:
- Probably not running Ethereum's CL — you have your own validator set, different slot times, different finality cadence
- Probably using a Reth-compatible Engine API — so you can swap in different consensus clients
- Definitely need slashing semantics — but customized for your validator set size
The two halves of Ethereum's hybrid (LMD-GHOST + Casper FFG) are the mental model for any new PoS chain. You'll likely simplify (no 1M validators = no need for the gadget split), but the slashing + 2/3+ quorum structure ports directly.
7. Reading list
- Ethereum consensus spec —
specs/phase0/beacon-chain.md - Vitalik's Casper FFG paper — original 2017
- Engine API spec — JSON-RPC interface
8. Practice
Sketch on paper:
- Two competing checkpoints — when does the gadget finalize one over the other?
- A slashing proof — what data is in it? Why is that data sufficient?
- The handshake from CL to EL when a new block arrives from the network
Final check: in two sentences, why is "Ethereum finality takes 13 minutes" not a bug — what does the 13 minutes buy us that 1-second BFT finality wouldn't? If your answer doesn't include "validator decentralization at scale," re-read §1 of this lesson and §3 of last.
🛣️ The road not taken (Solana): Solana's consensus is Tower BFT + Proof-of-History (PoH) — a fundamentally different bet from Gasper. Tower BFT is a PBFT variant where validator votes anchor to a verifiable clock (PoH — a SHA256 hash-chain that serves as a deterministic timeline). Validators don't agree on time first and then vote; PoH is the time, and votes reference points along it. The result: ~400ms finality vs Ethereum's ~13 minutes, at the cost of much higher validator hardware requirements and a single-leader-per-slot model (no per-slot committees, no ~1M validator pool). Gasper trades latency for permissionless validator participation at scale; Tower BFT trades validator-pool size for end-user latency. Both are valid BFT answers; the choice tracks what the chain optimizes for — open participation vs sub-second finality.
Summary (3 lines)
- Ethereum PoS = Casper FFG (finality, 2/3 stake-weighted attestations) + LMD-GHOST (fork choice, heaviest sub-tree). Two protocols composed.
- Slot 12 s + epoch 32 slots; finalization within ~12 minutes. Validator duties: propose + attest + sync committee.
- Three finality levels (latest / safe / finalized) for applications. Inactivity leak self-heals offline-validator scenarios. Next: HotStuff and HyperBFT.