Deep DiveEthereum MPTSubstrate TrieBeginner Friendly

Deep Storage Performance Comparison

A detailed, beginner-friendly guide explaining how different blockchains store data internally, why some are faster than others, what a "Merkle proof" actually is, and every term explained — no jargon left behind.

🔐 Merkle Proofs🌳 Trie Traversal Read / Write Cost📦 Proof Size🔢 RLP Encoding

🔐 1. What is a Merkle Proof?

📖 Plain English:A Merkle proof is a small amount of data that lets you confirm that something (like a transaction or an account balance) is genuinely part of a blockchain, without having to download and check the entire blockchain yourself.
💡
Think of it like a receipt from a restaurant. Instead of reading the full menu and every order ever made, the receipt proves your specific order was placed — and the manager's stamp (root hash) confirms it's real.

What problem does it solve?

Blockchains can have millions of accounts and transactions. If a mobile wallet had to download all of that just to check your balance, it would take hours. Merkle proofs let a light client (e.g. a phone app) ask a full node: "Can you prove my account has 5 ETH?" and get a tiny proof back that it can verify in milliseconds — without trusting the full node blindly.

How does it work — step by step?

1
Build a tree of hashes
All pieces of data (transactions, account states) are hashed individually. Then pairs of hashes are combined and hashed again. This continues until one single hash remains — called the "root hash" or "Merkle root".
2
Root hash goes into the block header
The Merkle root is stored in the block header (a small summary of the block). Everyone trusts the block header because it's secured by the blockchain's consensus (e.g. proof of work or proof of stake).
3
To prove one item, you only need siblings
To prove item B exists, you only need the hash of its sibling A, and the hash of the sibling subtree (H2). From those, you can recompute the root and check if it matches.

Visual — Merkle Tree

MERKLE ROOT0xabc123…H1 = hash(A+B)H2 = hash(C+D)AB ✓CDTo prove B: need hash(A) + H2 only

Blue = proof path. To prove B is in the tree, you only need hash(A) and H2 — not C or D.

What a proof contains in real systems

Ethereum MPT Proof
  • • Multiple trie nodes (branch, extension, leaf)
  • • Each node has up to 16 child references
  • • RLP-encoded (adds byte overhead)
  • • Typical size: 5KB – 15KB
Bitcoin Merkle Proof
  • • A simple list of sibling hashes
  • • One hash per "level" in the tree
  • • Binary tree = fewer levels
  • • Typical size: ~1KB (log₂ n × 32 bytes)

🌳 2. What is a Trie?

📖 Plain English:A Trie (pronounced "try") is a special kind of tree where each path from root to leaf spells out a key. It's like a filing cabinet where the folder hierarchy IS the key itself — you navigate folders one character at a time.
💡
Imagine a dictionary. Instead of a flat list of words, letters are organised as branches. "c → a → t" leads to "cat". "c → a → r" leads to "car". They share the "ca" prefix, saving space and making lookups fast.

Why do blockchains use Tries?

🔐
Cryptographic Proof
Every node is hashed. Any change anywhere changes the root — making tampering detectable.
📍
Efficient Lookup
Find any account's state by traversing the key path — no scanning a list.
🔄
State Snapshots
You can represent the entire world state as a single 32-byte root hash.

Trie vs Regular Tree — Key Difference

trie-concept.txt
1Regular Binary Tree (BST):
2 Node stores: value + left pointer + right pointer
3 Search: compare at each node (balanced = O(log n))
4
5Trie:
6 Node stores: children indexed by KEY CHARACTERS
7 Search: follow the key characters one by one
8
9Example - Ethereum 16-way trie:
10 Key = "a7f3..." (hex characters 0-f)
11 Root → [a] → [7] → [f] → [3] → ... → leaf (account data)
12 Each step: pick the next nibble, follow that branch

🔑 3. How Keys are Formed

📖 Plain English:The "key" is the address used to navigate the trie tree. How you build that key determines how the trie is organised, how fast it is, and how big the proof will be. This is where Ethereum and Substrate differ most fundamentally.

Ethereum: Single Hash Key

💡
Ethereum hashes the address with Keccak-256. This is like taking a name and putting it through a scrambler — you get a random-looking 64-character hex string. The trie must follow all 64 characters one by one. The path is deep and random.
ethereum-key.ts
1// User wants: account data for address 0x742d35...
2// Step 1: Hash the address
3key = keccak256(0x742d35Cc6634C0532925a3b844Bc454e4438f44e)
4 = 0xabc1234567890abc1234567890abc1234567890abc1234567890abc1234567890
5
6// Step 2: Convert to nibbles (each hex char = one nibble)
7nibbles = [a, b, c, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, a, b, c, ...]
8 ↑ ↑ ↑ ↑ total: 64 nibbles
9
10// Step 3: Traverse the 16-way trie, one nibble at a time
11root → [a] → [b] → [c] → [1] → ... → leaf (account state)
12
13// Result: 64 steps deep, completely random order
14// No two related addresses will be "near" each other in the trie

Substrate: Composed Structured Key

💡
Substrate builds the key in parts — pallet name + storage item name + the actual key. This is like an organised filing system: "Finance Department / Salaries / Alice". Related things end up near each other, which is better for caching.
substrate-key.ts
1// User wants: Balances pallet, Account storage, for Alice
2// Step 1: Hash each part separately
3pallet_hash = Twox128("Balances") // = 0x26aa394eea5630e07c48ae0c9558cef7
4storage_hash = Twox128("Account") // = 0xb99d880ec681799c0cf30e8886371da9
5key_hash = Blake2_128Concat(Alice) // = 0xde1e86a9a8c739864cf3cc5ec2bea59f...
6
7// Step 2: Concatenate all parts
8final_key = pallet_hash ++ storage_hash ++ key_hash
9 = 0x26aa394e...b99d880e...de1e86a9...
10
11// Key insight: ALL accounts in Balances pallet share the same PREFIX
12// → they are physically grouped together in the database
13// → cache hits are much more likely when reading multiple accounts
Ethereum Keys — Random
  • • Single keccak256 hash of the address
  • • 64 nibbles long (32 bytes)
  • • Completely random output — no logical ordering
  • • Alice and Bob's accounts are at random spots in the trie
  • ❌ Poor cache locality — every read likely causes a cache miss
  • ✅ Prevents prefix attacks (no predictable ordering)
Substrate Keys — Structured
  • • Pallet hash + storage hash + key hash (concatenated)
  • • Structured and human-readable prefix
  • • All keys in the same pallet share the same prefix
  • • Alice and Bob's accounts are near each other in storage
  • ✅ Great cache locality — reading multiple accounts is fast
  • ✅ Can enumerate all keys of a storage map efficiently

Hash Functions Used — Explained

keccak256 (Ethereum)

A cryptographic hash — extremely secure, output is random-looking. Takes 35–50 CPU cycles per byte. Used for trie node hashing too, so every node access involves a keccak hash.

Used for: Ethereum state/storage key derivation + node hashing

Twox128 (Substrate, non-crypto)

A very fast non-cryptographic hash (xxHash). Not resistant to brute-force key attacks, so it's only used for PALLET and STORAGE names (which are public). ~5× faster than keccak256.

Used for: Pallet name and storage item name prefix hashing

Blake2_128Concat (Substrate, crypto)

A cryptographic hash that ALSO preserves the original key by appending it. This is used for map keys (like AccountId) where the key must be readable from the full storage key.

Used for: Map keys where user-controlled input needs protection


🗂 4. Node Types & How They're Stored in DB

📖 Plain English:Each "node" in the trie is an individual data structure stored as a single key-value pair in the database. How nodes are designed directly affects how many DB reads are needed and how much data is transferred.

Ethereum: 3 Fixed Node Types

💡
At any fork in the path, Ethereum uses a Branch Node — always an array of exactly 17 slots (16 for hex characters 0–f, plus 1 for an optional value). Even if only 2 of the 16 slots are used, all 17 must be stored.
branch-node.ts
1// Branch Node structure — always 17 elements
2[
3 child_0, // reference to child if key[i] == '0'
4 child_1, // reference to child if key[i] == '1'
5 child_2, // ...
6 child_3,
7 child_4,
8 child_5,
9 child_6,
10 child_7,
11 child_8,
12 child_9,
13 child_a,
14 child_b,
15 child_c,
16 child_d,
17 child_e,
18 child_f, // reference to child if key[i] == 'f'
19 value // optional value stored at this node
20]
21// Even if only slots [3] and [7] are used,
22// the other 15 slots still take up space (as empty = 0x80 in RLP)

Why this matters: even a sparse trie wastes space in branch nodes. A typical Ethereum state trie has ~100 million accounts, but most branch nodes only use 2–3 of their 16 slots.

How every node is stored in LevelDB

ethereum-db.ts
1// For EVERY node (branch, extension, leaf):
2DB_key = keccak256(RLP(node)) // 32 bytes — hash of the encoded node
3DB_value = RLP(node) // the full encoded node data
4
5// To look up any node, you:
6// 1. Receive a 32-byte hash reference
7// 2. Do a DB lookup with that hash as key
8// 3. Get back the RLP-encoded node
9// 4. Decode the RLP to get the actual children / value
10
11// Cost per node: 1 DB read + 1 RLP decode + 1 keccak hash verification
12// For a 64-nibble path: up to 64 nodes × (DB read + decode + hash)

Substrate: One Flexible Node Type

📖 Plain English:Substrate doesn't use separate branch/extension/leaf types. Instead, every node is the same flexible structure that can have any number of children (not fixed at 16) and optionally holds a value. This is more compact and efficient.
substrate-node.ts
1// Substrate uses the Patricia Merkle Trie (different from Ethereum's MPT)
2// Node structure:
3Node {
4 partial_key: Vec<u8>, // compressed shared path
5 children: BTreeMap<u8, NodeRef>, // DYNAMIC — only used children stored
6 value: Option<Vec<u8>>, // value if this is a leaf-level node
7}
8
9// Key difference: only USED children are stored
10// If only 2 of 16 positions are occupied, only 2 children exist
11// No wasted space for empty slots
12
13// DB storage:
14DB_key = hash(encoded_node) // 32 bytes
15DB_value = scale_encoded(node) // SCALE codec — more compact than RLP
Ethereum MPT Nodes
  • • 3 separate node types (branch, extension, leaf)
  • • Branch always stores 17 slots (16 children + value)
  • • Empty slots still take space in RLP encoding
  • • Node hash = keccak256(RLP(node))
  • • DB key = 32-byte keccak hash
Substrate Trie Nodes
  • • Single unified node type
  • • Children are dynamic — only used children stored
  • • No wasted space for empty positions
  • • Node hash = Blake2 or Keccak (configurable)
  • • Encoded with SCALE — more compact than RLP

🔢 5. RLP vs SCALE Encoding

📖 Plain English:"Encoding" means converting a data structure (like a node with children and values) into raw bytes that can be stored in a database. The encoding format affects how many bytes are used and how fast encoding/decoding is.

What is RLP? (Ethereum's encoding)

💡
RLP stands for "Recursive Length Prefix". It's a way to encode nested data by prepending the length of each item before the item itself. It was invented specifically for Ethereum and is flexible but not particularly compact.
rlp-example.ts
1// RLP Encoding Example
2// Encoding the string "cat":
3// 1. String length = 3
4// 2. Length prefix = 0x83 (0x80 + 3 for short strings)
5// RLP("cat") = 0x83 0x63 0x61 0x74
6
7// Encoding a list ["cat", "dog"]:
8// 1. Encode each item: 0x83636174, 0x83646f67
9// 2. Total payload length = 8 bytes
10// 3. List prefix = 0xc8 (0xc0 + 8 for short lists)
11// RLP(["cat", "dog"]) = 0xc8 0x83 0x63 0x61 0x74 0x83 0x64 0x6f 0x67
12
13// For a branch node with 16 children:
14// EACH child reference is a 32-byte hash
15// Plus length prefix for each + list prefix
16// Total branch node size: ~600+ bytes even when mostly empty
17
18// Why this is a problem:
19// Every node read = 1 RLP decode operation
20// Deep trie = many decode operations per lookup

What is SCALE? (Substrate's encoding)

💡
SCALE (Simple Concatenated Aggregate Little-Endian) is Substrate's custom encoding format. It's designed to be lean — no extra metadata, no length prefixes where the length is already known from the type. It's 20-40% more compact than RLP.
scale-example.ts
1// SCALE Encoding Example
2// Encoding a u32 integer (e.g. 1000000):
3// SCALE: just the 4 bytes in little-endian
4// SCALE(1000000) = 0x40 0x42 0x0f 0x00
5
6// For a vector of bytes:
7// SCALE: compact-encoded length + raw bytes
8// No nested prefix like RLP — simpler structure
9
10// Substrate node encoding:
11// - partial_key length + partial_key bytes
12// - bitmask of which children exist (2 bytes) ← KEY OPTIMIZATION
13// - only the hashes of EXISTING children
14// - optional value
15
16// Example sparse node (2 children out of 16):
17// RLP would encode 16 slots (mostly empty = 0x80 each) → ~530 bytes
18// SCALE: bitmask (2 bytes) + 2 hashes (64 bytes) → ~70 bytes
19// SCALE is ~7.5x smaller for sparse nodes!
RLP (Ethereum)
  • • Recursive, general-purpose encoding
  • • Prepends length before every value
  • • Empty branch slots = 0x80 each (1 byte × 16 = 16 bytes overhead)
  • • Branch node avg size: ~500-600 bytes
  • ❌ Decode cost on every node access
  • ❌ More bytes = more I/O = slower
SCALE (Substrate)
  • • Flat, optimised binary encoding
  • • Uses bitmask (2 bytes) to mark which children exist
  • • Only existing children stored — zero overhead for empty
  • • Node avg size: significantly smaller
  • ✅ Faster encode/decode
  • ✅ Less data per node = fewer I/O bytes

⚡ 6. Read Performance — Step by Step

📖 Plain English:A "read" is any time you look up state — checking an account balance, reading a contract variable, querying a mapping. This is the most common operation and its speed directly impacts how fast a blockchain can validate transactions.

Ethereum — Read Flow

1
Hash the address
Compute keccak256(address) → 32 bytes. This is a moderately expensive cryptographic operation (SHA-3 family).
2
Convert to nibbles
Split the 32-byte hash into 64 nibbles (half-bytes). Each nibble (0-f) is one step in the trie.
3
Traverse 64 levels
At each level, load the node from LevelDB using its hash as the key. This is a disk read if the node isn't in memory.
4
RLP decode each node
Once a node is loaded from disk, it must be decoded from RLP format before you can read its children/value. CPU cost at every step.
5
Hash verification
To ensure the node wasn't tampered with, its keccak256 hash is recomputed and compared. Another hash per node.
6
Return the leaf value
After traversing ~15-20 nodes on average (many are compressed), the leaf value is RLP-decoded to get the actual account data.
ethereum-read-cost.ts
1// Cost analysis for ONE account read in Ethereum:
2keccak256(address) → 1 hash operation
3convert to 64 nibbles → trivial
4traverse ~15-20 nodes:
5 × 15 DB reads → disk seeks (expensive!)
6 × 15 RLP decodes → CPU work
7 × 15 hash verifications → keccak per node
8final RLP decode (value) → 1 decode
9
10// Total: ~15 disk reads + ~30 keccak operations + ~15 RLP decodes
11// In the WORST case (cold cache, deep path): ~20+ operations

Substrate — Read Flow

1
Build the structured key
Twox128(pallet) ++ Twox128(storage) ++ Blake2(key). Twox is ~5× faster than keccak256.
2
Traverse a shorter path
Because keys are shorter and the trie is more balanced (structured keys, not random), the path from root to leaf typically has fewer nodes.
3
SCALE decode each node (cheaper)
SCALE is faster to decode than RLP. Nodes are also smaller, so less data is loaded from disk.
4
Cache hits are more likely
Because all Balances accounts share a key prefix, they're physically near each other in storage. Reading 10 accounts? The first read warms the OS disk cache for the rest.

Read Cost Comparison

DB Reads per lookup (lower = better)
Ethereum
75%
Substrate
40%
CPU Hashing Cost (lower = better)
Ethereum
80%
Substrate
35%
Encoding/Decoding Overhead (lower = better)
Ethereum
70%
Substrate
30%
Cache Miss Probability (lower = better)
Ethereum
85%
Substrate
35%

Note: bars show relative overhead (higher % = worse). Absolute numbers vary by hardware and state size.


✍️ 7. Write Performance — Why Ethereum Writes are Expensive

📖 Plain English:A "write" happens when you update state — a token transfer, a smart contract execution, changing a vote. Every write must update the trie and recompute hashes all the way up to the root. This is called "hash propagation" and it's expensive.

The Write Cascade Problem

💡
Think of the trie like a pyramid of glass balls where each ball's colour depends on its children's colours. Change one ball at the bottom and EVERY ball above it up to the top must be repainted. That's exactly what happens with cryptographic hash propagation in a Merkle trie.
write-cascade.ts
1// Writing to Ethereum state (e.g. Alice sends Bob 1 ETH):
2
3// Step 1: Update Alice's leaf node
4alice_leaf_new = RLP([nonce+1, balance-1eth, storageRoot, codeHash])
5DB[keccak256(alice_leaf_new)] = alice_leaf_new
6
7// Step 2: Alice's parent branch node now has a new child hash
8parent_branch_new = [...15_children..., NEW_alice_hash, value]
9DB[keccak256(parent_branch_new)] = parent_branch_new
10
11// Step 3: The grandparent now has a new child hash
12// ... repeats all the way to root ...
13
14// Step N: New state root
15new_state_root = keccak256(new_root_node)
16
17// COST per write:
18// depth × (1 RLP encode + 1 keccak256 + 1 DB write)
19// For depth=15: 15 encodes + 15 hashes + 15 DB writes
20
21// Plus: OLD nodes stay in DB (for history) until pruning
22// So every write = 2× DB writes (old + new node versions)

Ethereum Write Cost Factors

🔗Hash Propagation

Every ancestor node must be re-hashed after a leaf changes. Depth of ~15-20 means 15-20 keccak256 operations per write.

💾RLP Re-encoding

Each updated node is re-encoded in RLP before being hashed and stored. CPU cost on every level of the tree.

📋Copy-on-Write Semantics

Ethereum creates new nodes instead of modifying old ones (for history preservation). Each write = new nodes inserted into DB.

🗃️Multiple DB Writes

A single state update results in ~15 new DB entries (one per updated ancestor node), each requiring a disk write.

Substrate Write Improvements

Faster Hash Functions

Substrate can use Blake2b for node hashing (faster than keccak256) or even xxHash for non-security-critical paths.

📦Smaller Nodes = Less Data

Compact SCALE-encoded nodes mean each DB write is smaller. Less I/O bandwidth per write operation.

🎯Fewer Nodes Updated

Flexible node structure (only used children stored) means tree rebalancing is cheaper and fewer nodes need updating.

🔄Overlay Caching

Substrate accumulates writes in an in-memory overlay during block execution, batching all DB writes at block commit time.

Write Cost Comparison

DB Writes per state update (lower = better)
Ethereum
80%
Substrate
45%
Hash operations per write (lower = better)
Ethereum
80%
Substrate
40%
Encoding overhead per write (lower = better)
Ethereum
75%
Substrate
30%
Total CPU cost per write (lower = better)
Ethereum
78%
Substrate
38%

📦 8. Proof Size — Why Ethereum Proofs are Larger

📖 Plain English:A "proof" is all the data you need to send someone so they can verify a value exists in the state — without them having the full state themselves. Smaller proofs = faster light clients, cheaper cross-chain bridges, and lower bandwidth usage.

What goes into a proof?

To prove a value in a Merkle trie, you need every node along the path from root to the leaf, PLUS any sibling nodes needed to recompute parent hashes. The more nodes, and the bigger each node, the larger the proof.

Why Ethereum proofs are large

16-slot Branch Nodes~7.5 KB from branch nodes alone

Every branch node in Ethereum has 16 child slots. Even if only 2 are used, all 16 must be included in the proof (verifiers need all sibling hashes to recompute the parent hash). At 32 bytes per hash × 16 slots = 512 bytes per branch node, and a path has ~15 branch nodes.

RLP Metadata Overhead+500B-1KB overhead per proof

Each node includes RLP length prefixes and type tags. On a typical branch node this adds 50-100 bytes of overhead that carries no data — just encoding metadata.

Path Depth~15-20 nodes per proof path

With 64-nibble paths and random key distribution, the tree is maximally deep. More depth = more nodes = bigger proof.

Proof Size by Blockchain

Bitcoin Merkle~1KB

Binary tree, O(log₂ n) × 32 bytes. ~20 hashes for 1M txs.

Substrate Trie2–8KB

Compact nodes + SCALE encoding. Fewer nodes, smaller nodes.

Cosmos IAVL~3–8KB

AVL tree is balanced — path length is O(log n), similar to Substrate.

Ethereum MPT5–15KB

16-way trie + RLP + random keys = many large nodes in proof.

SolanaN/A

No global state Merkle trie — cannot generate state proofs for light clients.

Verkle Trees (future ETH)~150 bytes

Polynomial commitment — one proof for MANY leaves simultaneously!

Why proof size matters in practice

📱
Light Clients
A mobile wallet proving your balance downloads the proof. 15KB per account × 100 queries = 1.5MB. With Verkle: 150B × 100 = 15KB. 100× cheaper.
🌉
Cross-Chain Bridges
Bridges between chains pass Merkle proofs to verify state on another chain. Smaller proofs = less gas cost for on-chain verification.
🔒
ZK Proofs
Zero-knowledge systems often use Merkle proofs as inputs. Smaller proofs dramatically reduce ZK circuit complexity and proving time.

🌐 9. All Chains — Performance Overview

Bitcoin
UTXO + Binary Merkle
Read Speed
Fast (flat DB lookup)
Write Cost
Low (insert/delete UTXO)
Proof Size
~1KB (binary Merkle)
Key formation:
hash(tx) → binary path
  • No global account trie
  • UTXO spending = simple key delete + insert
  • Proof = O(log₂ n) hashes
Ξ
Ethereum
Merkle Patricia Trie
Read Speed
Slow (16-way, 64 levels)
Write Cost
High (rehash all ancestors)
Proof Size
5–15KB (RLP + branch bloat)
Key formation:
keccak256(address) → nibbles
  • 64-nibble random path
  • RLP encode/decode per node
  • 15+ DB reads per lookup
Substrate
Composed Key Trie
Read Speed
Faster (structured keys, cache)
Write Cost
Medium (compact nodes)
Proof Size
2–8KB (SCALE + sparse)
Key formation:
Twox(pallet)++Twox(storage)++hash(key)
  • Structured keys = cache locality
  • SCALE encoding is more compact
  • Flexible node = less waste
Cosmos
IAVL Tree
Read Speed
Medium (balanced AVL)
Write Cost
Medium (AVL rebalance)
Proof Size
3–8KB (similar to Substrate)
Key formation:
module_prefix + key → AVL path
  • AVL self-balancing = O(log n) guaranteed
  • Versioned — historical queries built-in
  • Rebalancing on writes adds overhead
Solana
Flat Account Store
Read Speed
Very Fast (direct key lookup)
Write Cost
Very Low (direct write)
Proof Size
N/A (no state Merkle)
Key formation:
pubkey → direct DB key
  • No trie at all — pure flat KV
  • Can't generate account state proofs
  • Uses PoH + merkle for tx history only
Verkle (future)
Polynomial Commitments
Read Speed
Medium (256-way tree, shallower)
Write Cost
Medium (polynomial ops)
Proof Size
~150 bytes (!)
Key formation:
address ++ suffix → 256-way path
  • 256-way → tree is much shallower
  • One proof can cover many leaves
  • Enables stateless Ethereum clients

🎯 10. Final Summary & Mental Model

The Core Insight — Why structure matters more than the database

All blockchains use essentially the same underlying database — LevelDB or RocksDB. Both are high-performance key-value stores. The performance difference between Ethereum and Substrate is not the database. It's:

  1. How the key is derived: Random (keccak256) vs structured (pallet+storage+key)
  2. How nodes are designed: Fixed 16-slot arrays vs compact flexible nodes
  3. How data is encoded: RLP (verbose) vs SCALE (compact)
  4. How hashing is done: keccak256 (expensive) vs Twox128+Blake2 (cheaper)

Final Comparison Table

FeatureBitcoinEthereumSubstrateCosmosSolana
Key stylehash(tx)keccak(addr)pallet+storage+keymodule+keypubkey direct
Tree typeBinary Merkle16-way MPTCustom TrieAVL (IAVL)None (flat)
EncodingCustomRLPSCALEProtobuf-likeCustom
Node hashingSHA256keccak256Blake2/keccakSHA256SHA256
Read costVery LowHighMediumMediumVery Low
Write costLowHighMediumMediumVery Low
Proof size~1KB5–15KB2–8KB3–8KBN/A
Historical queriesNoNo*No*✅ Built-inNo
ParallelismUTXO naturalLimitedPer-palletPer-moduleAccount-based
Cache localityGoodPoorGoodGoodExcellent
* Needs archive node for full history

One-Line Summaries (no jargon)

Bitcoin

No account model — just track unspent coins. Simple, fast, can't do smart contracts.

Ethereum

Secure and expressive but heavy — random keys mean poor caching, RLP adds overhead, 16-slot nodes waste space. Security was prioritised over speed.

Substrate

Structured keys act like a namespace. Nearby data stays nearby in storage. Compact encoding reduces I/O. The right trade-off for a developer-first platform.

Cosmos

Self-balancing AVL tree keeps depth predictable. Versioned by design — historical queries are free. Great for multi-chain use cases via IBC.

Solana

Throws out the trie entirely. Direct key-to-account lookup. Maximum speed, minimum overhead — but cannot prove account state to light clients.

Verkle (future)

Uses polynomial math to make proofs 100× smaller. One proof covers many accounts at once. Will make light clients and stateless nodes practical for Ethereum.