1 of 11

to JIT (or not to JIT)

WebAssembly engines and ewasm

2 of 11

wasm engine types

Wasm engine

interpreted

compiled

JIT compilation not metered

AOT compilation is metered

3 of 11

Precompiles

  • ewasm - the last precompile (enables users to deploy their own precompiles). But ewasm not activated on the main chain (yet).
  • In the meantime, users want more precompiles. and they want them now.🔱🔱
  • Each precompile expands the surface area of consensus-critical code
  • Precompiles expand consensus code in two ways: the function itself (all the libraries imported as new dependencies, e.g. elliptic curve libraries), and new gas rules

4 of 11

  • Each precompile has some custom gas rules. These can be very complicated, and difficult to test
  • empirically a source of consensus bugs, see MODEXP and Byzantium

Precompiles - custom gas rules

5 of 11

Precompiles - test cases for consensus-critical code

6 of 11

wasm-based precompiles

  • More work to integrate a wasm engine than it is to implement one precompile
  • But if we're going to implement five+ precompiles, arguably might be less work if they are all wasm-based (especially when considering the work involved in testing)
  • One universal gas rule for all precompiles (injected metering)
  • minimal subset of ewasm for calls to “pure” wasm code (without side effects, no sload/sstore etc.) - a stepping stone to full ewasm
  • Should be possible for clients to actually execute a native implementation rather than the wasm one; Wasm version is just the reference implementation (fallback to wasm result on consensus bug). But knowing how much gas to charge might be tricky (execute the wasm version in parallel?).
  • quick proposal: https://github.com/ewasm/design/issues/104

7 of 11

Interpreter engine execution stages

Load bytecode

Execute 1st instruction

(charge gas)

Execute 2nd instruction

(charge gas)

8 of 11

JIT engine execution stages

Load bytecode

Compile wasm bytecode to machine code

(no gas charged)

Execute machine code

(calls to EEI method useGas)

9 of 11

JIT bombs: a DoS attack on JIT wasm engines

  • For JIT engines, the wasm module (contract) is compiled on every contract CALL. So the compilation stage better be fast
  • Would be nice to be able to use standard off-the-shelf JIT engines out of the box, just in case browser-based apps win the war (and eat all native apps). Also it would save a lot of work (writing/maintaining a custom bomb-proof wasm engine, whether a JIT or AOT)
  • Problem: some JIT engines are slow to compile some wasm modules (vulnerable to “JIT bombs”)
  • For reference: https://github.com/ewasm/design/pull/99

10 of 11

  • v8 JIT bombs found by Guido Vranken (via fuzzing)

https://gist.github.com/cdetrio/bf653174489777dd09524cbb1b13eb13

https://gist.github.com/cdetrio/ff70e99784b741cb2bc414e94feb85a1

11 of 11

Metered AOT vs JIT bomb sniffer

  • metered AOT is bomb-proof: metered compilation on deployment, then run the cached machine bytecode on CALL. Would work great in theory, but lots of work in practice (and rules out the use of standard off-the-shelf JIT engines)
  • If we want to ewasm contracts to be safely executed with standard JIT engines, then potential two ways to deal with bombs: get JIT fixes merged upstream (fix all the browsers), or don’t bother fixing and detect the bombs instead (“bomb sniffer”)
  • Bomb sniffer: detect bombs with a metered compilation stage executed on deployment (unlike with AOT, the compiled machine code is not cached).
  • Bomb sniffer is just another wasm blob that clients simply run (like the metering injection sentinel contract). In theory, would ensure that clients can safely use off-the-shelf browser JITs.