A year ago, I was with friends, casually joking about Solidity and what mainstream languages eventually will be used to write smart contracts. Lua? Python? It sowed a seed into my head. Soon after, on a rainy Saturday afternoon, I sat down and ported MicroPython to rv32emc
, the PVM target architecture. The interpreter eventually compiled down to a 180kb large object file. This could definitively be deployed as a contract. In my head, things were coming together: Implement and register a custom system call module for interacting with the chain. Add helper libraries to let contracts speak Solidity ABI and simplify function dispatching (maybe similar to http path routers via annotations in flask). Alex had another brilliant idea: For interpreted byte code, we can delegate call into the interpreter contract (or a pre-compile, but micro python is a C code base), allowing to upgrade the interpreter or merkleize the contract code more easily. Solidity interopable Python smart contracts seemed actually very doable!
Momentum
A year ago, revive
was roughly estimated to launch in Q3 this year. In other words, we were still busy with implementing the very fundamentals and it wasn’t the time to go after intriguing but uncertain ventures like this. However, I’d like to discuss this now in public. Solidity support is shaping up, and soon we will be busy no longer implementing but optimizing it, leaving room for more. Beyond Solidity, what else could help bringing mass-adoption for Polkadot?
The Python programming language is gaining momentum fast. It arguably is the most popular programming language on earth. Numbers vary by data source, but there seem to be more than 10 million python developers world wide, which is more than Solidity or Rust by large factors.
What helped Python gain popularity in the data analysis and AI field (Python scripts in the front, fast C++ libraries in the back) works with pallet-revive
too: Where performance becomes a limiting factor, libraries can just be implemented in Rust using the UAPI instead.
New developments like the Mojo language inspire high confidence in the popularity of Python. Lately, Google wants to launch an L1 with Python contracts. I think that strong enough momentum formed to seriously consider Python smart contracts on Polkadot.
Implementation
What follows is a short brain-dump about various implementation aspects.
Language support
There are two different approaches for Python language support.
a) Use an existing python implementation
Implement a pallet-python
using an existing Python implementation (compiler and VM) as a dependency. MicroPython
is a bit limited in language support and also not a Rust codebase, so the RustPython project could work better for us. There seem to be successful efforts porting it tono_std
- unfortunately it’s not very up to date with the base branch, needs nightly and I faced some compilation problems but overall looks promising.
The python interpreter functionality of pallet-python
is exposed via a pre-compile address. The Python source code would then be compiled into byte code and stored in contract storage under a designated, specific storage keys (inaccessible in Solidity). Python contracts would actually be small PVM stubs which delegate call into the interpreter pre-compile.
I haven’t finalized my thoughts around how exactly the runtime handles the abstract concept of Contract
instances (create semantics) and module imports. An obvious thing is statically link modules (“frozen” modules). As a future optimization, a JIT compiler could be employed, compiling some modules or maybe even hot paths to PVM byte code.
b) Compile Python byte code directly to PVM
Akin to the Mojo and revive compiler approaches. Results in faster contract code but potentiallly at the expense of larger contract code blobs. I think this is more work than the interpreter route, even when we could work with some existing Python compiler to spare us some scaffolding. In the case of Python however, I intuitively value getting support quickly and investing time into developer experience over having optimized runtime efficiency.
Developer experience
To me the most important part: Making the developer experience absolutely stellar. Short-term, we can implement a tool to convert Python source code into contract blobs. Maybe even integrate it with Hardhat and Foundry. The revive
compiler infrastructure could serve as a basis for this. But that’s just the MVP. Ultimately, we make sure that Python on Polkadot makes developers fall into the pit of success:
-
Full interoperability with Solidity contracts by default. We need to generate Solidity contracts compatible metadata. dApp End-users must not notice that their dApp was in fact not written in Solidity. We also provide audited versions of common libraries like ERC token standards (and work closely with partners).
-
ink!
has shown to me that we should take care to meet non-blockchain-native developers where they are. Writing basic contracts should be very easy and intuitive. We need to provide intuitive and easy to use modules, frameworks and tooling. Things like reading and writing files should just work. What about for example prototyping your smart contract in a Jupyter notebook in the browser? How to do package management in a secure way?
This represents a lot of work (more than the language supporting pallet or compiler). Now you might think, why would it be justified when it didn’t work out with ink!
? I see three compelling reasons:
ink!
was neither Solidity nor Ethereum compatible. Trying to build a siloed, isolated ecosystem is harder and more effort.- Python has significantly more market share than Rust.
- While Rust and Python are both general purpose languages, Rust is more tailored towards low-level and systems programming, where as Python is arguably more tailored towards application development and scripting. dApps fall into the applications category and it follows that Python is the better fit for finding traction in this domain.
Limitations, risks and open questions
Not all existing Python libraries will work well (especially those calling into native code via FFI). We also introduce additional technical depth and attack surfaces. I’m sure there are many more obstacles which I didn’t think of yet.
Alternatives considered
A valuable alternative to me seems to be Javascript (or Typescript for that matter). Arguably also very popular, it seems slightly harder to integrate or to write a working compiler, at least I could not find a viable no_std
Rust runtime implementation. I also remember the ask! language framework targetting pallet-contracts
.
Closing thoughts and next steps
Supporting one of if not the world’s most popular programming language on Polkadot gets us ahead the curve and could bring us a lot of traction. While we are busy polishing Solidity support, I am curious what all stakeholders think about this. Once we find consensus about if and how exactly we want to do this, resources can be allocated to develop a proof of concept.
Thanks for reading, looking forward to discuss!