Standalone
Smart Contract Development in a Scalable World
Smart contract development in a scalable world
By: Barnabé Monnot
Whether multi- or cross-chain, future development of decentralized applications will have to account for the variety of environments DApps will inhabit. While the EVM has accrued large network effects in the years since its inception, competing designs on Solana or Cosmos promised improved smart contract languages and toolings. Meanwhile, infrastructure based on Ethereum such as Starkware's validity rollup forego the Solidity/EVM route to build upon the strengths of their SNARK-based architecture.
Here we map the ecosystem for a developer building in this diverse future. We start the journey from the EVM and its incarnations on secondary layers, observing how rollups preserve or break certain operations of the Ethereum base layer. Finally, we move on to new languages custom-built for their runtime environment and broaden our scope further to ecosystems beyond Ethereum.
A quick primer on DApps and EVM development
Programs deployed on the Ethereum base layer are known as smart contracts. Today, Solidity is the language of choice to write the code which specifies a smart contract. Once written, the Solidity code is compiled to bytecode format, providing the ticker tape of Ethereum Virtual Machine (EVM) opcodes to execute when the smart contract is called. Opcodes are elementary instructions, such as "add two variables" or "store permanently this piece of data". The EVM defines a stack- and memory-based environment for the execution of bytecode.
To write secure smart contracs, developers make use of a variety of tooling. Unit tests are written to guarantee that inputs to a function call return the expected output. Such tests may be written in Javascript, in the popular Hardhat development environment, or directly in Solidity, as in the up-and-coming Foundry toolkit. Fuzzing frameworks attempt to break required properties of function calls by submitting streams of random inputs, sometimes tuning randomness towards being most adversarial. Symbolic execution relies on evaluating a function call "symbolically", replacing a specific input ("42") with a variable ("x"), and asking whether any value of that variable would break some required property. A step further, critical smart contracts may be formally verified too, by writing a model specification of the contract and proving properties of the model.
Tracking the EVM in Optimistic Rollups
All the tooling detailed above relies on the EVM running as specified and executed on the Ethereum base layer. Sidechains such as Polygon PoS or Binance Smart Chain exactly replicate the runtime environment of the Ethereum base layer, hence all tooling immediately applies to smart contract development on either platforms.
This is not always the case for rollups. Optimistic rollups secure themselves by allowing anyone to challenge a state transition done on the rollup. A challenge implies that a specific part of the rollup's execution must be replayed on the Ethereum base layer, to arbitrate the conflict. Building such challenges, called fraud proofs, for the whole instruction set of the EVM was not an easy task, so early rollup programs looked like custom-built DApps with fraud proofs tailored to specific behaviors.
Optimistic rollups execute transactions and the execution is assumed to be correct, unless a challenger proves it incorrect by replaying part of the execution.
This is not what we want. A developer who built a DApp for the Ethereum base layer does not want to modify their code to deploy on a different platform. They may be content with compiling their source to a different target, and letting the target run in a different environment than the EVM. But this implies engineers of this non-EVM environment must update their "transcription" compiler whenever the EVM is updated, or whenever they update their own execution environment. The transcription process may also break properties that were proven to hold on an EVM environment, but no longer after the transcription.
The ideal then, in this model, is to remain as close as possible to the EVM. The DApp developer writes smart contract code, the code is compiled to bytecode for EVM execution, deployed on an EVM-based platform (e.g., an optimistic rollup) and fraud proofs are built by replaying the "rollup EVM" on the "base layer EVM", with minimal work to synthesize this rollup EVM on the base layer EVM. This also allows the rollup to quickly adopt upstream changes to the base layer's execution environment, by simply re-compiling the "rollup EVM" runtime to the newer version of the "base layer EVM".
Today, the optimistic rollup Optimism has committed to full EVM-equivalence, while Arbitrum expanded its compatibility with the EVM in its Nitro release made in August 2022.
Proving the EVM in Validity Rollups
For validity rollups who submit a cryptographic proof that off-chain execution was performed correctly, the holy grail is the zkEVM, short for "zero-knowledge EVM". As we know, the zero-knowledge part doesn't have much to do with validity rollups, referring to the ability for a prover to convince a challenger that a statement is true given a private input ("This person is above 18, though I am not telling you how old they are"). Yet obtaining a succinct proof of correct execution, a.k.a. validity proof, also gives us that "zero-knowledge" property, hence the name.
So a zkEVM is a circuit which, given a set of transactions, is able to output the state of the rollup once these transactions are executed along with a validity proof that the state was computed correctly. The transactions induce EVM-based computation, with the zkEVM responsible for proving correctness of the computation.
The rollup executes the transactions, and outputs a validity proof. With an EVM-equivalent zkEVM, regular Ethereum contracts and transactions can be proven.
Here again, we want to know that the DApp we write for Ethereum's base layer behaves the same once we deploy it to a validity rollup. If the rollup's proving circuit does not fully match the EVM, it may require that DApps be re-compiled to a target including only a strict subset of the base layer EVM operations.
Same as optimistic rollups, EVM-equivalence in validity rollups is more like a spectrum, a metaphor and classification we borrow from Vitalik Buterin. The ultimate form ("Type 1") is a circuit able to prove native execution on the Ethereum base layer itself. However this may not be necessary for a development environment mirroring exactly the experience of writing DApps for the base layer.
Such an ultimate zkEVM mirrors the base layer down to how the state of the DApp is represented. When a smart contract saves a variable, it is written to the Merkle-Patricia tree representing the whole state of Ethereum, recorded by all nodes following the base layer. The ultimate zkEVM proves that the piece of the data is recorded to the tree. However, changing the data structure holding the state, to make it more amenable to validity proofs, does not really change how the DApp itself behaves. A developer working on such a modified EVM would not see the difference while writing their contracts. This constitutes Type 2 zkEVM, proving correct execution while using data structures distinct from those on the Ethereum base layer.
zkEVMs may distance themselves further from the EVM environment, to reduce proof generation time (an important bottleneck of current validity rollups) or go to market earlier. Being EVM equivalent up to tweaking gas costs ("Type 2.5") to reflect operations inducing high proving times may break some tooling mostly related to gas estimation, but it offers a more optimized execution environment. A step further: certain EVM operations or precompiles (short pieces of highly optimized code that smart contracts can make use of) are particularly tricky to represent for proving. Disabling such features, while hampering smart contracts relying on them, decreases proving time again ("Type 3").
Finally, DApps written for an EVM target in Solidity can also be "transpiled" to a different virtual machine target, perhaps one for which generating validity proofs is much easier ("Type 4"). Starkware's Cairo VM is such an environment, with the Nethermind "Warp" transpiler taking Solidity code and compiling it down to the Cairo instruction set. A developer looking to port their base layer, Solidity-written DApp to CairoVM must be mindful of what is lost in the translation from an EVM target to CairoVM. It is also possible for a new DApp to be written directly in the Cairo language and use associated tooling instead.
Beyond the EVM
The EVM was the first smart contract environment to go to market. Successful DApps built on Ethereum entrenched further the tooling and developer community around the EVM's languages and idiosyncracies. Its moat and network effects increased as popular sidechains and rollups adopted its principles to attract users while reducing the cost for deploying existing applications.
Yet today the EVM is challenged by multiple other candidates. In this section, we look at some of them and attempt to understand why developers might decide to forego the EVM and consider alternative environments.
In debates about the EVM's drawbacks, its lack of native parallelism is often pointed out. With access lists, Ethereum has made steps towards a more declarative style of resource allocation. Transactions are able to pre-declare which state accesses they intend to perform, paving the way towards parallelism when multiple transactions execute, each with distinct state accesses. Yet the account model at the base of Ethereum's state representation does not quite natively allow for parallelism.
On the other hand, UTXO-style transactions are more natively parallel. On Bitcoin, it is possible to update the state of the ledger by running transactions side-by-side, as long as the UTXO sets between each other are distinct, a trivial property to check. FuelVM, developed by Fuel Labs, intends to generalize such a model to smart contract applications. FuelVM doesn't stray too far from EVM foundations, but adds more facilities for an explicitly parallelizable execution environment. Launched first as an optimistic rollup on Ethereum, and subsequently generalized to an all-purpose execution layer, Fuel comes with its own programming language, the Rust-inspired Sway language.
Co-developed with Diem (previously Libra), the failed attempt by Meta (previously Facebook) to create a permissioned network behind a stablecoin, the Rust-based Move language continues to percolate across the ecosystem. By making ownership of objects explicit, Move natively enforces invariants common to smart contract development such as "a coin can't be held by two parties at once". Move appears in new projects such as the monolithic L1's Sui and Aptos, as well as on Solana where it can be used to write DApps.
On Cosmos, CosmWasm had established a strong presence, powering the smart contract ecosystem of Terra. Following Terra's demise and the rejection of the Cosmos Hub's proposition 69, which advocated for deploying CosmWasm on the Hub, the future of CosmWasm seemed more uncertain. Still, CosmWasm features prominently in the Cosmos Hub's vision for the second phase of Cosmos.
Conclusion
While the EVM still attracts considerable mindshare and developer attention, its shortcomings are addressed by new execution environments and related languages to build secure and performant DApps. It is too early to tell whether any of the contenders named in this post will rise to the EVM's ubiquity, but it is clear that as blockchain and decentralized applications experience greater user adoption, each environment could find its relative strengths and participate in the larger constellation of available solutions.
So many books, so little time!