Ewasm 1.x precompiles, part 1

This is a write-up of a lightning talk that I gave at the Ethereum 1.x meetup in Stanford on January the 28th, 2019. The goal of this presentation was two-fold: 1) draft up a list of requirements for an ewasm precompiles proposal, and 2) showcase the progress that has been made on that proposal. This post expands on that second point. Many thanks to Paul Dworzanski for his patient feedback.

A first prototype

At this stage, I have completed a first geth prototype that can execute simple contracts and sync Rinkeby. We created Rust version of the precompiles, compiled them to WASM, then embedded them into geth. Each contract is associated to a VM object that is created once and for all, thus removing from the measurements the overhead caused by decoding the binary on each contract execution. And a small subset (6 functions) of the EEI (ewasm helper functions) has been implemented, for the WASM precompiles to interact with geth.

Performance

For each transaction stored on Rinkeby, the native precompile was executed and timed, before executing its WASM counterpart. It makes the sync considerably longer, but it’s also very useful since it’s then possible to compare the output of both methods transaction by transaction, and thus to identify behavioral differences.

Figure 1 — Initial, non-optimized benchmark of a Rinkeby sync using a 8 core, 8th gen Intel Core i7 at 1.80GHz. The chart on the left represents the logarithmic difference in performance between the native implementations of the precompiles and their WASM counterparts. The chart on the right represents the slowdowns.

In first approach, these numbers are far from impressive, but there’s more than meet the eye:

  • For starters, it shows that the longer a native contract takes to execute on average, the longer its WASM counterpart runs as well. So there is a direct relationship, which indicates that speeding up the interpreter is going to have some real impact. That’s great, those tests were made with a slower interpreter. So it’s only going to get better from here! The next steps include looking at hera, life and wag.
  • Looking at the diagram on the right, we also see which contracts are in dire need of optimization. Luckily, they are the ones that are used the least. In the next step, we’re going to optimize them. For example, expmod uses a big integer library that is likely under-performing and there are no doubt a lot of gains to be made in this direction.

But the most important conclusion, is that WASM precompiles are not intended to be run on interpreters once compilers are audited for consensus. It does makes adoption by every client easier when you create a new precompile (e.g. some SNARK precompiles that have been requested): you just fire up the good ol’ interpreter to execute your shiny new WASM precompiles until you can replace those WASM precompiles with an AOT version. Safety comes first, then performance. After all, the choice of WASM has always been about the tooling, ease of adoption and simpler gas rules. Speed is an implementation detail.