# Ethereum # ❤️ # WebAssembly Martin Becze github.com/wanderer Alex Beregszaszi github.com/axic [comment]: # (this talk will give an overview of ewasm) --- ## The core of the system is the VM ![](https://i.imgur.com/aLMhvso.gif) --- ## EVM, growing pains - 256 bit words<!-- .element: class="fragment" data-fragment-index="1" --> - It has instuctions that shoudn't be instuctions (GASLIMIT, BALANCE, SHA3, etc)<!-- .element: class="fragment" data-fragment-index="2" --> - Missing instuctions like shift and rotate<!-- .element: class="fragment" data-fragment-index="3" --> - No system call equivalent <!-- .element: class="fragment" data-fragment-index="4" --> - Its a hard compilation target for many HLL <!-- .element: class="fragment" data-fragment-index="5" --> - Largely incompatible with the ecosystems outside of Ethereum <!-- .element: class="fragment" data-fragment-index="6" --> --- ## Can there be a better way? --- ## What is WebAssembly? > WebAssembly or wasm is a new, portable, size- and load-time-efficient binary format that aims to execute at native speed by taking advantage of common hardware capabilities available on a wide range of platforms. --- ## What is WebAssembly? - Fast & Efficient <!-- .element: class="fragment" data-fragment-index="1" --> - Secure Sandbox <!-- .element: class="fragment" data-fragment-index="2" --> - Toolchain Compatibility <!-- .element: class="fragment" data-fragment-index="3" --> - Extensible <!-- .element: class="fragment" data-fragment-index="4" --> - The Combined Powers of the Web!<!-- .element: class="fragment" data-fragment-index="5" --><br>![](https://i.imgur.com/Av9JHNY.gif)<!-- .element: class="fragment" data-fragment-index="5" --> ---- ### W3C Working Group www.w3.org/community/webassembly - Participants (660) <!-- .element: class="fragment" data-fragment-index="1" --> - Mozilla <!-- .element: class="fragment" data-fragment-index="2" --> - Google <!-- .element: class="fragment" data-fragment-index="3" --> - Microsoft <!-- .element: class="fragment" data-fragment-index="4" --> - Apple <!-- .element: class="fragment" data-fragment-index="5" --> ---- ### Instruction Set and AST - RISC like <!-- .element: class="fragment" data-fragment-index="1" --> - Integer and float operations <!-- .element: class="fragment" data-fragment-index="2" --> - Defined as an AST <!-- .element: class="fragment" data-fragment-index="3" --> - can be easily processed - can be easily transformed - can be interpreted with a Stack Machine - or JITed ---- ### S-Expressions ```clojure= (module (import $useGas "ethereum" "useGas" (param i32)) (memory 1) (export "memory" memory) (export "main" $main) (func $main (local $sp i32) (local $jump_dest i32) (set_local $sp (i32.const -32)) (set_local $jump_dest (i32.const -1)) (loop $done $loop (block $1 (block $0 (br_table $0 (if (i32.eq (get_local $jump_dest) (i32.const -1)) (then (i32.const 0)) (else (unreachable))))) (call_import $useGas (i32.const 6)) (if (i32.gt_s (get_local $sp) (i32.const 32672)) (then (unreachable))) (call $PUSH (i64.const 0) (i64.const 0) (i64.const 0) (i64.const 96) (get_local $sp)) (set_local $sp (i32.add (get_local $sp) (i32.const 32))) (call $PUSH (i64.const 0) (i64.const 0) (i64.const 0) (i64.const 0) (get_local $sp)) (set_local $sp (i32.add (get_local $sp) (i32.const 32))))))) ``` ---- ### Semantics * `(i64.const 42)`<!-- .element: class="fragment" data-fragment-index="1" --> * Types<!-- .element: class="fragment" data-fragment-index="2" --> * i32 `(i32.const 0xffffffff)` * i64 `(i64.const -644)` * <!-- .element: class="fragment" data-fragment-index="3" -->`(local $a)` * Memory Access <!-- .element: class="fragment" data-fragment-index="4" --> * `(i64.load (i64.const 4))` * `(i64.store (get_local $a) (i64.const 4))` * Arithmetic<!-- .element: class="fragment" data-fragment-index="5" --> * Conditionals <!-- .element: class="fragment" data-fragment-index="6" --> * <!-- .element: class="fragment" data-fragment-index="7" -->Calls * `(call_import $useGas (i64.const 33))` ---- ### Binary Dump ``` 0061736d0b00000004747970651003400101004005020202020 10040000006696d706f727412010008657468657265756d0675 73654761730866756e6374696f6e03020102066d656d6f72790 3010101066578706f7274070101046d61696e04636f64655f02 01005b01020110601500107f15010201011401107f4d0310000 40a0f080000000000000f1006180100140010a0ff0153030a0f 11001100110011e000140016050014001020401500110011001 10011001400160500140010204015000f0f ``` ---- ### Binary Disected ```python= 0000000: 0061 736d ; WASM_BINARY_MAGIC 0000004: 0b00 0000 ; WASM_BINARY_VERSION ; section "type" 0000008: 04 ; string length 0000009: 7479 7065 ; section id: "type" 000000d: 00 ; section size (guess) 000000e: 01 ; num types ; type 0 000000f: 40 ; function form 0000010: 02 ; num params 0000011: 01 ; param type 0000012: 01 ; param type 0000013: 01 ; num results 0000014: 01 ; result_type ; section "function" 0000015: 08 ; string length 0000016: 6675 6e63 7469 6f6e ; section id: "function" 000001e: 00 ; section size (guess) 000001f: 01 ; num functions 0000020: 00 ; function 0 signature index 000001e: 02 ; FIXUP section size ; section "export" 0000021: 06 ; string length 0000022: 6578 706f 7274 ; section id: "export" 0000028: 00 ; section size (guess) 0000029: 01 ; num exports 000002a: 00 ; export func index 000002b: 06 ; string length 000002c: 6164 6454 776f ; export name ; section "code" 0000032: 04 ; string length 0000033: 636f 6465 ; section id: "code" 0000037: 00 ; section size (guess) 0000038: 01 ; num functions ; function body 0 0000039: 00 ; func body size (guess) 000003a: 00 ; local decl count 000003b: 14 ; OPCODE_GET_LOCAL ``` ---- ### Binary Encoding - Fast decoding <!-- .element: class="fragment" data-fragment-index="1" --> - Single pass validation <!-- .element: class="fragment" data-fragment-index="2" --> - Extensible <!-- .element: class="fragment" data-fragment-index="3" --> ---- ### Availability of VMs - <!-- .element: class="fragment" data-fragment-index="1" -->Chrome (chrome://flags - enable-webassembly) - <!-- .element: class="fragment" data-fragment-index="2" -->Firefox Nightly (about:config and set `javascript.options.wasm` to true) - <!-- .element: class="fragment" data-fragment-index="3" -->Microsoft Edge - <!-- .element: class="fragment" data-fragment-index="4" -->node.js 7.0-pre (--enable-wasm) - <!-- .element: class="fragment" data-fragment-index="5" -->wasm-jit-prototype (github.com/WebAssembly/wasm-jit-prototype) - <!-- .element: class="fragment" data-fragment-index="6" -->Ocaml "the spec" (github.com/WebAssembly/spec) - interpreters<!-- .element: class="fragment" data-fragment-index="7" --> - sexpr-wasm-prototypen (github.com/WebAssembly/sexpr-wasm-prototype) - binaryen (github.com/WebAssembly/binaryen) --- ## Ethereum flavored WebAssembly `e^WASM` - A proposed replacement for EVM<!-- .element: class="fragment" data-fragment-index="1" --> - A restricted subset of WebAssembly<!-- .element: class="fragment" data-fragment-index="2" --> - No floating point operations - Defines Backwards Compatibility<!-- .element: class="fragment" data-fragment-index="3" --> - Defines Metering<!-- .element: class="fragment" data-fragment-index="4" --> - Defines an interface for interacting with the Ethereum Blockchain<!-- .element: class="fragment" data-fragment-index="5" --> ---- ### EVM2WASM - Transcompiles EVM code to WebAssembly<!-- .element: class="fragment" data-fragment-index="1" --> - Can be run as a contract<!-- .element: class="fragment" data-fragment-index="2" --> - Compliant with the offical EVM tests<!-- .element: class="fragment" data-fragment-index="3" --> - Produces very fast EVM code<!-- .element: class="fragment" data-fragment-index="4" --> - ~5000 line of wasm<!-- .element: class="fragment" data-fragment-index="5" --> - ~400 line of js<!-- .element: class="fragment" data-fragment-index="6" --> ---- ### EVM2WASM <iframe width="100%" height="500" style='background:white' src="https://ewasm.github.io/evm2wasm-frontend/dist/" frameborder="0"></iframe> ---- ### Metering Injection Metering is decoupled from the VM ```flow st=>start: raw wasm e=>end: run op=>operation: Validate op2=>operation: Injection Metering cond=>condition: Yes or No? st->op->op2->e ``` ---- ### Metering By Branch ![](https://i.imgur.com/axIXk25.jpg) ---- ### Metering By Branch ![](https://i.imgur.com/dngglBx.jpg) --- ## Interfaces <!-- Transition: by now you all are experts in WebAssembly and S-expressions. Let's glue all of this together. --> *Glueing all this together* --- ### eWASM Ethereum Interface (EEI) Defines the Ethereum blockchain methods for contracts: - getCallDataSize ~ CALLDATASIZE - callDataCopy ~ CALLDATACOPY - storageLoad ~ SLOAD - storageStore ~ SSTORE - call ~ CALL - delegateCall ~ DELEGATECALL - return ~ RETURN - ... A total of 29 methods. --- ### Example: storageLoad ```clojure (call_import $storageLoad (i32.const 0) (i32.const 32)) ;; ^ key offset in memory ;; ^ result offset in memory ``` Simples. --- <!-- Transition: now it is time to wrap all these calls into an actual contract. --> ### eWASM Contract Interface (ECI) Defines the format of contracts: - WebAssembly binary encoding version 0xb - Single entry point: *main* - Sets other limitations. --- ### Example contract Drumroll: ```clojure (module (memory 1 (segment 0 "Hello World!") ) (import $return "ethereum" "return" (param i32 i32)) (export "main" $main) (func $main (call_import $return (i32.const 0) (i32.const 12)) ) ) ``` --- <!-- Transition: if we can write contract, we can also write system contracts --> ### System Contracts 1) Sentinel - ECI validation - metering injection - wrap into deployer 2) evm2wasm! <!-- .element: class="fragment" data-fragment-index="3" --> 3) EVM1 precompiled contracts <!-- .element: class="fragment" data-fragment-index="4" --> --- <!-- Transition: having system contracts simplifies the client implementation a lot --> ## VM Semantics Only 3 new rules for a client: 1) Check contract code for eWASM signature <!-- .element: class="fragment" data-fragment-index="1" --> 2) Use evm2wasm to transcompile if needed <!-- .element: class="fragment" data-fragment-index="2" --> 3) Use sentinel contract during contract creation <!-- .element: class="fragment" data-fragment-index="3" --> <!-- Note: transcompiled code is not stored in the state. --> --- ## ewasm-kernel and Hera 1) ewasm-kernel - Javascript - runs in browsers and node.js - < 1000 lines for the interface and VM core 2) Hera - C++ - *EVM-C compatible* - works with cpp-ethereum (eth --vm hera) - and pyethereum \o/ - ... and hopefully go-ethereum + parity in the future --- ## The test network <!-- ZCASH --> --- <!-- Transition: don't be afraid, no need to write S-expressions. Contracts can be written in C and C++. --> ## Programming in C and the precompiles *clang & ewasm-libc* --- ## Example: sha256 ```c #include "ethereum.h" #define BASE_FEE 60 #define WORD_FEE 12 void main() { size_t datasize = ethereum_calldatasize(); unsigned char data[datasize]; unsigned char ret[32] = { 0 }; ethereum_calldatacopy(data, 0, datasize); ethereum_usegas(BASE_FEE + (((datasize + 31) / 32) * WORD_FEE)); mbedtls_sha256(data, datasize, ret, 0); ethereum_return(ret, 32); } ``` --- <!-- Transition: afraid of C? Solidity! --> ## Solidity for eWASM Input: ```js contract A { function a() { throw; } function b() payable returns (uint64) { uint64 x = 42; return x; } } ``` --- ## Solidity for eWASM Output: ```clojure ;; Contract: A (module (import $callDataCopy "ethereum" "callDataCopy" (param i32 i32 i32)) (import $getCallValue "ethereum" "getCallValue" (param i32)) (import $return "ethereum" "return" (param i32)) (memory 1 1) (export "memory" memory) (export "main" $main) (func $main (call_import $callDataCopy (i32.const 0) (i32.const 0) (i32.const 4)) (call $dispatcher (i32.load (i32.const 0))) (unreachable) ) (func $ensureNotPayable (call_import $getCallValue (i32.const 0)) (if (i64.ne (i64.const 0) (i64.load (i32.const 0)) (unreachable)) (if (i64.ne (i64.const 0) (i64.load (i32.const 8)) (unreachable)) ) (func $dispatcher (param $sig i32) (if (i32.eq (get_local $sig) (i32.const 0x0dbe671f)) (then (call $__0dbe671f))) (if (i32.eq (get_local $sig) (i32.const 0x4df7e3d0)) (then (call $__4df7e3d0))) (unreachable) ) ;; function: a() (func $__0dbe671f (call $ensureNotPayable) (block (unreachable) ) ) ;; function: b() payable (func $__4df7e3d0 (block (local $x (param i64)) (set_local $x (i64.const 42)) (i64.store (i32.const 0) (i64.const 0)) (i64.store (i32.const 8) (i64.const 0)) (i64.store (i32.const 16) (i64.const 0)) (i64.store (i32.const 24) (get_local $x)) (call_import $return (i32.const 0) (i32.const 32)) ) ) ) ``` --- ## Bonus: Gas Cost Calculation 1) Gas cost is based on the cycle count of the instructions.<!-- .element: class="fragment" data-fragment-index="1" --> 2) The gas cost table is stored in a contract.<!-- .element: class="fragment" data-fragment-index="2" --> 3) SHA256 performance (of 8kb data):<!-- .element: class="fragment" data-fragment-index="3" --> - precompile cost: ~3 100<!-- .element: class="fragment" data-fragment-index="3" --> - eWASM cost: ~6 500<!-- .element: class="fragment" data-fragment-index="3" --> - EVM (Solidity) cost: ~32 000 000<!-- .element: class="fragment" data-fragment-index="3" --> - EVM (Solidity) cost (with shifts): ~1 000 000<!-- .element: class="fragment" data-fragment-index="3" --> --- ## (call_import $ethereumReturn) See more awesome details at https://github.com/ewasm >:::danger >:fire: Error: Out-Of-Gas! :fire: >::: <!-- .element: class="fragment" data-fragment-index="2" -->
{}
    4758 views