Design a cross-institution settlement ledger (many banks, multiple regulators, nobody willing to be the central party): replicate, across mutually distrusting hundreds of nodes, one transaction history that everyone agrees on and no one can unilaterally alter. This is a different threat model from classic distributed systems — Day 5's replication assumes nodes only crash (crash fault), whereas here nodes may actively lie, forge, and collude (Byzantine fault), with no trusted coordinator. Consensus shifts from "make the live replicas agree" to "make a crowd of potential liars agree."
graph TD
C["Client / Wallet
signs tx with private key"]
MP["Mempool
pending tx pool"]
subgraph P2P["P2P node network (gossip broadcast)"]
V1["Validator node
execute+consensus"]
V2["Validator node"]
V3["Validator node"]
end
EVM["State machine / VM
EVM · deterministic exec"]
LDG[("Blockchain ledger
hash chain + Merkle tree")]
OFF[("Off-chain storage
IPFS / Arweave")]
C -->|1 signed tx| MP --> P2P
P2P -->|2 consensus picks leader| EVM
EVM -->|3 state transition| LDG
EVM -.large blobs store only hash.-> OFF
V1 <-.gossip.-> V2 <-.gossip.-> V3
classDef client fill:#1a2530,stroke:#64c8ff,color:#e8eef5
classDef net fill:#0e2030,stroke:#5eead4,color:#e8eef5
classDef exec fill:#1a1a30,stroke:#ffb450,color:#e8eef5
classDef store fill:#2a1530,stroke:#ff7ab6,color:#e8eef5
class C client
class V1,V2,V3,MP net
class EVM exec
class LDG,OFF store
Transactions enter the mempool → P2P network → consensus picks a block producer → the VM deterministically executes to a new state → the hash chain appends. Every full node replays all transactions to verify independently, trusting no producer.
Principle: reaching agreement under Byzantine conditions requires scarce voting power, otherwise an attacker spins up endless fake identities (Sybil attack) to swing votes. PoW uses hash power as the scarce resource (solve a hash puzzle; whoever solves first produces the block). PoS uses staked capital (a stake-weighted random pick of the producer; misbehave and your stake is slashed). BFT-style (PBFT / Tendermint) runs two voting rounds (pre-vote / pre-commit) within a known validator set and commits deterministically once 2/3+ agree.
| PoW (Bitcoin) | PoS (Ethereum) | BFT (Tendermint) | |
|---|---|---|---|
| Scarce resource | hash power | staked capital | known identity + stake |
| Finality | probabilistic (~6 blocks) | ~2 epochs | 1 block |
| Node scale | permissionless, tens of thousands | permissionless, 100k+ validators | usually <200 (O(n²) voting) |
| Energy | very high | very low | very low |
| Cost | slow, power-hungry, 51% attack | nothing-at-stake, rich-get-richer | scale-limited, needs gated identity |
# PoW block production: brute-force a nonce meeting the difficulty (pseudo-code)
def mine(block, difficulty):
target = 2 ** (256 - difficulty)
nonce = 0
while True:
h = sha256(sha256(block.header + nonce)) # Bitcoin double SHA-256
if int(h, 16) < target: # enough leading zeros
return nonce # found -> broadcast block
nonce += 1
# Verification is a single hash (O(1)); production needs ~2^difficulty tries.
# Difficulty auto-adjusts every 2016 blocks, locking ~10-min block interval.
Principle: a smart contract is code deployed on-chain and re-executed by every node. Each full node must compute the exact same result, or the state forks — demanding strict determinism: no true randomness, no reading wall-clock/network, avoid floating point. The EVM is a 256-bit stack machine. Because code may loop forever (the halting problem is undecidable), gas prices every opcode; the caller prepays gas, and running out reverts — both a DoS guard and a price on computation.
// reentrancy bug: transfer before zeroing balance -> recursive re-entry (The DAO 2016)
function withdraw() public {
uint bal = balances[msg.sender];
(bool ok,) = msg.sender.call{value: bal}(""); // ⚠️ callback re-enters withdraw()
balances[msg.sender] = 0; // too late! re-entered before zeroing
}
// Fix — Checks-Effects-Interactions: change state first, then call out
function withdraw() public {
uint bal = balances[msg.sender];
balances[msg.sender] = 0; // ✅ zero first (Effect)
(bool ok,) = msg.sender.call{value: bal}(""); // then transfer (Interaction)
require(ok);
}
Principle: tamper-evidence comes from two hashing layers. A hash chain: each block header contains the previous block's hash, so altering any historical block invalidates every hash after it — the cost to tamper equals redoing all subsequent PoW/consensus. A Merkle tree: the thousands of transactions in a block are pairwise-hashed into a tree whose root goes into the header — so a light node (SPV) needs only an O(log n) Merkle proof to verify "this transaction is in this block" without downloading the full block. That lets a phone wallet skip storing 600GB.
# Merkle proof verification: recompute the root from O(log n) sibling hashes (pseudo-code)
def verify(leaf, proof, root):
h = sha256(leaf)
for sibling, is_left in proof: # bottom-up
h = sha256(sibling + h) if is_left else sha256(h + sibling)
return h == root # root matches -> leaf is in the tree and untampered
# For one tx in a million-tx block, the proof is only ~20 hashes ≈ 640 bytes.
Principle: the "blockchain trilemma" (per Vitalik) says decentralization, security, scalability are hard to have all at once — raising throughput tends to either shrink the node set (lose decentralization) or relax verification (lose security). The mainstream scaling path is the Layer 2 Rollup: execute hundreds-to-thousands of transactions off-chain in a batch, and submit only compressed data + a validity guarantee back to L1, which acts as the settlement and data-availability layer. Two schools: Optimistic Rollup trusts by default but keeps a challenge window (~7 days) for fraud proofs; ZK Rollup uses zero-knowledge proofs (SNARK/STARK) to mathematically prove correct execution, so the main chain finalizes on one verification.
The essence: during a fork, a PoW miner's hash power is physically exclusive — the same rig mining chain A can't simultaneously mine chain B, so betting on a fork splits hash power and carries a real opportunity cost. A PoS validator, however, can sign votes on every fork at near-zero cost (signing barely consumes resources), so the rational strategy is "vote on all of them" to collect rewards no matter which chain wins. The result: nothing converges to a single chain and consensus collapses.
The fix, slashing: the protocol declares "signing two conflicting blocks" a cryptographically provable offense; once reported, the validator's stake is confiscated and they are ejected, turning "vote-on-all is free" into "vote-on-all gets you bankrupted" and restoring the opportunity cost. Second-order effect: validators now risk "fat-fingered double-signing" (misconfig, bugs), which spawned Distributed Validator Technology (DVT) to reduce single-point mis-slashing.
The core constraint is network propagation latency. Broadcasting a block across a global P2P network takes time (seconds). If the block interval approaches propagation latency, two miners produce blocks "before receiving each other's" → frequent forks (orphan/stale blocks). Nakamoto deliberately set the interval to 10 minutes, far above propagation latency, so forks are rare and the chain converges cleanly — at the cost of being slow.
How Solana hits 400ms: Proof of History pre-orders transactions (a cryptographic clock), cutting the "whose turn is it now" coordination overhead, while requiring validators to run high-spec hardware. The cost: a high hardware bar → fewer nodes → decentralization decay; thin fault-tolerance margin, with repeated network-wide halts for hours in 2022 from traffic surges/bugs. This is the trilemma in the flesh: throughput bought with decentralization and stability — fast blocks are spent safety margin.
random() differs per node → state fork. On-chain "randomness" can only use reproducible pseudo-randomness (e.g. block hash), which miners can manipulate (MEV).Breaking determinism doesn't throw an error — it makes different nodes reach different state roots, so consensus can't align → the chain splits. That's why the EVM cuts these sources out at the instruction-set level.
The trap: immutable ≠ won't disappear. The on-chain hash permanently guarantees "if the content for this CID exists, it is the original content" (tamper-evident), but nobody guarantees that content stays stored. IPFS is content-addressed; content is online only while some node actively pins it — if every pinning node goes offline, the content is unretrievable: the hash is still on-chain, pointing into the void. Many early NFT "images disappearing" was exactly the project stopping its pinning service.
vs S3+URL: an S3 URL is location addressing — content can be silently swapped while the URL stays the same — not tamper-evident. An IPFS CID is content addressing — change the content and the CID changes — so tamper-evident but equally without availability guarantees. Both need a "someone keeps storing it" incentive; the only difference is "can tampering be detected." True durability requires Filecoin (storage proofs + incentives) or Arweave (pay once, stored forever), which fold storage availability into the incentive.
Most likely yes, object to mainnet. The consortium wants "members share one tamper-evident, auditable ledger and skip reconciliation," but members are known and regulated — which is precisely where you don't need a permissionless chain's most expensive property: Sybil- and censorship-resistant open consensus. On a public chain you'd also hit: privacy (all transactions public, breaking financial confidentiality), throughput (~15 TPS nowhere near enough), fee volatility, and uncontrollable compliance (assets on an uncontrolled public network).
What to use instead: a permissioned / consortium chain (Hyperledger Fabric, R3 Corda, Quorum) — BFT consensus among known validators for deterministic finality, with orders-of-magnitude higher throughput, private channels, and controllable governance. In essence it gives up "trust no one" for "decentralize within a gated, small trust circle."
When you genuinely need a public chain: when participants can't be determined in advance, distrust each other, and need censorship-/single-shutdown-resistance — e.g. public asset issuance to any global user, trustless cross-border value transfer. A litmus test: if you can write a whitelist of "who may write," you probably don't need a permissionless public chain.