Introduction to CKB Light Client

By @quakewang

What's Light Client?

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

  • Neuron
  • Exchange
  • imToken, MetaMask

CKB data-structures


    ┌──────────────────────┐   ┌──────────────────────┐   ┌──────────────────────┐
 ◄──┤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│
                               └──┘   └──┘  └──┘   └──┘

          

Bitcoin SPV

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│
                               └──┘   └──┘

          

Download all headers

    ┌──────────────────────┐   ┌──────────────────────┐   ┌──────────────────────┐
 ◄──┤parent_hash: H()      │◄──┤parent_hash: H()      │◄──┤parent_hash: H()      │
    │transactions_root: H()│   │transactions_root: H()│   │transactions_root: H()│
    └──────────────────────┘   └──────────────────────┘   └──────────────────────┘
          
  • Linked List
  • Header Size * N
  • Bitcoin in one year: 80 * 52560 = 4.2 MB
  • CKB in one year: 204 * 3942000 = 804 MB

Better linked list?

Merkle Mountain Ranges

      ┌─────┐
      │Root1│
      └─────┘
     /       \
  ┌──────┐ ┌──────┐
  │Block0│ │Block1│ Contains Block0 Hash
  └──────┘ └──────┘
          

Better linked list?

Merkle Mountain Ranges Append

            ┌─────┐
            │Root2│
            └─────┘
            /     \
      ┌─────┐      \
      │     │       \
      └─────┘        \
     /      \         \
  ┌──────┐ ┌──────┐  ┌──────┐
  │Block0│ │Block1│  │Block2│ Contains Root1
  └──────┘ └──────┘  └──────┘
          

Better linked list?

Merkle Mountain Ranges Append

              ┌─────┐
              │Root3│
              └─────┘
            /           \
      ┌─────┐            ┌─────┐
      │     │            │     │
      └─────┘            └─────┘
     /       \          /       \
  ┌──────┐ ┌──────┐  ┌──────┐  ┌──────┐
  │Block0│ │Block1│  │Block2│  │Block3│ Contains Root2
  └──────┘ └──────┘  └──────┘  └──────┘
          

Better linked list?

Merkle Mountain Ranges Append

                      ┌─────┐
                      │Root4│
                      └─────┘
                  /             \
              ┌─────┐            \
              │     │             \
              └─────┘              \
            /           \           \
      ┌─────┐            ┌─────┐     \
      │     │            │     │      \
      └─────┘            └─────┘       \
      /       \          /      \       \
  ┌──────┐ ┌──────┐  ┌──────┐  ┌──────┐  ┌──────┐
  │Block0│ │Block1│  │Block2│  │Block3│  │Block4│ Contains Root3
  └──────┘ └──────┘  └──────┘  └──────┘  └──────┘
          

Better linked list?


      /\         Time complexity of append: O(log n)
     /  \        Time complexity of proof generation: O(log n)
    /    \
   /\     \
  /  \    /\
 /\  /\  /\ \
/\/\/\/\/\/\/\
          

Merkle Mountain Ranges: list of perfectly balance binary trees

Verify Transaction

                     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│
 └──┘   └──┘
          

Verify longest chain

Tip 1 is a honest chain tip

Tip 2 is a malicious chain with 1/3 hashrate

                                               ┌────┐
    ──────────────────────────────────────────►│Tip1│
                                               └────┘

                                               ┌────┐
    ──────────────────────────────────────────►│Tip2│
                                               └────┘
            

Verify longest chain

Sampling constant with binary distribution, 41 times

\[\begin{aligned} ({\frac13})^{41} < 2^{-64} \end{aligned} \]
                                               ┌────┐
    ─┬──────────────────┬───────────┬────┬──┬─►│Tip1│
     │                  |           |    |  |  └────┘
     └──────────────────┴───────────┴────┴──┴─
                                               ┌────┐
    ─┬──────────────────┬───────────┬────┬──┬─►│Tip2│
     │                  |           |    |  |  └────┘
     └──────────────────┴───────────┴────┴──┴─
            

Forking problem

\[\begin{aligned} ({\frac13})^{2} \end{aligned} \]
                                               ┌────┐
    ─┬──────────────────┬───────────┬────┬──┬─►│Tip1│
     │                  |           |    |  |  └────┘
     └──────────────────┴───────────┴──┬─┴──┴─
                                       │
                                       └──────── malicious fork
                                       │       ┌────┐
    ─┬──────────────────┬───────────┬──┴─┬──┬─►│Tip2│
     │                  |           |    |  |  └────┘
     └──────────────────┴───────────┴────┴──┴─
            

Find fork point effectively

                                               ┌────┐
    ─┬──────────────────┬───────────┬────┬──┬─►│Tip1│
     │                  |           |    |  |  └────┘
    ┬└──────────────────┴───────────┴────┴──┴─
    │
    └──────── malicious fork
    │                                          ┌────┐
    ┴┬──────────────────┬───────────┬────┬──┬─►│Tip2│
     │                  |           |    |  |  └────┘
     └──────────────────┴───────────┴────┴──┴─
            
  • Binary Search Approach
  • Bounding the Fork Point
  • The FlyClient Sampling Protocol

FlyClient Paper

FlyClient: Super-Light Clients for Cryptocurrencies

  • Variable difficulty
  • Non-Interactive and Transferable Proofs
  • Short fork optimization
  • Deploying FlyClient
  • CKB in 34 years (2 ** 27 blocks): 500 * (208 + (27 * 32)) = 536 KB

block filter

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
          

Server Side block filter


 ┌────────────┐
 │Light Client├───┬──────────────────────────────────────────
 └────────────┘   | Send filter (bob)        ▲
                  │                          │
 ┌────────────┐   ▼                          │  Send merkle proof
 │Full Node   ├──────────────────────────────────────────────
 └────────────┘                    │         │         │
                                   │         │         │
                                ┌──────┐  ┌──────┐  ┌──────┐
                                │Block1|  │Block2|  │Block3|
                                └──────┘  └──────┘  └──────┘
                                             |
                                             |
                                            tx4 (alice send to bob)
          

Server Side block filter

BIP37

Pros
  • Low resource requirements on light client
  • Easy to implement
Cons
  • Privacy leak and tx censorship
  • Easy to DDoS

Client Side block filter

    ┌────────────┐
    │Light Client├────────────────────────────────────────────────────┬────────
    └────────────┘   ▲ Send filter (all txs)        ▲ Send filter     |
                     │                              │                 | Get Block2
    ┌────────────┐   |                              |                 ▼
    │Full Node   ├─────────────────────────────────────────────────────────────
    └────────────┘   │                              │
                     │                              │
                 ┌──────┐                       ┌──────┐
                 │Block1|                       │Block2|
                 └──────┘                       └──────┘
          

Client Side block filter

BIP157

Pros
  • Low resource requirements on full node
  • No privacy leak
Cons
  • Requires a certain amount of computing and bandwidth resources

Better bloom filter?

bloom filter

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

Better bloom filter?

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

Golomb coded alphabetum


hash -> Digest::MD5.hexdigest(s)[-8..].hex % (N * P)
N    -> 24
P    -> 2 ** 6 = 64
          
String Hash
Alpha 408
... ...
Omicron 1001
... ...
Omega 812

Golomb coded alphabetum

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]
alphabetum sort

Golomb coded alphabetum

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]
geometric distribution

Unary encoding

P = 2 ** 6

0 0
1 10
2 110
3 1110
4 11110
5 111110

Golomb encoding


[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

Golomb encoding

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

CKB Light Client Protocol

CKB Light Client implementation

Q & A