Zeeka saysIn PoS an attacker with old keys can rewrite ancient history because their stake is no longer at risk — the fix is weak subjectivity: trust only a recent enough checkpoint.
PoW chains anchor history to physical work that cannot be cheaply redone. PoS chains do not have that anchor: validators who have already unstaked have nothing left to lose, so they can build an alternate chain from old epochs at near-zero cost. This is the long-range attack, and a naive longest-chain rule would happily switch to the attacker's longer history.
The defense is weak subjectivity: a node refuses to follow any chain that diverges before a recent weak subjectivity checkpoint, typically within the unbonding period (the time after which old validators are no longer slashable). New or returning nodes must obtain such a checkpoint from a trusted source. It is a real cost, but a small one for absolute-finality PoS.
Power-ups you unlock
PoW history is anchored to physical work that cannot be redone cheaply
PoS validators who have unstaked have nothing left to slash
They can build an alternate chain from old epochs at near-zero cost
Defense: weak subjectivity — refuse chains that diverge beyond a recent checkpoint
New or returning nodes must trust a checkpoint within the unbonding period
The Collision attacks — common mistakes
Confusing nothing-at-stake with the broader long-range attack
Assuming a longest-chain rule is sufficient in PoS — it is not
Choosing an unbonding period shorter than expected node downtime
Treating weak subjectivity as a flaw rather than a deliberate trade-off
Boss battleSimulate an attacker building a longer chain from old keys and show how a recent checkpoint rejects it.
Example code
<!doctype html><html><head><meta charset="utf-8"></head>
<body style="background:#06040d;color:#e6e0ff;font-family:monospace;padding:20px"><pre id="o"></pre>
<script>
// long-range attack: old unstaked keys forge a longer chain from epoch 0.
// defense: refuse any chain diverging before a recent checkpoint.
const honestLen = 50, attackerLen = 60;
const weakSubjectivityCheckpoint = 40; // last finalized epoch trusted
const naiveAccepts = attackerLen > honestLen;
const safeAccepts = naiveAccepts && 0 >= weakSubjectivityCheckpoint;
document.getElementById('o').textContent = [
'honest chain: ' + honestLen + ' epochs',
'attacker chain: ' + attackerLen + ' epochs (built from old, unstaked keys)',
'',
'naive longest-chain rule: would switch to attacker → ' + naiveAccepts + ' (catastrophic)',
'weak-subjectivity checkpoint at epoch ' + weakSubjectivityCheckpoint,
' refuses any chain that diverges before epoch ' + weakSubjectivityCheckpoint,
' attacker chain diverges at epoch 0 → REJECTED',
'',
'cost: new/returning nodes must trust a recent checkpoint (within unbonding period)'
].join('\n');
</script></body></html>