Disclaimer: These are just some thoughts of mine. They currently have no implications on the Starknet roadmap.
This post outlines some thoughts around the following topics:
-
Why should we support multiple smart contract languages?
-
What core stack(s) should we choose for Starknet?
-
How can we implement them, and how painful is it to add things?
-
What migrations are necessary and how should we go about them?
When should you care? Nothing here is actionable in the upcoming months, so take your time.
Stack of a zk-blockchain
Here are the key terms. You can skip to the diagram below for some visuals (ignore the red arrows).
-
High level language (HLL) not coupled to blockchain
-
Smart contract languages (SCL) which extend high level languages with blockchain-related notions of state, syscalls, etc.
-
Blockchain VM (bcVM) which defines a blockchained-oriented instruction set architecture (ISA) that provides resource metering, state, syscalls, and safety.
-
zkVM which defines a proving-oriented ISA.
In Ethereum there are just two levels to the core stack: contract languages (Solidity, Vyper) and the blockchain VM (EVM). Ethereum is currently not a zk-blockchain as its protocol involves no proofs of EVM execution.
Rollups have another level in their stack: zkVM i.e a provable (and proof-friendly) arithmetization of a VM.
-
EVM-based rollups have a zkEVM, and compile EVM bytecode to their zk instruction set.
-
Starknet has an entirely different stack, with Cairo as the SCL, Sierra as the bcVM, and Cairo VM as the zkVM.
Why? Building for adoption
Our goal is to bring adoption to Starknet. The consumer-facing part of our stack is the SCL(s), âconsumedâ by SC developers. All other things equal, devs obviously prefer languages that are familiar and/or have a good reputation/adoption. Blockchains with exotic SCLs must fight back with an efficient stack (causing lower transaction fees & latency) and other features.
Historically, both the Ethereum and Starknet stacks developed bottom-up; the SCLs are both exotic.
-
EVM was invented to facilitate general computation on blockchain. Solidity was subsequently invented to provide good SC devX.
-
Cairo VM was invented to avoid manual AIR-writing per business logic. Then CairoZero was invented as a low-level language for writing exchange-oriented business logic. Later arose two problems: how to charge for reverted Starknet transactions (red-green) and the devX, respectively motivating Sierra and high level Cairo. Note the direction was bottom-up: the SCL was invented to fit the existing VM.
To improve adoption, we can attract devs by adding SCLs to Starknet. Some examples:
-
Solidity, highly adopted in blockchain as the main SCL in the Ethereum ecosystem
-
SCLs based on HLLs that are adopted in web2
-
Existing ones include Solanaâs flavor of Rust, Arbitrum Stylus, CosmWasm
-
Perhaps weâll want to define our own SC extensions for Rust, typescript, python, etc
-
What core stack(s)?
Thereâs a lot of weight to attractive SCLs and to other features of the core stack.
Candidate directions
Pro | Con | Remarks | |
M31 Cairo | Easiest way toward lightning-fast client-side proving Bonus: HLL Cairo as the best (fastest & friendliest) provable language | Other HLLs & SCLs accessible only through extra compilation interpretation layers | |
LLVM-friendly | May attract Web2 devs: HLLs that compile to LLVM are supported, and can be extended to SCLs | LLVM forgets types, so type-safety unclear No off-shelf bcVM | Athena bcVM WIP |
WASM-friendly | SpaceMesh advised against, due to ever-growing instruction set | ||
Solidity Friendly | Helps unlock Solidity devs | Doesnât provide tooling, which is coupled to EVM and Ethereum RPC | |
Move-friendly | Benefit from a bcVM built by expertsBootstrap Aptos & Sui ecosystem | Not LLVM-friendly | Typed Starknet |
Priorities?
Depends on the goal. IMO here are the most interesting goals as of Oct 13, 2024 and some paths toward them:
-
Lightning fast client side proof & verification on Starknet
-
M31 Cairo
-
Rusty SCL + Rust-friendly stack to wrap Rust verifier in a contract
-
-
Attract Web2 devs
-
Pursue an LLVM-friendly stack (bcVM unclear)
-
Compile HLLs to MoveVM and write a Move zkVM?
-
Compile HLLs to Sierra (WIP by Reilabs)
-
-
Attract Solidity devs
Do we need to choose just one direction for years?
No. See next section.
How? MultiVM!
â ď¸ What follows is just a sketch of an idea; apologies if imprecise, unclear, inaccurate, etc.
There are three flavors of solutions, ranked by efficiency:
-
Native Multi-VM â prove AIRs for more instructions
-
Compile everything to one core stack (example: LLVMâSierra WIP by Reilabs)
-
Write interpreters in Cairo (example: RISC-V interpreter WIP by MassaLabs; Kakarot )
Conceptually, option #1 is âdownwardsâ while option #2 also involves horizontal steps across stacks.
Some advantages of #1 over #2:
-
Adding a new stack is easier:
-
Option #1. Nothing across stacks but do need AIRs (which weâre best at). Weâll also benefit from tooling that will be naturally developed as part of other stacks.
-
Option #2. Compilers across stacks can be unnatural (e.g EVMâCASM) both in principle and tooling-wise.
-
-
In option #2, moving to a new distinguished stack sucks. Choice between two evils:
-
Throw away the compilers to the previous distinguished stack and develop new stuff
-
Only develop a compiler from the old to the new distinguished stack, but incur inefficiency of two layers of compilation from the other stacks.
-
Weâll focus on option #1: native multi-VM. Below we outline two approaches. The modular one manages several separate core stacks that operate on different (but possibly intersecting) parts of the Starknet state. The monolithic one is founded on a big monolithic ISA.
-
From the product PoV, the modular approach has the slight benefit that we can use the separate stacks for other products/purposes. I donât see additional differentiators atm.
-
Engineering PoV â deferring to engineering. Two observations:
-
The monolithic approach incurs some complexity cost due to many constraints being used in the same proof (very large AIR).
-
The modular approach has a more complicated flow using applicative recursion.
-
Modular â multiple operating systems
The state of Starknet is partitioned per-VM. Adding another stack means appending new parts to the Starknet state that are compatible with the zkVM that will prove them. For example, adding the M31-Cairo stack means a new part of the state whose commitment hash may be Blake/M31-Pedersen, and not the current mix of Pedersens and Poseidons. The old state can be unaffected.
Each part of the state is managed by its own operating system. OSâ is a program that compiles to assembly for zkVMâ â just as the current OS compiles to CASM.
So far we can handle disjoint stacks, but we really want composability. To this end we need to define several things:
-
How does a transaction specify entry points to contracts from multiple stacks?
-
How can contracts communicate across stacks? Suppose a function f in contract A wants to call a function g from contract BâŚ
-
How can a contract change to a class from a different stack?
-
How is inter-stack communication proven? OSâ manages stack m but it doesnât âunderstandâ n. How to prove a transaction that goes back and forth between the stacks?
Weâll cover each in turn.
-
Either transactions will specify entry points in âheterogeneousâ, stack-specific formats, or weâll have some uniform unstructured identifiers.
-
The SCLs will refer to contract interfaces in âuniversalâ unstructured terms. Each SCLâbcVM compiler will require a utility to specialize the universal description to its zkVM.
- @ilyalesokhin suggests using the ABI, and also thinks associated utilities will be straightforward to implement.
-
The
replace_class_hash
syscall will be aware of all stacks. Perhaps this is relevant for more syscalls. (Is it cleaner to move this logic into the state manager?) -
Hints.
-
During the execution phase, every context-switch will be marked. During the proving phase, each OSâ will:
-
Receive will receive hints about intermediate states.
-
Externalize intermediate state data as public outputs.
-
-
The hints will be jointly verified by a âstate managerâ program in an applicative recursion proof. The state manager is written in whatever HLL preferred by engineering (donât need SCL).
-
There is inevitable overhead in translating between the different state representations for each stack.
-
Universal translation logic can sit in the state manager.
-
Each OS can translate to some âuniversalâ unstructured encoding, so the state manager only deals with book-keeping.
-
-
- This design draws from the syscall handler and also from book-keeping that arises in proof-chains.
Monolithic â large instruction set
Bundle everything into a big ISA. TBD whether it also makes sense to bundle everything into a big bcVM. Compiler work seems more complicated to me, but leaving such discussions to engineering.
Migrations
This section has some proposed procedures for migrating Starknet (classes, state, OS) from its current core stack to another one. Everything is very naive; apologies if also stupid.
In the multi-VM approach, I think we can avoid migrations entirely:
-
There are no necessary large scale migrations.
-
To avoid breaking changes when adding a new stack, we can move the state to e.g a forest of several trees indexed by some sequence numbers. This is similar to DA trees in the Volition design.
State. One-time proof of conversion: we prove the conversion from the current state representation to the new one. For example, to move from the present 252 Cairo + mixed Pedersen-Poseidon commitment to M31 Cairo with e.g Blake, weâll prove type conversions and also compatibility of commitments using the old hash and the new.