Posted 10 months ago | by Catoshi Nakamoto
Tackling Social Scalability
Rollups are currently a heated topic in the Ethereum community, and for a good reason. It is clear that the current Ethereum architecture is not ready for mass adoption, with gas fees fluctuating wildly, sometimes reaching such prohibitive heights that the network gets gentrified and entire DApps become effectively unusable. The infamous scalability problem has been proven very hard to solve without compromising on security and decentralization. Rollups, however, are gaining more and more traction and support, becoming almost universally considered to be one of the key scalability solutions for Ethereum’s woes. Vitalik himself suggested a rollup-centric roadmap for Ethereum that is worth the read.
At Cartesi, we are building a rollups solution. Check out the previous articles written, by my awesome colleagues, about it: The Rollups Rollout Announcement introduced the different pieces of our solution and offered a brief explanation of each of them. Readers looking for more details can delve into Erick de Moura’s “Cartesi Rollup — Scalable smart contracts built with mainstream software stacks” where they’ll find the reasoning behind many of our design decisions and in-depth explanations of the rollups behavior.
This article is part of the Rollup Rollout series, meant to get users and developers up to speed on what we’ve been building in the Rollups team. Two great articles have been released in this series: State Fold and Transaction Manager. Both of them introduce open-source Rust tools that aid interactions with the blockchain. In this article, we’ll summarize some topics we’ve written about before and expand on them. Then, we’ll focus on the on-chain smart contracts that make the Cartesi Rollups possible.
Rollups, What are They?
There are multiple ways to conceptualize scalability on blockchains, though it is commonly divided into two main components: data scalability and execution scalability. Rollups deal mainly with the latter — improving the former as a fortuitous consequence. As he often does, Vitalik Buterin wrote an informative post in which he highlights the relation between data and execution that I recommend.
To put it simply, rollups achieve scalability by moving the bulk of the computation outside the blockchain, using the ledger as a data source but not as an execution environment. As such, the rollups solution contains both off-chain and on-chain components.
Users interact with a rollup through Ethereum transactions. They send it messages (inputs) that define a computation to be processed and advance the state of the rollups machine. Interested parties run an off-chain component that watches the blockchain for inputs — understanding and executing the state updates. Once in a while, the state of the machine is checkpointed on-chain.
Checkpointing a state on-chain has to be done responsibly, which is guaranteed by the on-chain part. Here it is important to differentiate between two possible ways to gate-keep state updates: validity proofs and fraud proofs.
In validity proof schemes, every state update comes accompanied by a cryptographic proof, created off-chain, attesting its validity. The update is only accepted if the proof successfully passes verification on-chain. Zero-Knowledge Proofs are frequently used for this, which is why these types of rollups are usually referred to as ZK Rollups. Validity proofs bring the big benefit of instant finality — as soon as a state update appears on-chain, they can be fully trusted and acted upon. The choice, however, also brings less than ideal properties: generating ZK proofs for general-purpose computations is, when possible, immensely expensive and each on-chain state update must pay the extra gas fee from including and verifying a validity proof.
Fraud-proof schemes work by a different paradigm. State updates come unaccompanied by proofs, they’re proposed and, if not challenged, confirmed on-chain. Challenging a state update proposal is done by the use of fraud proofs, which can be divided into two categories: non-interactive fraud proofs and interactive fraud proofs.
Non-interactive refers to the fact that the challengers can prove that a state update is invalid in one single step. With interactive fraud proofs, the claimer and challenger have to, mediated by the blockchain, partake in something similar to a verification game. The assumption that state updates will most likely be honest often gives solutions like this the name of Optimistic Rollups. Naturally, this optimism comes paired up with financial incentives for honest behavior and guarantees that, unless the proposed false state is undisputed for a significant amount of time, it will never get accepted.
At Cartesi, we chose to create Optimistic Rollups with interactive fraud proofs. The interactive model was chosen because it imposes a higher ceiling to the size of computations that can be executed. With Cartesi Rollups we’re tackling an additional scalability aspect that was not mentioned at the beginning of this article: social scalability.
The idea that developers will be able to build their DApps using mainstream software stacks, libraries, and tools they’re used to is very dear to us. We want to bridge the gap between day-to-day and blockchain developers. We want developers to build impossible DApps, the ones only that need complex and powerful software stacks.
Tackling social scalability required an awesome VM, and we built one. The Cartesi Machine runs on a deterministic RISC-V architecture, capable of running a general fully self-contained Linux operating system. When giving developers the ability to run Linux on a fast VM, we also need to give them access to a dispute resolution method capable of adjudicating massive computations — such as the verification game.
Data Availability, Transaction Improvements, and Aggregation
As mentioned in the previous sections, rollups move the execution environment to layer-2 but still use layer-1 for its data availability guarantees. This doesn’t mean, however, that bringing execution to layer-2 doesn’t have positive impacts on the amount of data on-chain and the cost of transactions.
There are multiple strategies to translate the improved execution environment into more efficient ways to deal with data. Since much of the data doesn’t have to be known by the smart contracts, it can be stored inside Ethereum in a cheaper way (e.g., calldata instead of storage). It is also possible to transform data into computation by using techniques such as compression methods and signature aggregation. That is what aggregators do, they receive inputs off-chain and batch them together into a single bundle before sending them to the blockchain. The idea behind it is that, by aggregating user’s signatures, they can dilute the cost per user in that bundle of transactions — creating cheaper transactions.
There are a lot of different design decisions to be made when creating an aggregation scheme. Those choices impact a variety of different features such as order guarantees, censorship resistance, and AEV (aggregator-extractable value). The details on our design and analysis of those concepts will come in a later article.
The shift from global to local consensus means that data availability has to be guaranteed for a smaller set of interested participants. Hungry DApps can, therefore, choose different sources for storing data, as long as their users are comfortable with the tradeoffs.
The rollups smart contracts, designed to mediate the relationship between the off-chain rollups with other smart contracts and externally owned accounts (EOAs), were built for modularity. Each module has clear responsibilities and communicates with others through well-defined interfaces. This gives us lots of flexibility when it comes to customizing, configuring, and upgrading each part. DApps that need a different model for their on-chain input sanitation can easily swap theirs for the current implementation, for example.
There are two different agents that interact with the smart contract infrastructure: users and validators. Both run off-chain nodes but interact with the on-chain rollups in different ways. Validators are tasked with checkpointing the state of the off-chain machine on-chain, which includes fighting possible dishonest validators to ensure the prevalence of the honest claim. Users, on the other hand, send inputs to the machine, either directly or through aggregators, and execute the outputs they’re interested in.
In order to avoid over interacting with the blockchain, validators don’t checkpoint every new state update on the off-chain machine. They do it at the end of an epoch, which are batched inputs that follow the same cycle.
We can imagine epochs in three different states:
- Accumulating, when the epoch is open and waiting for inputs.
- Sealed, when the inputs for that epoch are well defined and the validators are preparing to or sending their claims. Sealed epochs can also be under dispute.
- Finalized epochs, when consensus was reached and the outputs can be safely executed.
The on-chain machine, depending on the phase it is at, can contain one or two epochs. These are the possible phases:
- Input Accumulation: there is a single accumulating epoch, active and waiting for the inputs it is going to batch.
- Awaiting Consensus: there are two epochs. A sealed one, for which validators are preparing to or sending their claims, and an accumulating one, which is active and receiving inputs.
- Awaiting Dispute: also has two epochs. A sealed one and an accumulating one. The sealed epoch is under dispute. Two conflicting claims were received and the validators are enrolling in a verification game to decide which claim stands. Since the sealed epoch’s inputs are well defined, honest validators will always reach the same claim. A dispute necessarily means that a claim is provably false.
The trigger for phase changes is explained in the previously mentioned Cartesi Rollups article.
Now that epochs, phases, and interactions are known, let’s go over each of the on-chain modules and explain their purpose:
The DescartesV2 Manager is responsible for synchronicity between the modules. It defines the duration of the different phases and notifies the other modules of any phase change. Among others, the responsibilities of this module are:
- Define for which epoch, depending on the current state and deadlines, an input is destined to.
- Receive and forward claims to the validator manager.
- Forward disputes to the dispute resolution module.
- Forward the result of disputes to the validator manager.
- Forward the summary of finalized outputs to the output module.
- Notify other modules of phase changes.
Inputs, for the blockchain, are but a sequence of meaningless bytes that form messages to be understood by the layer-2. On-chain execution resources are not wasted in trying to make sense of an input — we rely on the computing power of our VM for decompressing, interpreting, and processing them off-chain.
As explained above, the on-chain contracts often have two concurrent epochs: a sealed but unfinalized epoch and an accumulating epoch. The input contract keeps one inbox for each of those epochs, switching between them depending on the DescartesV2 Manager’s notifications. For anyone to be able to synchronize the machine from its beginning without needing to trust a data provider, the full content of inputs is always present in calldata. In storage, which needs to be used in a more parsimonious way, we keep a single hash for each input of an active epoch. This input hash summarizes both the input itself and its metadata — sender’s address and time of reception. Notice that this input implementation is permissionless, the permission layer is delegated to the off-chain machine which will, for example, judge if a sender is allowed to do what their input wants to do.
Portal, as the name suggests, is used to teleport assets from the Ethereum blockchain to DApps running on Cartesi Rollups. Once deposited, those Layer-1 assets gain a representation in Layer-2 and are owned, there, by whomever the depositor assigned them to. After being teleported, Layer-2 assets can be moved around in a significantly cheaper way, using simple inputs that are understood by the Linux logic. When an asset is deposited, the Portal contract sends an input to the DApp’s inbox, describing the type of asset, amount, receivers, and some data the depositor might want the DApp to read. This allows deposits and instructions to be sent as a single Layer-1 interaction.
One could think of the Portal as a bank account, owned by the off-chain machine. Anyone can deposit assets there but only the DApp — through its output contract — can decide on withdrawals. The withdrawal process is quite simple from a user perspective. They send an input requesting a withdrawal, which gets processed and interpreted off-chain. If everything is correct, the machine creates an output destined to the Portal contract, ordering and finalizing that withdrawal request.
An output is a combination of a target address and a payload in bytes. It is used by the off-chain machine to respond and interact with Layer-1 smart contracts. When outputs get executed they’ll simply send a message to the target address with the payload as a parameter. Therefore, outputs can be anything ranging from providing liquidity in a DeFi protocol to withdrawing funds from the Portal. Each input can generate a number of outputs that will be available for execution once the epoch containing them is finalized.
While the output contract is also indifferent to the content of the output being executed, it enforces some sanity checks before allowing its execution: Outputs are unique and can only be successfully executed once. Outputs are executed asynchronously and don’t require an access check. The order of execution is not enforced — as long as outputs are contained in a finalized epoch and were not executed before, the contract will allow their execution by anyone. The Output module ensures, however, that only outputs suggested by the off-chain machine and finalized on-chain can be executed. It does so by requiring a validity proof to be sent with the execute call.
The Validator Manager module was created to help DApps manage their claims, claim permissions, and punishments for bad behavior. Initially, our suggested implementation for this module includes the following characteristics: the set of payable validators is defined in construction time, validators send a claim for every epoch and those that lose a dispute are kicked off the validators set. As explained above, DescartesV2 manager receives claims and redirects them to the Validator Manager. When receiving a claim, the validator manager checks which other claims have arrived at that epoch and returns the information DescartesV2 Manager needs to continue. The module can respond to received claims in one of the following ways:
- If the sender is not a validator or the claim is invalid, the transaction reverts.
- If the claim is valid, doesn’t disagree with any of the other claims in the epoch, and does not generate consensus, it returns a “No Conflict” response.
- If the claim is valid but disagrees with another claim for that epoch, it warns DescartesV2 Manager that a conflict is happening and what are the conflicting claims and claimants involved. When that dispute is resolved the validator manager module gets notified so it can deal however it likes with the validators involved. In our initially suggested implementation, the loser of a dispute gets removed from the validator set.
- If the claim is valid, agrees with all other claims in that epoch, and is the last claim to be received, it lets DescartesV2 know that consensus was reached. This allows the rollups DApp to finalize the epoch and allow for the execution of its outputs.
Regardless of what the name might suggest, validators do not interact with this module at all.
Disputes occur when two validators claim different state updates to the same epoch. Because of the deterministic nature of our virtual machine and the fact that the inputs that constitute an epoch are agreed upon beforehand, conflicting claims imply dishonest behavior. When a conflict occurs, the module that mediates the interactions between both validators is the dispute resolution.
The Cartesi rollups is a base infrastructure created to allow developers to build amazing applications — its value derives from all the cool things created on top of it. When developing this kind of framework it is often interesting to release an initial version, with well-defined interfaces, and then continuously improve it. The goal of releasing software this way is to allow developers to build their applications in parallel, without having to wait for a pristine final implementation of the base framework.
Disputes are an example of infrastructure that can be added a posteriori since they’re rare and don’t heavily impact the behavior of a DApp — other than possibly delaying finalization. Therefore, to accelerate deployment and allow developers to build with us sooner rather than later, we decided to release the first version without disputes.
Having said that, we haven’t neglected building the disputes at all. In fact, our Descartes SDK has a dispute module that utilizes our arbitration dlib. The Arbitration dlib implements the previously mentioned verification game for our RiscV VM. For Cartesi Rollups, however, there is some extra work to be done when integrating the arbitration dlib: we now need to find the exact input in which the validators disagreed. The good news is that while you are implementing all those cool DApps on top of our rollups, we’re implementing a robust dispute resolution module that will be readily connectable.
At Cartesi we have a very strong research team, always studying new designs, solutions, and improvements. It is frequently a challenge for engineering to catch up to all the cool research we’ve been doing. There is, therefore, a list of improvements that we’re looking to implement for DescartesV2: updates in the architecture, gas optimizations, example applications, improved off-chain components, and so on. Stay tuned!
Special thanks to
for the feedback and review.
Cartesi is a multi-chain layer-2 infrastructure that allows any software developer to create smart contracts with mainstream software tools and languages they are used to while achieving massive scalability and low costs. Cartesi combines a groundbreaking virtual machine, optimistic rollups and side-chains to revolutionize the way developers create blockchain applications.
Cartesi’s Ecosystem Links:
Discord (Development Community): https://discordapp.com/invite/Pt2NrnS
Telegram Announcements: https://t.me/cartesiannouncements
Original article published on Cartesi’s Medium.