By @quakewang
Light client (or light node) help users access and interact with a blockchain in a secure and decentralized manner without having to sync the full blockchain
┌──────────────────────┐ ┌──────────────────────┐ ┌──────────────────────┐ ◄──┤parent_hash: H() │◄──┤parent_hash: H() │◄──┤parent_hash: H() │ │transactions_root: H()│ │transactions_root: H()│ │transactions_root: H()│ └──────────────────────┘ └──────────▲───────────┘ └──────────────────────┘ │ │ ◄── merkle tree ┌───┬───┴────┬───┐ │H()│ │H()│ └───┘ └───┘ ┌──┐ ┌──┐ ┌──┐ ┌──┐ │tx│ │tx│ │tx│ │tx│ └──┘ └──┘ └──┘ └──┘
Simple payment verification allows a lightweight client to verify that a transaction is included in the Bitcoin blockchain, without downloading the entire blockchain.
┌──────────────────────┐ ┌──────────────────────┐ ┌──────────────────────┐ ◄──┤parent_hash: H() │◄──┤parent_hash: H() │◄──┤parent_hash: H() │ │transactions_root: H()│ │transactions_root: H()│ │transactions_root: H()│ └──────────────────────┘ └──────────▲───────────┘ └──────────────────────┘ │ │ ┌───┬───┴────┬───┐ │ │ │P │ ◄── merkle tree proof └───┘ └───┘ ┌──┐ ┌──┐ │P │ │tx│ └──┘ └──┘
┌──────────────────────┐ ┌──────────────────────┐ ┌──────────────────────┐ ◄──┤parent_hash: H() │◄──┤parent_hash: H() │◄──┤parent_hash: H() │ │transactions_root: H()│ │transactions_root: H()│ │transactions_root: H()│ └──────────────────────┘ └──────────────────────┘ └──────────────────────┘
Merkle Mountain Ranges
┌─────┐ │Root1│ └─────┘ / \ ┌──────┐ ┌──────┐ │Block0│ │Block1│ Contains Block0 Hash └──────┘ └──────┘
Merkle Mountain Ranges Append
┌─────┐ │Root2│ └─────┘ / \ ┌─────┐ \ │ │ \ └─────┘ \ / \ \ ┌──────┐ ┌──────┐ ┌──────┐ │Block0│ │Block1│ │Block2│ Contains Root1 └──────┘ └──────┘ └──────┘
Merkle Mountain Ranges Append
┌─────┐ │Root3│ └─────┘ / \ ┌─────┐ ┌─────┐ │ │ │ │ └─────┘ └─────┘ / \ / \ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │Block0│ │Block1│ │Block2│ │Block3│ Contains Root2 └──────┘ └──────┘ └──────┘ └──────┘
Merkle Mountain Ranges Append
┌─────┐ │Root4│ └─────┘ / \ ┌─────┐ \ │ │ \ └─────┘ \ / \ \ ┌─────┐ ┌─────┐ \ │ │ │ │ \ └─────┘ └─────┘ \ / \ / \ \ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │Block0│ │Block1│ │Block2│ │Block3│ │Block4│ Contains Root3 └──────┘ └──────┘ └──────┘ └──────┘ └──────┘
/\ Time complexity of append: O(log n) / \ Time complexity of proof generation: O(log n) / \ /\ \ / \ /\ /\ /\ /\ \ /\/\/\/\/\/\/\
Merkle Mountain Ranges: list of perfectly balance binary trees
log2(N) ┌──────mmr proof─────┐ ┌──────────────────────┐ ┌──────────────────────┐ │root: H() │ |root: H() │ ◄── tip mmr root │transactions_root: H()│ │transactions_root: H()│ ◄── tip header └───────────▲──────────┘ └──────────────────────┘ │ │ ┌───┬───┴────┬───┐ │ │ │P │ ◄── merkle tree proof └───┘ └───┘ ┌──┐ ┌──┐ │P │ │tx│ └──┘ └──┘
Tip 1 is a honest chain tip
Tip 2 is a malicious chain with 1/3 hashrate
┌────┐ ──────────────────────────────────────────►│Tip1│ └────┘ ┌────┐ ──────────────────────────────────────────►│Tip2│ └────┘
Sampling constant with binary distribution, 41 times
\[\begin{aligned} ({\frac13})^{41} < 2^{-64} \end{aligned} \]┌────┐ ─┬──────────────────┬───────────┬────┬──┬─►│Tip1│ │ | | | | └────┘ └──────────────────┴───────────┴────┴──┴─ ┌────┐ ─┬──────────────────┬───────────┬────┬──┬─►│Tip2│ │ | | | | └────┘ └──────────────────┴───────────┴────┴──┴─
┌────┐ ─┬──────────────────┬───────────┬────┬──┬─►│Tip1│ │ | | | | └────┘ └──────────────────┴───────────┴──┬─┴──┴─ │ └──────── malicious fork │ ┌────┐ ─┬──────────────────┬───────────┬──┴─┬──┬─►│Tip2│ │ | | | | └────┘ └──────────────────┴───────────┴────┴──┴─
┌────┐ ─┬──────────────────┬───────────┬────┬──┬─►│Tip1│ │ | | | | └────┘ ┬└──────────────────┴───────────┴────┴──┴─ │ └──────── malicious fork │ ┌────┐ ┴┬──────────────────┬───────────┬────┬──┬─►│Tip2│ │ | | | | └────┘ └──────────────────┴───────────┴────┴──┴─
FlyClient: Super-Light Clients for Cryptocurrencies
How the light client gets the transactions it is interested in?
┌──────────────────────┐ │parent_hash: H() │ │transactions_root: H()│ └─────────▲────────────┘ │ │ ┌───┬───┴────┬───┐ │H()│ │H()│ └───┘ └───┘ ┌──┐ ┌──┐ ┌──┐ ┌──┐ │tx│ │tx│ │tx│ │tx│ ◄── input: alice └──┘ └──┘ └──┘ └──┘ output: bob
┌────────────┐ │Light Client├───┬────────────────────────────────────────── └────────────┘ | Send filter (bob) ▲ │ │ ┌────────────┐ ▼ │ Send merkle proof │Full Node ├────────────────────────────────────────────── └────────────┘ │ │ │ │ │ │ ┌──────┐ ┌──────┐ ┌──────┐ │Block1| │Block2| │Block3| └──────┘ └──────┘ └──────┘ | | tx4 (alice send to bob)
┌────────────┐ │Light Client├────────────────────────────────────────────────────┬──────── └────────────┘ ▲ Send filter (all txs) ▲ Send filter | │ │ | Get Block2 ┌────────────┐ | | ▼ │Full Node ├───────────────────────────────────────────────────────────── └────────────┘ │ │ │ │ ┌──────┐ ┌──────┐ │Block1| │Block2| └──────┘ └──────┘
N is the number of elements, P is the false-positive probability, bloom filter size:
\[\begin{aligned} bits = N \times \log_2e \times \log_2P \end{aligned} \]CKB 1000 transactions in one block, N = 1000, P = 2 ** 13 => 1000 * 1.44 * 13 bits = 2.34 KB
Theoretical minimum for a probabilistic data structure
\[\begin{aligned} bits = N \times \log_2P \end{aligned} \]BIP158 vs BIP37 bloom filter -44%: Golomb coded sets
hash -> Digest::MD5.hexdigest(s)[-8..].hex % (N * P)
N -> 24
P -> 2 ** 6 = 64
String | Hash |
---|---|
Alpha | 408 |
... | ... |
Omicron | 1001 |
... | ... |
Omega | 812 |
Uniformly distributed hash result
alphabetum = %w(Alpha Beta Gamma Delta Epsilon Zeta Eta Theta Iota Kappa Lambda Mu Nu Xi Omicron Pi Rho Sigma Tau Upsilon Phi Chi Psi Omega)
alphabetum.map{|s| Digest::MD5.hexdigest(s)[-8..].hex % 1536}.sort
[181, 354, 359, 395, 407, 408, 662, 740, 771, 794, 804, 807, 812, 1001, 1021, 1026, 1090, 1092, 1126, 1126, 1132, 1243, 1315, 1367]
Convert uniformly distribution to geometric distribution
sorted.each_cons(2).map{|a| a[1] - a[0]}.sort
[0, 1, 2, 3, 5, 5, 5, 6, 10, 12, 20, 23, 31, 34, 36, 52, 64, 72, 78, 111, 173, 189, 254]
P = 2 ** 6
0 | 0 |
1 | 10 |
2 | 110 |
3 | 1110 |
4 | 11110 |
5 | 111110 |
[181, 354, 359, 395, 407, 408, 662, 740, 771, 794, 804, 807, 812, 1001, 1021, 1026, 1090, 1092, 1126, 1126, 1132, 1243, 1315, 1367]
sorted.each_cons(2).map{|a| ((a[1] - a[0]).divmod 64)}
[[2, 45], [0, 5], [0, 36], [0, 12], [0, 1], [3, 62], [1, 14], [0, 31], [0, 23], [0, 10], [0, 3], [0, 5], [2, 61], [0, 20], [0, 5], [1, 0], [0, 2], [0, 34], [0, 0], [0, 6], [1, 47], [1, 8], [0, 52]]
Number | Quotient | Modulus | Golomb encoding |
---|---|---|---|
181 | 2 | 53 | 110 | 110101 |
173 | 2 | 45 | 110 | 101101 |
5 | 0 | 5 | 0 | 000101 |
36 | 0 | 36 | 0 | 100100 |
12 | 0 | 12 | 0 | 001100 |
1 | 0 | 1 | 0 | 000001 |
Theoretical minimum for a probabilistic data structure
\[\begin{aligned} bits = N \times \log_2P \end{aligned} \]110 110101 110 101101 0 000101 010010000011000000001111011111010001110001111100101110001010000001100001011101111010010100000010110000000000001001000100000000000011010101111100010000110100
181 / (24 * 6) =~ 1.25