This is the first article about exploring a custom WebAssembly runtime environment for Tezos. Let’s start with comparing Michelson and WebAssembly.
Michelson is a stack-based smart contract language with high level data types and primitives for Tezos. As the language is used to program money that’s stored on a distributed ledger, some unique characteristics apply:
- it’s important that a contract can be verified to do exactly what it says it does. And to do this on any machine that it runs on.
- storing a contract on the ledger can be done by anyone, and it’s not clear if a contract comes from an attacker or not. Therefore the space that’s used is important, and every byte on the ledger costs money.
- executing the instructions of the smart contract takes time, and can be misused, therefore instructions cost money as well.
These last two points are also known as gas costs.
Next to these unique characteristics, there are also several other characteristics worth mentioning:
- Contracts are written in plain text. Therefore it first needs to parsed before it can be checked and evaluated.
- No exception handling.
- Immutable variables.
- Strict type system, which includes Tezos specific types.
- The language can evolve through amendment.
For more info see: http://tezos.gitlab.io/whitedoc/michelson.html
WebAssembly is a stack-based binary instruction format with low level data types and primitives, that’s used as a compilation target for a growing list of programming languages. An important characteristic of WebAssembly is that it’s memory-safe and sandboxed. To achieve this a strict type system is used together with implicit access to the system stack. The implicit access to the system stack also makes it quite different from more traditional compilation targets.
Beyond this, for WebAssembly - the MVP specification - some other important characteristics apply:
- There are four value types: i32, i64, f32, f64. The sign bit of the floats is non-deterministic as described here: https://github.com/WebAssembly/design/blob/master/Nondeterminism.md. Functions are typed as well.
- It can be printed to s-expressions.
- There is no nested function support.
- WebAssembly MVP has access to a single block of bounds checked linear memory. There is no form of automatic memory management.
- Indirect calls can be made and are checked at runtime.
For more info see: https://webassembly.github.io/spec/
Although the WebAssembly MVP specification is finished and implemented many times, new features are being added to WebAssembly through extensions.
For this post I want to mention the reference types specification (https://github.com/WebAssembly/reference-types), which adds the anyref value type. This allows host references to be directly used from WebAssembly. The only downside with the current iteration is that all anyrefs are equal. There are however ideas to make reference types unique - https://github.com/WebAssembly/reference-types/blob/master/proposals/reference-types/Overview.md#type-importexport.
Most of the instructions used by Michelson can be transferred to WebAssembly. A challenge will be having the same kind of type safety that Michelson has, and might require help with reference types standardization work. Tezos specific instructions will need to be supported by the host environment.
Not all functionality that WebAssembly has is supported by Michelson. Floats, linear memory, and indirect calls are not supported by Michelson.
WebAssembly by default has no support for gas cost calculation, but this can be solved in the runtime.
Now that we have a basic understanding of the differences between Michelson and WebAssembly, what are your thoughts? Did I miss something essential here?
As we are not the first ones to explore WebAssembly for a smart contract platform, let’s take a look at prior art in the next article about exploring a custom WebAssembly runtime environment for Tezos.