Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Towards a True Programmable Blockchain World: A...

Towards a True Programmable Blockchain World: An Introduction to CKB VM

Xuejie "Rafael" Xiao

July 30, 2020
Tweet

More Decks by Xuejie "Rafael" Xiao

Other Decks in Programming

Transcript

  1. • Flexible enough to support any use case, yet simple

    enough to reduce attack surface. ◦ Backwards compatibility. • Industrial support. ◦ Innovation is good, but no need to reinvent everything • Reasonable & future-proof runtime cost model. ◦ Estimable resource usage
  2. CKB VM builds on RISC-V RISC-V is an & ISA

    (instruction set architecture) enabling a new era of innovation for processor architectures. CKB VM is a software implementation of RISC-V following its current standards.
  3. CKB VM works more like a real CPU int fib(int

    n) { int a = 0, b = 1, c, i; if (n == 0) return a; for (i = 2; i <= n; i++) { c = a + b; a = b; b = c; } return b; } fib: li a5,0 beqz a0,.L2 li a4,2 li a5,1 li a3,0 .L3: ble a4,a0,.L4 .L2: mv a0,a5 ret .L4: addw a2,a3,a5 addiw a4,a4,1 mv a3,a5 mv a5,a2 j .L3
  4. RISC-V is flexible • Essentially a computer embedded in a

    blockchain • More than adequate for existing use cases(ERC20 tokens, atomic swaps, etc.) • Enables new use cases
  5. CKB VM enables new use cases • The world has

    numerous crypto algorithms, which one should we use? • Compile secp256k1 via GCC to RISC-V, then deploy it on CKB. • No need to wait for precompiles. Deploy your favorite algorithm as you wish. • Your contracts are treated exactly the as the official ones.
  6. CKB VM enables new use cases • Solidity is fading,

    what should I do with my current dapp? • Compile an existing blockchain VM(Bitcoin Script, EVM, …) to RISC-V, then deploy it on CKB. • Preserve , keep a more , ecosystem.
  7. CKB VM enables new use cases • What if I

    want to use JavaScript and enjoy the rich npm ecosystem? • Compile a JS implementation(e.g: duktape) to RISC-V, then deploy to CKB. • Performance might or might not be a problem, it greatly depends on the use case. ◦ As adoption grows, optimizations will be applied due to economy.
  8. CKB VM enables new use cases WebAssembly makes a lot

    of sense for Web, but remains for blockchains.
  9. Is WebAssembly the right choice? Existing quirks: heap • Low

    level languages(C/C++, Rust, Go, etc.) typically require heaps for dynamic allocations. • WebAssembly only allows declaring fixed length buffer in modules in advance. • To implement a growable heap, typical solution is to create an ArrayBuffer in JavaScript, then expose it to WebAssembly. • This works for Web, but what about blockchains?
  10. Is WebAssembly the right choice? Existing quirks: non-determinism Source: https://webassembly.org/docs/rationale/

    “Nondeterminism is only specified as a compromise when there is no other practical way to: - Achieve portable native performance. - Lower resource usage. - Reduce implementation complexity (both of WebAssembly VMs as well as compilers generating WebAssembly binaries). - Allow usage of new hardware features. - Allows implementations to security-harden certain usecases.”
  11. Is WebAssembly the right choice? Existing quirks: non-determinism Source: https://webassembly.org/docs/rationale/

    “As WebAssembly gets implemented and tested with multiple languages on multiple architectures we may revisit some of the design decisions: - (omitted …) - When different languages have different expectations then it’s unfortunate if WebAssembly measurably penalizes one’s performance by enforcing determinism which that language doesn’t care about, but which another language may want.”
  12. Is WebAssembly the right choice? Ton of planned features Source:

    https://webassembly.org/docs/future-features/
  13. Is WebAssembly the right choice? Ton of planned features Source:

    https://webassembly.org/docs/future-features/
  14. Is WebAssembly the right choice? Ton of planned features Source:

    https://webassembly.org/docs/future-features/
  15. Is WebAssembly the right choice? Ton of planned features Source:

    https://webassembly.org/docs/future-features/
  16. CKB VM enables new use cases • WASM => RISC-V

    transpiler. • Ship higher-level features(GC, Tail Call, Expressive Control Flows, Floating Point calculations, etc.) in your contract as used. • Evergreen WASM implementation.
  17. RISC-V has a decent cost model • As an ISA

    for a real CPU, each RISC-V instruction has a cost called . • As a real computer model, CKB VM can work in a , memory space.
  18. Hardware based CKB VM • A lucky accident • Real

    RISC-V CPU can be attached to accelerate CKB VM executions further. • Suitable for cases where higher TPS is required, e.g., exchanges, mining pools.
  19. Numbers Runner type Runtime Ratio Native 0.124 ms 1x CKB

    VM (Interpreter) 6.9ms 55.6x CKB VM (AOT JIT) 1ms 8x Wasmer (Cranelift) 1ms 8x Wasmer (LLVM) 0.84ms 6.7x
  20. Numbers Runner type Runtime Ratio LOC Native 0.124 ms 1x

    CKB VM (Interpreter) 6.9ms 55.6x 8484 CKB VM (AOT JIT) 1ms 8x 8484 Wasmer (Cranelift) 1ms 8x 36830(wasmer) + 62266(cranelift) = 99096 Wasmer (LLVM) 0.84ms 6.7x ? Counted via: cloc --not-match-f='generated|compiled|test|example' --fullpath .
  21. Numbers Runner type Runtime Ratio LOC Native 0.124 ms 1x

    CKB VM (Interpreter) 6.9ms 55.6x 8484 CKB VM (AOT JIT) 1ms 8x 8484 Wasmer (Cranelift) 1ms 8x 36830(wasmer) + 62266(cranelift) = 99096 Wasmer (LLVM) 0.84ms 6.7x ? Those are not designed for blockchains! Counted via: cloc --not-match-f='generated|compiled|test|example' --fullpath .
  22. • : RISC-V is much closer to real hardware •

    Rust balances between code clarity and low level control • Leverage RAW assembly for hot loops. • Rust is awesome in most cases, but watch out for quirks
  23. pub enum Instruction { I(i::Instruction), // omitted } pub enum

    i::Instruction { R(Rtype), // omitted } pub struct Rtype { rs1: usize, rd: usize, imm: usize, inst: i32, } 32 bytes 40 bytes 48 bytes
  24. 63 0 +-----+-----+-----+-----+-----+-----+-----+-----+ | | rs1 | rs2 | res

    | | rd | op | R-type +-----------+-----------------------------------+ | immediate | rs1 | res | | rd | op | I-type +-----------------------------------------------+ | immediate | rs1 | res | | rs2 | op | S-type/B-type +-----------------+-----------------------------+ | immediate | res | | rd | op | U-type/J-type +-----+-----+-----+-----+-----+-----+-----+-----+
  25. pub enum Foo { Bar(u64), Baz(u8), Hah(u32), Lol(u16), } fn

    pp(f: &Foo) { match f { Foo::Bar(i) => println!("Bar {}", i), Foo::Baz(j) => println!("Baz {}", j), Foo::Hah(h) => println!("Hah {}", h), Foo::Lol(l) => println!("Lol {}", l), }; }
  26. playground::pp: subq $72, %rsp movzbl (%rdi), %eax cmpq $1, %rax

    je .LBB9_4 cmpq $2, %rax je .LBB9_5 cmpq $3, %rax jne .LBB9_3
  27. Source: https://www.reddit.com/r/programming/comments/badl2/luajit_2_beta_3_is_out_support_both_x32_x64/c0lrus0/ // Prologue for type ABC instructions (others have

    a zero prologue). movzx ebp, ah Decode RC (split of RD) movzx eax, al Decode RB (split of RD) // The instruction itself. cmp [edx+ebp*8+0x4], -13 Type check of [RB] ja ->lj_vmeta_arith_vn movsd xmm0, [edx+ebp*8] Load of [RB] addsd xmm0, [edi+eax*8] Add to [RC] movsd [edx+ecx*8], xmm0 Store in [RA] // Standard epilogue: decode + dispatch the next instruction. mov eax, [esi] Load next bytecode movzx ecx, ah Decode RA movzx ebp, al Decode opcode add esi, 0x4 Increment PC shr eax, 0x10 Decode RD jmp [ebx+ebp*4] Dispatch to next instruction Inspirations from masters
  28. 13 instructions for 1 RISC-V instruction movzx edx,cl movzx ebp,ch

    mov rdx,QWORD PTR [rsi+rdx*8] add rdx,QWORD PTR [rsi+rbp*8] mov QWORD PTR [rsi+rax*8],rdx mov QWORD PTR [rsi],0x0 mov rcx,QWORD PTR [r9] add r9,0x8 movzx eax,ch sar rcx,0x20 mov rdi,QWORD PTR [r8] add r8,0x8 jmp rdi Decode operands Actual work Decode next instruction
  29. 13 instructions for 1 RISC-V instruction movzx edx,cl movzx ebp,ch

    mov rdx,QWORD PTR [rsi+rdx*8] add rdx,QWORD PTR [rsi+rbp*8] mov QWORD PTR [rsi+rax*8],rdx mov QWORD PTR [rsi],0x0 mov rcx,QWORD PTR [r9] add r9,0x8 movzx eax,ch sar rcx,0x20 mov rdi,QWORD PTR [r8] add r8,0x8 jmp rdi Decode operands Actual work Decode next instruction This is our interpreter
  30. Can we save more? movzx edx,cl movzx ebp,ch mov rdx,QWORD

    PTR [rsi+rdx*8] add rdx,QWORD PTR [rsi+rbp*8] mov QWORD PTR [rsi+rax*8],rdx mov QWORD PTR [rsi],0x0 mov rcx,QWORD PTR [r9] add r9,0x8 movzx eax,ch sar rcx,0x20 mov rdi,QWORD PTR [r8] add r8,0x8 jmp rdi Overhead Actual work Overhead
  31. • Translate RISC-V assembly directly to X86-64 assembly • In

    most cases, VM can run in X86-64 generated code directly • Fallback to assembly interpreter in rare cases • Rust’s zero cost JIT helps a lot!
  32. • Rust in most places for safety and clarity •

    Assembly in few places for absolute speed ------------------------------------------------------------------------------- Language files blank comment code ------------------------------------------------------------------------------- Rust 31 611 341 5567 C 1 131 75 1087 Assembly 1 23 94 982