Skip to content

Reorgs

Chapter 43: Chain Reorganizations Handling

Section titled “Chapter 43: Chain Reorganizations Handling”

Chain reorganizations (reorgs) are fundamental to how blockchains function. They occur when the network discovers a new chain that is longer or more valid than the current chain, causing nodes to revert to a previous state and follow the new fork. Understanding and properly handling reorgs is essential for building robust blockchain applications.


A chain reorganization (reorg) occurs when a blockchain node must switch to a different chain because the network has reached consensus on a new chain that differs from what the node previously accepted.

┌─────────────────────────────────────────────────────────────────────────────┐
│ CHAIN REORGANIZATION EXAMPLE │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ BEFORE REORG: │
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │Genesis│───▶│ B1 │───▶│ B2 │───▶│ B3 │ (current head) │
│ └─────┘ └─────┘ └─────┘ └─────┘ │
│ │
│ NEW BLOCK ARRIVES: │
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │Genesis│───▶│ B1 │───▶│ B2 │───▶│ B3 │───▶ B4 │
│ └─────┘ └─────┘ └─────┘ └─────┘ │
│ │ │
│ ▼ │
│ CONFLICT! Another B4' arrives │
│ with different transactions │
│ │
│ AFTER REORG: │
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │Genesis│───▶│ B1 │───▶│ B2 │───▶│ B3' │───▶ B4' │
│ └─────┘ └─────┘ └─────┘ └─────┘ │
│ │ │
│ └───── B3 and B4 are now discarded (uncle blocks) │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
TypeDepthCauseFrequency
Minor1-2 blocksNetwork latency, block propagationCommon
Medium3-10 blocksValidator issues, network partitionsOccasional
Deep10+ blocksConsensus bugs, majority misbehaviorRare
FinalityN/AProtocol-level finalizationNever (for finalized blocks)

43.2 How Different Consensus Mechanisms Handle Reorgs

Section titled “43.2 How Different Consensus Mechanisms Handle Reorgs”

In PoW networks like Bitcoin and Ethereum Classic, reorgs can occur frequently due to mining competition.

┌─────────────────────────────────────────────────────────────────┐
│ POX REORG CHARACTERISTICS │
├─────────────────────────────────────────────────────────────────┤
│ │
│ PROBABILITY OF REORG: │
│ ━━━━━━━━━━━━━━━━━━━━━━━ │
│ │
│ Block Depth (n) ≈ Probability of Reorg │
│ ┌─────────────┬─────────────────────┐ │
│ │ 1 block │ ~50% (natural) │ │
│ │ 2 blocks │ ~25% │ │
│ │ 3 blocks │ ~12.5% │ │
│ │ 6 blocks │ ~1.5% │ │
│ │ 12 blocks │ ~0.02% │ │
│ └─────────────┴─────────────────────┘ │
│ │
│ Recommendation: Wait for 6 confirmations for significant │
│ transactions │
│ │
└─────────────────────────────────────────────────────────────────┘

In PoS networks like Ethereum 2.0, reorgs are much less frequent due to finality.

┌─────────────────────────────────────────────────────────────────┐
│ PROOF OF STAKE FINALITY │
├─────────────────────────────────────────────────────────────────┤
│ │
│ SLOT (12 seconds) ──▶ EPOCH (32 slots = 6.4 minutes) │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────┐ ┌─────────────┐ │
│ │ Proposed │ │ Checkpoint │ │
│ │ Block │ │ Finalized │ │
│ └─────────┘ └─────────────┘ │
│ │
│ FINALITY: │
│ ━━━━━━━━━ │
│ After 2 epochs (2/3 validators agree): │
│ - Block is finalized │
│ - Cannot be reverted │
│ - Probability of reorg ≈ 0 │
│ │
│ UNFINALIZED BLOCKS: │
│ ━━━━━━━━━━━━━━━━ │
│ - Can experience reorgs up to 2 epochs │
│ - Reorg depth typically 1-12 blocks │
│ │
└─────────────────────────────────────────────────────────────────┘

In Tendermint consensus (Cosmos), blocks are finalized immediately upon receiving 2/3+ pre-commits.

┌─────────────────────────────────────────────────────────────────┐
│ TENDERMINT IMMEDIATE FINALITY │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Each block is finalized as soon as 2/3+ validators │
│ pre-commit: │
│ │
│ ┌─────────┐ │
│ │ Block N │ ──▶ 2/3+ Pre-commits ──▶ FINALIZED │
│ └─────────┘ │
│ │
│ Key Points: │
│ ━━━━━━━━━━━━━━ │
│ - No probabilistic finality │
│ - Reorgs only possible during same height │
│ - Rare "soft reorg" scenarios (same block height) │
│ │
└─────────────────────────────────────────────────────────────────┘

// JavaScript/TypeScript - Detecting reorgs
class ReorgDetector {
constructor() {
this.lastBlockNumber = null;
this.lastBlockHash = null;
}
async checkBlock(block) {
// Block number decreased = reorg occurred
if (this.lastBlockNumber && block.number < this.lastBlockNumber) {
console.log(`Reorg detected! Block ${block.number} < ${this.lastBlockNumber}`);
await this.handleReorg(block.number);
return;
}
// Block number same but hash different = same-height reorg
if (this.lastBlockNumber === block.number &&
block.hash !== this.lastBlockHash) {
console.log(`Same-height reorg detected for block ${block.number}`);
await this.handleReorg(block.number);
return;
}
this.lastBlockNumber = block.number;
this.lastBlockHash = block.hash;
}
async handleReorg(newHeadNumber) {
// Rollback database to new head
await this.rollbackDatabase(newHeadNumber);
// Clear cached data after new head
await this.clearCache(newHeadNumber);
// Re-fetch blocks from new head
await this.refetchBlocks(newHeadNumber);
}
}
# Python - Handling reorgs
class ReorgHandler:
def __init__(self, db):
self.db = db
self.last_block = None
async def on_new_block(self, block):
# Check for reorg
if self.last_block:
if block['number'] < self.last_block['number']:
# Reorg detected - rollback
await self.handle_reorg(block['number'])
elif (block['number'] == self.last_block['number'] and
block['hash'] != self.last_block['hash']):
# Same-height reorg
await self.handle_reorg(block['number'])
self.last_block = block
await self.process_block(block)
async def handle_reorg(self, new_head):
# Remove blocks after new head
await self.db.rollback_to_block(new_head)
# Clear mempool
await self.mempool.clear()
# Re-sync from new head
await self.sync_from(new_head)

In PoW, blocks that are replaced become “uncle” blocks but still get rewards.

┌─────────────────────────────────────────────────────────────────┐
│ UNCLE BLOCKS │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Main Chain: │
│ ┌────┐ ┌────┐ ┌────┐ ┌────┐ │
│ │ A │──▶│ B │──▶│ C │──▶│ D │ │
│ └────┘ └────┘ └────┘ └────┘ │
│ │ │
│ └──▶ ┌────┐ (Uncle - got orphaned) │
│ │ B' │ │
│ └────┘ │
│ │
│ Uncle rewards: │
│ ━━━━━━━━━━━━━━ │
│ - Uncle block gets ~87.5% of block reward │
│ - Including uncle increases main block reward │
│ │
└─────────────────────────────────────────────────────────────────┘
# Handling same-height reorgs (rare in PoS)
async def handle_same_height_reorg(block_hash_1, block_hash_2):
"""
When two different blocks at same height are proposed.
This can happen due to:
- Proposer misbehavior
- Network partition
- Timing issues
"""
# Compare block timestamps
block_1 = await get_block(block_hash_1)
block_2 = await get_block(block_hash_2)
# Keep the one that arrived first or has more attestations
if block_1.timestamp < block_2.timestamp:
return block_hash_1
else:
return block_hash_2

// Best practices for transaction confirmations
const CONFIRMATION_BLOCKS = {
ethereum: {
regular: 12, // ~3 minutes for regular transactions
defi: 64, // ~16 minutes for DeFi transactions
high_value: 128, // ~32 minutes for high-value transactions
},
polygon: {
regular: 128, // ~4 minutes
defi: 512, // ~17 minutes
}
};
async function confirmTransaction(txHash, value) {
const network = 'ethereum';
const confirmations = value > 1000000 ? 'high_value' : 'regular';
const required = CONFIRMATION_BLOCKS[network][confirmations];
return await waitForConfirmations(txHash, required);
}
-- Use database transactions to handle reorgs safely
BEGIN TRANSACTION;
-- Check current state
SELECT block_number FROM chain_state WHERE id = 1;
-- If reorg detected, rollback
DELETE FROM transactions WHERE block_number > :new_head;
DELETE FROM logs WHERE block_number > :new_head;
DELETE FROM receipts WHERE block_number > :new_head;
-- Update chain state
UPDATE chain_state SET block_number = :new_head WHERE id = 1;
COMMIT;

QuestionAnswer
What is a chain reorg?When a node switches to a different chain due to network consensus
How does Ethereum handle reorgs?Uses checkpoint finality - after 2 epochs, blocks are finalized
How deep can reorgs be in PoS?Typically 1-12 blocks before finality
How do you detect a reorg?Monitor block number/header changes - decrease indicates reorg
What are uncle blocks?Valid blocks that were orphaned due to reorg

  • Reorgs are normal blockchain behavior
  • Different consensus mechanisms have different reorg characteristics
  • PoS has finality, making deep reorgs impossible
  • Applications must handle reorgs by monitoring block changes
  • Database transactions should be used for safe rollback

In Chapter 44: Snapshot Management, we’ll explore blockchain snapshots.


Last Updated: 2026-02-20