Volition: Hybrid Data Availability Solution

One of the major challenges L2 rollups face today is the high cost of L1 data availability, which can account for a significant portion of transaction fees. We propose Volition as a way to address this challenge, by giving developers and users the ability to choose between multiple data availability solutions. In this post, we will discuss the design and remaining open questions.

We want to thank all reviewers, especially the builders’ council, for their comments and reviews.


Introduction

L1 data availability can be expensive due to the fact that all state diffs are sent as calldata to Ethereum. In March 2023, for example, L1 data availability (L1DA), meaning the state diffs sent to Ethereum, accounted for over 93% of the transaction fees paid on Starknet.

To address this challenge, Starknet will let developers use L2 data availability (L2DA) mode, per their choice, as a complementary possibility to the L1DA. With L2DA, only a commitment to the L2DA mode is posted on L1 so that the state transition can be verified by Ethereum, but the data itself is not posted on L1, Instead it is posted on L2.

This approach is made possible thanks to the Validity Rollup principle: Verifying a STARK proof on L1 is sufficient to guarantee the validity of the transaction’s execution on L2, with no need to send the detailed information of the transaction to Ethereum (unlike optimistic rollups that base their security on having the entire data on Ethereum for verifying fraud proofs). Using the L2DA solution will enable a data availability cost reduction of at least 10X.

This post discusses the importance of both types of data availability modes and presents Volition – the innovative solution that combines the two. Specifically, we explore the concept of a hybrid data availability mode, which allows developers to use both L1 and L2 data availability modes in the same contract. Additionally, we discuss how this solution can be applied in practice, using the example of ERC-20 contracts.

But what about EIP-4844? Once EIP-4844 is available on Ethereum, Starknet will use it to replace the current method of L1DA. However, we should keep in mind that the cost of data availability is determined by market forces of supply and demand. Therefore, the exact cost of EIP-4844 is not known yet, as it will involve a separate market used by all rollups (and probably other usecases) on Ethereum. The introduction of a dedicated market for Starknet users has the potential to establish a cheaper pricing for data availability. This specialized market could offer advantages in setting prices tailored specifically to Starknet users’ needs and requirements.


Principles for Hybrid Data Availability

Now that we understand the potential benefits of L2DA mode, it is important to consider the trade-offs and whether relying solely on this mode is feasible. The security of state transitions, verified by STARK proofs on L1, remains the same in both L2 and L1 data availability modes. The difference lies in the mechanism that guarantees data availability.

In the L1 solution, data availability is ensured by Ethereum consensus (both in the current solution and with EIP-4844). On the other hand, in the L2DA mode, data availability depends on the L2 consensus layer. Sequencers in the decentralized protocol only approve a block if they possess a fully updated state.

However, it is crucial to acknowledge the risk associated with relying exclusively on L2DA: The potential for a malicious majority stakeholder attack on L2. In this scenario, we still have the commitment to the data, but accessing the data itself might become problematic.

This risk can be managed by using both L2 and L1 data availability modes. This approach allows developers to benefit from the cost efficiency of L2DA for cheaper and highly used assets, while maintaining the more secure L1DA mode for valuable assets.

By supporting both L2 and L1 data availability modes, Starknet provides developers with flexibility and the ability to optimize data availability based on the specific requirements of their applications. This way, they can leverage cheaper data availability while ensuring the security of high-value assets.

The key principles to consider for the hybrid data availability mode for Starknet are as follows:

  • The failure of one DA mode does not affect other DA modes. Specifically, the ability to access and execute transactions on the other DA modes should be possible.
  • The account contract must always be able to operate, even after a data availability crisis.
  • Builders should have the flexibility to use L1 and L2 data availability in every contract, and potentially allow the users to choose.
  • Applications should have the ability to move variables between the data-availability modes (L2 and L1), even in the event of a data availability crisis (although the data won’t be accessible, the contract should still be able to function).

One network, multiple data availability modes

How will the hybrid data availability modes work? Essentially, Starknet will hold storage for every contract in both L1 and L2 data availability modes. Currently, Starknet’s state commitment consists of commitment on two Patricia trees: one for the declared classes and one for the storage of all deployed contracts. The hybrid state will include a commitment for another Patricia tree (and maybe more in the future) that will hold the commitment for the L2DA mode. The result will be multiple trees that, together, will contain the commitment for the state: 1 - for declared contracts; 2 - for the L1DA mode of all contracts; other - for the L2DA mode of all contracts.

Each deployed contract will have the same address in all data availability modes. The developers will be able to choose for every storage variable whether to store it in L2DA mode, L1DA mode, or, for example, store a variable under the same key in both trees, in which case, they will choose in runtime from where to conduct the read/write operations.

By making this separation of the state between the different DA modes, we ensure that the failure of one does not affect the others. Let’s consider a case where the L2DA mode has failed. This means that a state update was posted on L1, together with the commitment to the L2DA state, but the data for this state is not available. In this case, even though it is not possible to access the state of the L2DA part, Sequencers and users have the full state of the L1DA part and so can continue operating with L1DA as if nothing happened.

To allow account contracts to operate even in spite of malicious attempts to prevent access to L2DA and still reduce costs for those who will choose to store data in the L2DA mode, Starknet will maintain an account nonce in both L1 and L2 data availability modes. Every transaction will specify the nonce’s data availability mode relevant to the transaction. This way, users will be able to use their L2DA nonce for cheaper transaction fees and use the L1DA nonce (same as today) during a data availability crisis.

In the first Starknet version to support Volition the L2DA mode will be presented as described above. In the future, additional data availability modes could be added, such as a data availability committee for users who prefer a trusted party for their data availability.

As for the data cost in the L2DA mode, it will be defined more accurately in the future, after further development of the L2DA model.


Case study - ERC-20

Let’s imagine how the hybrid state could lead to cost reduction by implementing it in a standard token contract with minimal risk. A common behavior with fee tokens is a lot of activity with small amounts. As the average fee in Starknet will likely be reduced to a few cents, a user will be able to conduct thousands of transactions for a few dozens dollars, while the savings of the user might be much higher. In this case, a rational user might want to store a small amount of funds in their L2DA mode balance for common activities, while the lion’s share of their funds will be stored in an L1DA mode balance. The user could transfer funds to the L2DA “small expenses” balance once in a while.

To implement this in a standard ERC-20 token, an L1 and L2 data availability modes mapping for balances would be required, so each user would have a balance in both mappings. The user will also be able to set and change the default balance for charging. In this way, data from certain activities will be posted on L2, and data from other activities will be posted on L1.


What’s next - how will developers use it?

From the protocol perspective, the read and write syscalls will have another field which will allow specifying the DA mode to write/read from.

In order to make it more convenient and safe for Starknet builders, Cairo will allow you to annotate, for every storage variable, what data availability mode is used.

The L1DA mode will be the default mode, which will behave exactly like storage variables do today. Changes to those storage variables will be posted on L1.

The MANUAL mode, marked with #[manual_da], will allow only explicit reading and writing from the desired data availability mode, with no default mode, the contract developer will specify, with every read/write access to that var, to what data availability mode he’s aiming at.

In the example below, my_var and may_map are defined without special annotation like before, and so are kept on L1DA mode, same as before.


The Remaining Challenges

As Uncle Ben said “with great power comes great responsibility”. While Volition holds a huge potential for cost reduction, there is one behavioral risk associated with it that needs to be addressed: It is unclear how easy it will be for developers and users to understand the risks associated with different DA modes and to analyze the risk of a specific application or contract:

  • Will my contract continue working under an L2DA crisis?
  • Even if I’m sure as a developer that my contract can continue to operate, how can I be sure of other contracts that I interact with?

An L2 Data Availability crisis may not only impact the known contracts using L2DA but also affect contracts that are considered safe but actually rely on other contracts that utilize L2DA in an unsafe manner. This situation could potentially lead to significant damage and a widespread network failure.

To assess this risk, we propose a longer testnet period for this version to thoroughly examine the actual risks. Additionally, we aim to introduce more features that can better distinguish between pure L1DA and contracts that utilize other data availability modes. We welcome comments and suggestions, so please don’t hesitate to propose ideas.


Summary

Volition’s approach to L2DA offers a promising solution to reduce the high fees of posting data on L1. By enabling the use of L2DA for certain data, developers can potentially reduce up to 90% of the costs and improve scalability without compromising the integrity and security of the Ethereum network. The potential benefits of L2DA are significant and could pave the way for new possibilities in the development of decentralized applications. There is a potential risk of a malicious majority affecting the normal functioning of the network, and we would appreciate your thoughts and ideas on this matter.

Great article, very clear!
However, I’m a bit puzzled about this part:

How is a contract supposed to still be able to function when it can’t access the data it needs?
Or is it related to how read and write syscalls have been designed:
Since they use SyscallResult it forces the developer to explicitly do something with the result returned by the function.

I would like to better understand the assumptions around DA crisis:

  • rough outline of DA crisis scenario would be helpful
  • AFAIU current assumption is that L2DA data may become permanently unavailable due to the DA crisis, if so, this should be somehow reflected by the storage API
  • what will happen to L2DA contracts? Will all they methods touching L2DA storage will just start reverting? Or is there any recovery process (like L2DA storage reset) planned that will allow L2DA contracts to operate after the DA crisis?
  • what about hybrid L1DA/L2DA contracts?

Thanks for the comment! It would indeed require a contract-level migration in such a case. In the event of an L2 Data Availability crisis where data is lost, some contracts can still continue functioning with certain adjustments. For example, developers can use a storage variable, such as da_mode_pointer, to specify the Data Availability mode of other variables. Normally, this pointer would indicate L2 Data Availability mode. However, in the event of a Data Availability crisis, a transaction can update da_mode_pointer to point to L1 Data Availability instead.

While the data stored in the affected storage variables would be lost, the contract itself could still operate and begin reconstructing those variables from scratch.

A Data Availability crisis can occur if a temporary malicious majority selectively shares the L2DA data of a block within their group without making it publicly available to the rest of the network. In this scenario, the block itself can still be proven, but the data contained within the block is not accessible to other sequencers. As a result, these other sequencers are unable to create valid L2DA state transitions because they lack the necessary data.

How do you suggest doing it?

The sequencer will not include a transaction in a block if it does not have the necessary data required for updating the state. Therefore, transactions that interact with contracts utilizing L2DA storage will not be sequenced.

There are plans to reset the L2DA through governance decisions.

To safely develop a contract that can handle a DA crisis, one approach is to implement a mechanism within the contract itself. This mechanism would allow the contract to read and write storage variables from L1DA after the crisis occurs. By incorporating this functionality, the contract can adapt to the loss of L2DA data and continue functioning by utilizing L1DA storage (see the comment above).

I appreciate the detail in the explanation.

I’m not a programmer (although I understand some of the DA context).

From my position as a regular user of the network, I can only express my feelings.

I cannot deny that reading the entire context generates some uncertainty and perhaps fear about the complexity required to implement this hybrid concept.

There are two main aspects for me:

UX in relation to the appropriate security guarantees for each use case (regular user).
The regular user will face a new way of approaching their actions on the network.

It is clear that 90% will choose the most economical route, even if it means having lower security guarantees.

I’m not so sure how much they are interested in understanding and accepting the final trade-offs as regular users.

Perhaps we will need general education? Or is it not the goal to reach that extreme?

Maybe we can consider it as a trade-off that doesn’t necessarily have to be fully understood?

I wonder if users of Inmutable X, Sorare, or Myria truly understand the entire context of security guarantees. I think not.

Derived from this, I believe a user interface that is sufficiently intuitive is required to clearly and FRIENDLY present the trade-offs of the two possible paths, L1DA/L2DA.
However, it should not reach the point of generating fear in the user.

Please note that my perspective is from the point of view of a non-technical user (which is what I am).

So, under this context, I would only ask that the interfaces presented for choosing L1DA/L2DA be quite user-friendly, clear, and provide basic (not excessive) information that allows me to make a quick decision but with the necessary understanding.

I hope I have understood and expressed coherent ideas with the technical publication you just described.

Thank you for the feedback!

Bottom line up front: I think that your concerns are valid and should be in front of all core and dapps developers. In the end, the way to measure it will be in a longer time on a special Testnet to test how developers benefit from the Volition in reality.

As for the regular user experience: I’d split it into two parts - the interaction w/ the network in general (how Volition will affect its account contract, paid fees) and the interaction with specific dapps. The first one will be specified explicitly in the transaction and in the wallets. The second part is dependent on the specific dapps and what it chooses to show to the users.

In general, I think that two measures to be taken may allow reducing the risk:

  1. Make every default behavior use L1DA.
  2. Clearly mark (in block explorers and wallets, for example) contracts that are using L1DA purely.

Will there be some way how existing contracts can migrate their storage to Volition?

In an ideal scenario, I’d like to just replace_class with the same storage vars, but just mark them with #[manual_da] though I understand fiddling with storage is not straightforward.

Are there any solutions to this?

Would it be possible to have some storage for which the address domain points to some “temporary storage” effectively acting as transient storage?

No, sequencer won’t execute txs without having the relevant DA_mode data.

There are no plans to migrate storage to L2DA at the network level; it should be implemented within the contract level. For example, if you want to exclusively use L2DA mode instead of the existing L1DA, you can devise a logic such as ‘try to fetch the data from L2DA, and if it doesn’t exist, fetch it from L1DA and write it under the same key in L2DA.’

But would be easy/possible to make this DA_mode available?

Maybe I didn’t understand your question, can you elaborate more about the DA mode that you are suggesting?

The first version of volition in Starknet is planned to contain only two DA mode, there is an intention to expand it in the future.

Basically having a DA that would store stuff until the end of the transaction.
Once the transaction is done, it would drop the “stored” data entirely.

This would effectively achieve the same purpose as transient storage:

Great post. Thank you for the clear description. Two questions relating to this quote:

  • Assuming this would be compatible with Adamantium style DA as well?

  • Also, could you decide to write to multiple cheap DA options at once rather than choosing just one, e.g., L2DA + Multiple Adamantium DA providers + Other non-native DA provider. In most cases you may not want to do this, but I can think of one or two exceptions.

Thank you for your comment!

Assuming this would be compatible with Adamantium 1 style DA as well?

The first version of Volition for Starknet will include L1DA and L2DA. The intention is to expand it to other Data Availability solutions, but there is no specific design yet for supporting a particular DA solution.

Also, could you decide to write to multiple cheap DA options at once rather than choosing just one, e.g., L2DA + Multiple Adamantium DA providers + Other non-native DA provider. In most cases you may not want to do this, but I can think of one or two exceptions.

Of course, it is possible to implement it at the contract level without the need for a new feature in Cairo. As Starknet currently has no specific design for more than two DA modes, there is no intention at the moment to expand Cairo to support features for more than one non-L1DA mode.

Regarding the L2 DA crisis: I should be able to use volition only for index data, i.e. data that can be reconstructed from L1 data (e.g. Enumerable extension of the 721 specification), without incurring the risk of L2 DA crisis permanently breaking my contracts. If the data I store in volition is just an index, anyone can reconstruct the L2 data of the contract from L1 data, so I shouldn’t be taking on the same L2 DA risk as everyone else by using it in such a way.

My suggestion is to change the volition design to store a commitment for an L2 DA trie, separately for each account, in the L1 data. If one contract uses L2 DA in a way that is safe, it can always recover from any L2 DA issues. This will be more expensive but also more secure.

Some other comments below:

  • The Cairo API: why not just have a read_from and write_to methods that take the DA mode as a first argument, alongside the existing read and write? Seems more explicit and easier than having to add #[manual_da] and having the same method name with different arguments.
  • My preferred implementation of an ERC20 would by default query L2 balances first, and only query L1 balances if L2 balance is insufficient to cover a transfer. On transfer, recipient should always receive L1 balances so the sender is not deciding to risk the recipient’s payment. There should also be a method to move tokens from L1DA to L2DA. The recipient contract (account or protocol) can choose to expose a method that allows the sender to move tokens in some amount to DA.

Ideally the cheaper volition token is standardized. Here is my proposed interface:

#[starknet::interface]
trait VolitionToken<TContractState> {
  // the existing methods are unchanged but now check L2 DA balances first
  fn transfer(ref self: TContractState, to: ContractAddress, amount: u256) -> bool;
  fn balanceOf(self: @TContractState, account: ContractAddress) -> u256;

  // Returns the balance of this token stored in one particular DA
  fn balance_of_da(self: @TContractState, data_availability_mode: u8, account: ContractAddress) -> u256;

  // transfers from a specific da balance only
  fn transfer_from_da_balance(ref self: TContractState, data_availability_mode: u8, to: ContractAddress, amount: u128);
  fn move_between_da(ref self: TContractState, from_da_mode: u8, to_da_mode: u8, amount: u128);
}

Of course, approve/allowance is omitted from this specification, since it is not required with native AA.

I think the goals of transient storage should be achieved with a separate syscall. Using L2 DA for this doesn’t help that much because you still have to prove the 0 value of the storage address at the beginning of the transaction.

Regarding the L2DA crisis – the expectation is that malicious node operators would have their STRK token stake slashed in full then, right?

We have planned on running our own full node to guarantee the security of our users L2 data, in the expectation that in the event of a DA crisis, we could provide the data our users need.

If I understand the crisis situation correctly, we would only be able to supply old data, but reconstruct the current L2DA state by re-executing transactions (which we would have saved on our full node), proving that they lead to a certain L2DA storage state.

Am I then right to understand that any L2DA crisis would be temporary? Or is the expectation that they would prove txs, but not broadcast them to the rest of the network, meaning we wouldn’t be able to reconstruct the L2 state – at all? And keep operating this majority honest-on-L1DA-but-withholding-information network forever if they wish, since there’s no way to prove that the malicious majority is indeed withholding data?

Thank you for your response! I agree that the proposed DA mode seems to have interesting potential, especially as a middle ground between L2DA and L1DA in the future.

However, I think that your proposed design shouldn’t serve as the immediate L2DA solution for two main reasons:

  • Going this route means an inherent cost of 1.5k gas per transaction (changing the nonce of the calling contract), which means that achieving a significant reduction in cost for simple transactions won’t be possible.
  • The security benefit is limited; while you can continue working with contracts that have not been changed during a malicious majority attack, a reasonable few-hours control by a malicious majority will alter most of the common/“important” contracts, and the data needed to reconstruct them won’t be available.

Hey!

The L2DA crisis occurs when we have a malicious majority of validators. In this case, they could sign on a block without exposing the data to full nodes, and the block will still be valid on L1 as 2/3 of the stake signed on the block.

It’s not a probable event, but if that happens, the L2DA might not be able to reconstruct, even by L2 full nodes.