I’d like to share a brief update about 2 endeavors I’m currently working on.
A new Solidity compiler
As discussed previously here on the forum, we are exploring an alternative contracts runtime, based on PolkaVM. Since we want this new runtime to be highly compatible with Solidity, we started working on a new Solidity compiler.
Priorly, I was mainly working on Hyperledger Solang and we implemented an experimental PolkaVM target.
What is Solang
Hyperledger Solang is a Solidity compiler shipping a custom Solidity frontend, immediate representation and code generator. It emits LLVM IR and currently supports compiling contract to Polkadot pallet-contracts
and Solana runtime targets.
You might ask yourself now, why starting something new? (1) Solidity is a moving target, (2) developing a complete Ethereum Solidity compatible compiler is a lot of work and (3) it comes with its own drawbacks (more detailed reasoning in spoiler below).
Tell me more
- A canonical Solidity language specification covering all version is yet to be published, the documentation is lacking, many half-baked Solidity features were shipped but never finished over the years. Today,
solc
as the reference implementation remains the single source of truth. - It seemingly took the nomic foundation over a year and multiple engineers to build an accurate parser covering about 70 different Solidity versions (starting from Solidity 0.4.11). Note that this is not a complete compiler but just about the frontend!
- While Solang can produce a lot more optimized code for Wasm targets, this comes at the cost of loosing compatibility with some Solidity language features, most notably inline assembly. “Solang Solidity” contracts use SCALE ABI encoding, which integrates better with Polkadot overall, but is again loosing compatibility. The end result is effectively that we have a new Solidity dialect, which unfortunately isn’t highly compatible with “Ethereum Solidity” source code nor with existing tooling infrastructure. However, since any language targeting LLVM also runs in our contract runtime, we should value higher compatibility over higher performance for Solidity: Expensive workloads can for example be implement in
ink!
.
Instead, we leverage YUL (which wasn’t yet available when the work on Solang started initially), an intermediate representation (IR) used by solc
: Instead of directly compiling Solidity to LLVM IR, we can let solc
generate YUL IR, and compile that to LLVM IR. As an IR, YUL is a lot simpler and a much less moving target than Solidity; a lot less work is required to build a compiler that translates YUL IR to LLVM IR.
This is the exact same approach ZKSync
is following with their zksolc Solidity compiler. By re-using some of their code base, we were able to hack together a working PoC to run a recompiled flipper contract on pallet contracts
quickly.
TL;DR:
- Using
solc
to process Solidity source code spares us a lot of work. - Recompiling YUL (and EVM byte code as a fallback if needed) dramatically improves Solidity compatibility on PolkaVM.
- Getting tooling and wallets to support our runtime becomes simpler.
New RISC-V contracts runtime: Comprehensive benchmarks
Ideally, our RISC-V runtime achieves much better execution performance than Wasm and EVM runtimes while also retaining very competitive startup and compilation times.
Initial benchmarks showed that for computationally intensive code, RISC-V might outperform Wasm contracts by more than an order of magnitude - EVM performs even worse here anyways. Which enables exciting new applications so far not possible to realize directly inside a smart contract (for example, verifying STARK proofs without relying on any specific host functions - yes that’d still be slower than using a host functions but we gain a lot of flexibility).
However, traditional contract workloads aren’t computationally heavy; they execute little code per transaction. Here, fast startup and compilation times is king: A contract runtime exhibiting even native code execution performance but at the cost of doing a lot of work on compiling contract code still looses against in-place interpreters in the average case.
We want our contract runtime to exhibit excellent properties in both dimensions! To confidentially achieve this goal, we are setting up a comprehensive benchmark suite, comparing different Solidity compatible contract platforms like pallet-contracts
and pallet-evm
.
We’ll be measuring wall clock times for the runtime and setup parts. We aim to use a diverse set of contracts:
- Synthetic ones (e.g. small code that does computational heavy work, large code that does only very little computational work and the like)
- Classic contract use cases like ERC20 token transfers or ERC721 NFT mints
- Some of the most popular contracts on ETH mainnet
- New use cases for RISC-V (e.g. cryptographic computations currently infeasible on EVM or even Wasm).
Wasm based runtimes will be able to run ink!
as well as Solidity cases; cross-validation against other Wasm and EVM interpreters or even eBPF is a possibility too.
If you feel like any specific contract or algorithm should be included into this benchmark suite, please let us know here!
Summary
This post covers new developments I’ve been actively working on at the derived Contracts Team at Parity. We hope to deliver a first working version of the compiler as well as a conclusive smart contracts benchmark report later this year. Stay tuned for future updates!