OCaml Under The Hood: SmartPy
Tezos is a blockchain project well known of the OCaml ecosystem. It has support for rich smart-contracts, i.e. accounts of “programmable money,” which are the basis for distributed applications (“DApps”) which use the blockchain as a synchronization source between non-trusting parties.
Michelson, the smart-contract language specified in the current Tezos protocol, is a quite low-level, stack-based, statically typed, language. Even though some aficionados do love programming in Michelson, most users prefer to avoid it and, hence, quite a few higher-level language projects have appeared in the ecosystem, e.g., SmartPy, LIGO, Lorentz, Juvix, or Archetype.
SmartPy is one of these projects but should be seen more as a meta-programming framework than a (new) high-level language. It uses some of python's annotation features as well as some light (optional) syntactic sugar to provide a “native feel” but it is essentially a library of constructors for SmartML programs and test scenarios. Here is a minimal example:
import smartpy as sp class HelloWorld(sp.Contract): def __init__(self): self.init(mem = "") @sp.entryPoint def remember(self, param): self.data.mem += param @addTest(name = "Test") def test(): scenario = sp.test_scenario() scenario.h1("Let's Go!") c = HelloWorld() scenario += c scenario += c.remember("Hello World")
The SmartPy team publishes the software under the MIT-license periodically at https://gitlab.com/SmartPy/smartpy, various builds (“stable”/“dev”/“test”) of the distribution are also provided to users.
Python is one of the most popular languages in the world:
- It has an intuitive syntax for most people.
- It provides good meta-programming capabilities (e.g. programmable AST annotations).
- New users (believe they) already know how to program with it, they can focus on learning the really hard part: smart-contract design and development.
SmartPy also provides a very complete online IDE as well as a command-line application. Both allow the user to compile, simulate, run (sandboxes and test-networks) and inspect the contracts.
SmartPy programs use Python essentially as a very powerful macro-language for SmartML. SmartML is an inperative, fully type inferred, intermediate language which is defined in an OCaml library. The library itself contains a type-inference engine, an interpreter, an optimizing compiler to Michelson, as well as a scenario “on-chain” runner.
The WebIDE uses a mix of OCaml built with
The command line interface is also buildt with
js_of_ocaml in order
to run with Node.js and make distribution much easier.
The user edits their code written from scratch or, most likely, imported from one of the many self-documenting “templates” provided by the UI. The workflow of what happens when a user clicks on “Run & Test” in WebIDE is as follows:
- The Python code is interpreted with Brython.
- It constructs a SmartML expressions and scenarios.
- The contract and the tests enter the
- Full type inference and type checking.
- Simulation of the tests in the interpreter.
- Compilation to Michelson.
- Back to the UI to display the results.
The interpreter requires fast execution of the contracts in a command line application and in the WebIDE. Moreover, for interoperability some primitive operations of Michelson must match bit-for-bit what the interpreter computes on both execution environments. This includes all the cryptographic operations and the binary serialization of values.
For instance, a user should be able to use other tools to construct the Ed2551
signatures fed to the entry-point in the example below. The behavior of the call
check_signature as well as the serialization (
sp.pack) should match
perfectly the specification and implementation of the Tezos protocol:
@sp.entryPoint def set_current_value(self, params): thing_to_sign = sp.pack( sp.record( o = self.data.current_value, n = params.new_value, a = sp.self, c = self.data.counter)) sp.verify( sp.check_signature( self.data.boss_public_key, params.user_signature, thing_to_sign)) self.data.current_value = params.new_value self.data.counter = self.data.counter + 1
As current work-in-progress or future work items, our road-map contains:
- Decompilation from Michelson to SmartPy.
- Other static analyses, such as abstract interpretation: ownership, value domains, etc. and gas usage prediction.
- Other compilation targets, like contract storage parsing code, or proof-friendly representations (e.g. WhyML).
- An OCaml version of the EDSL, i.e. generate SmartML from OCaml instead of Python.
Ecosystem and Real-World Users
SmartPy benefits from quite some popularity within the Tezos ecosystem; especially given how “niche” the product is. The main Telegram help-channel has more than 200 members, and the twitter account has about 600 followers.
There are already 3rd party online courses, like blockmatics.io or "Cryptobots vs Aliens", and most hackathons include SmartPy (e.g. CoinList). Some nascent financial applications such as ChainLink already build on the platform. Generic development platforms like ConseilJS natively support SmartPy.
We have also participated in the development of standard contract interfaces, through reference implementations. For instance, FA2-SmartPy implementation of the TZIP-12 standard abuses meta-programming features to provide many different “builds” of the contract corresponding to various options; it also happens to use OCaml-code generation to provide type-safe access to those smart-contract variants, the specialized command-line application, used for demoing, benchmarks, and generating documentation can safely evolve as the draft specification changes.
The talk will present all of the above with a focus on:
- The specific OCaml aspects: the portability between browser Vs Node.js
packaging, the re-implementation of lower-level Tezos functionality (including
- The meta-programming approach both in Python and OCaml.