The Two Ways to Lie With a Vote

You've just finished migrating your validator to a new client. Both instances are live for about forty minutes longer than they should be. Both attest. Different target blocks, same epoch. Somewhere on the network, another node quietly assembles your two signed messages into a proof, and the chain does what the chain does.

But which slashing condition just fired?

Casper FFG, the finality gadget baked into Ethereum's proof-of-stake consensus, defines two separate slashable offenses, and they are not the same thing dressed up differently. One is about voting twice in the same slot. The other is about using one vote to quietly contradict an older one by wrapping around it. The attack vectors they close are genuinely different, and conflating them is the kind of mistake that costs real ETH.

What Casper FFG Is Actually Doing

Casper the Friendly Finality Gadget works on top of a block-producing layer (originally a proof-of-work chain in the research phase, today the LMD-GHOST fork-choice rule in Ethereum's beacon chain). Its job is finality: taking the probabilistic "longest chain" assurance and converting it into something cryptographically irreversible.

It does this through a two-phase commit. Validators cast votes linking a source checkpoint to a target checkpoint. Once two-thirds of the validator set votes for the same source-target pair, that link is justified. Once a justified checkpoint itself has a justified child, the parent becomes finalized. Finalized means gone. No honest chain can ever reorg past it.

A vote is a signed tuple: `(source_epoch, source_hash, target_epoch, target_hash)`. The slashing conditions are constraints on what combinations of these tuples a single validator is allowed to broadcast.

Double Votes: The Straightforward Crime

The first condition is the simpler one. A validator is slashed if it signs two distinct votes that share the same target epoch but point to different target blocks.

Formally: slash if `vote_A.target_epoch == vote_B.target_epoch` and `vote_A != vote_B`.

Equivocation. The validator is saying, in the same epoch, both "block X is the target" and "block Y is the target," which is the checkpoint equivalent of signing two contradictory contracts on the same afternoon. It cannot be a miscommunication. The signature is the statement.

Here's the concrete scenario. Validator 0x4F2a is running two client instances after a botched migration. Both are live simultaneously. Both cast attestations for epoch 104, but the first sees a slightly different view of the chain and targets checkpoint A, while the second targets checkpoint B. Any node that sees both signed messages can construct a slashing proof on-chain. The validator loses a portion of its 32 ETH stake immediately, gets forcibly exited, and faces a further correlation penalty scaled to how many other validators were slashed in the same window. If 0x4F2a is the only casualty, the penalty is modest. If hundreds go down together, the correlation penalty can reach the full stake.

Detecting this is straightforward: check whether two signatures from the same validator share a target epoch.

Surround Votes: The Subtler Weapon

The surround vote condition is where the geometry gets interesting.

A validator is slashed if it signs two votes where one vote's source-to-target span surrounds the other's span.

Formally: slash if `vote_A.source_epoch < vote_B.source_epoch` and `vote_B.target_epoch < vote_A.target_epoch`. Vote A's interval contains vote B's interval entirely. The surrounding vote wraps around the surrounded one like a pipe fitting over a smaller pipe, sealing off any way to claim the inner span is independent.

Why is that dangerous? Walk through it.

Suppose a validator casts vote A: source epoch 10, target epoch 20. Later, under some attack scenario or client manipulation, it casts vote B: source epoch 12, target epoch 18. Vote B sits entirely inside vote A's span. The problem is that vote B implicitly claims epoch 12 is a better starting point than epoch 10 and that epoch 18 is sufficient as a target rather than epoch 20. If both votes reach different parts of the network, an attacker can potentially construct two conflicting justified chains: one using the outer vote to justify one fork, one using the inner vote to justify another. The surround structure is precisely what enables a long-range reorg attempt against already-justified checkpoints.

The practical danger is this. Say validator 0x9C11 participated honestly for years, then its key is compromised. The attacker replays old blocks to a segment of the network and needs to justify an alternative chain rooted before a recent finalized checkpoint. To do it, they need the compromised validator to sign a vote with a very wide span that surrounds votes it already cast during normal operation. Cast source 5, target 200 while the validator previously signed source 80, target 120, and the inner vote is surrounded. Slashable. The proof is just the two signed messages.

Detecting surround votes is computationally heavier than detecting double votes. A naive check requires comparing every new vote against every historical vote for the same validator. The major client implementations, Prysm, Lighthouse, Teku, Nimbus, Lodestar, all maintain a slashing protection database: a local record of every source and target epoch the validator has previously signed. Before signing anything, the client queries this database. EIP-3076 exists specifically so validators can migrate between clients without losing this protective history.

Lose the slashing protection database, migrate without exporting it, and you risk signing a surround vote on your first attestation with the new client.

That database is not optional bookkeeping. It is the mechanism by which the surround-vote condition is practically enforced at the client level, before anything reaches the chain. Think of it as the pressure relief valve in the system: invisible when it works, catastrophic when it's missing.

What People Get Wrong About These Two Conditions

The most common misconception is treating slashing as a single catch-all penalty for misbehaving. It isn't, and the distinction actually matters.

Double votes attack the current finality process: a validator voting for two competing targets in the same epoch can help justify two competing forks simultaneously, breaking the two-thirds supermajority guarantee. Surround votes attack historical finality, retroactively undermining justified checkpoints the network already treated as settled. One is vandalism; the other is an attempt to rewrite what already happened.

People also equate slashing with catastrophic loss by default, and that's wrong too. The immediate penalty for a first-offense slash is 1/32 of the validator's effective balance. On a 32 ETH stake, that's 1 ETH, not a wipeout. What scales the damage is the correlation penalty. Slashed alone, you survive with a forced exit and a modest loss. If a coordinated attack slashes 33% of validators simultaneously, the correlation penalty reaches 100% of stake for all of them. The formula is deliberately designed this way: honest accidents hurt a little, coordinated attacks are supposed to be financially ruinous. That asymmetry is a policy choice, and it's the right one.

One more thing worth correcting: the conditions are not symmetric. A double vote requires two messages with the same target epoch. A surround vote requires two messages where one interval contains the other, meaning the target epochs are different. You can have a surround without a double, and a double without a surround.

The Whistleblower Mechanic

Neither condition enforces itself. Someone has to submit the proof.

Any node on the network can package the two conflicting signed messages into an `AttesterSlashing` object and include it in a beacon block. The block proposer who includes a valid slashing proof receives a small reward, a fraction of the slashed validator's penalty. So there's a market for slashing detection: independent services and dedicated slasher nodes run by large staking operators scan the mempool and the chain specifically hunting for slashable pairs. A bounty system, embedded directly in the protocol.

For a solo staker running one validator at home, the practical upshot is simple: never run two validator keystores simultaneously, always export your slashing protection database before switching clients, and treat that EIP-3076 JSON file with the same care you'd give a seed phrase. The protocol will forgive an honest mistake once, at a price.

What makes the design genuinely elegant is that it doesn't require the protocol to know why you misbehaved. Intent is irrelevant. Two signed messages are sufficient. The math doesn't care about your migration schedule.