Eclipse is Ethereum's fastest Layer 2, powered by the Solana Virtual Machine (SVM).
As mentioned in our initial architecture post, Eclipse combines the best pieces of the modular stack: Ethereum as the settlement layer for our enshrined validating bridge, Celestia as the data availability layer, RISC Zero to generate our zero-knowledge fraud proofs, and Solana's SVM as the execution environment.
In this article, we will cover Eclipse's canonical bridge and fraud proof design. The upcoming release of our monorepo will contain the canonical bridge smart contracts, relayers, and a Docker container to run a test network for local development.
Eclipse is composed of three layers:
Execution: A fork of the Solana Labs client (v1.17) for SVM transaction execution
Settlement: Our canonical bridge defining Eclipse's fork-choice rule exists on Ethereum, where fraud proofs will also be submitted
Data Availability: Eclipse publishes the data necessary to produce fraud proofs as data blobs on Celestia
The diagram below illustrates how these modules interact:
The rest of this article will focus on Eclipse's Ethereum bridge, as shown in the diagram. Blobstream will relay attestations signed by Celestia's validator set to certify to Ethereum that the data for a batch of Eclipse's slots was published correctly. This allows Eclipse's bridge to verify the data provided for fraud proofs against the signed data roots from Celestia. In the rest of this section, we will outline the processes by which:
funds are deposited via our bridge,
data blobs of batches of Eclipse's blocks are posted on Celestia,
withdrawals via the bridge are handled, and
fraud proofs are generated in worst-case scenarios.
The flow when a user deposits onto Eclipse via the native Ethereum bridge is summarized as follows:
A user calls Eclipse's Deposit Bridge contract on Ethereum
From within Eclipse's SVM executor [1], the relayer [2] observes the user's deposit and destination address
Next, the relayer calls the SVM bridge program, which is responsible for transferring a user's deposit to the applicable destination address
The relayer verifies the deposit transaction via a zk-light client (to be implemented)
Finally, the block containing the subsequent post-deposit transfer transaction is finalized and published via a Solana Geyser Plugin
The diagram below shows the interactions between Ethereum, Celestia, and the SVM Executor during the deposit flow described above:
The flow for publishing batches of Eclipse's slots to Celestia as data blobs is summarized below:
The SVM executor publishes each Eclipse slot to the message queue via Geyser
The SVM executor posts batches of Eclipse's slots to Celestia as data blobs
The Celestia validator set produces commitments to the data blobs submitted, which can be used to prove the inclusion of a transaction on Eclipse's chain against the data root
The data roots contained in every single Celestia block header are relayed to Eclipse's bridge contract on Ethereum via Blobstream
The diagram below from Celestia explains how the commitment of the data within a given Celestia block is stored in the block header:
Similarly to other L2s that use fraud proofs (Arbitrum, Fuel, and many others), withdrawals from Eclipse require a challenge period during which verifiers can submit fraud proofs in the case of an invalid state transition:
At a regular cadence, the SVM executor posts a commitment to an epoch (a predetermined number of batches) of Eclipse's slots to Ethereum, along with collateral
Eclipse’s bridge contract conducts some basic checks to ensure that the data posted is well-formed (described in the Fraud Proof Design section)
If the submitted batch passes these basic checks, there is a predefined window during which verifiers can post fraud proofs in the case that the batch commitment implies an invalid state transition
If a verifier posts a successful fraud proof, they win the executor's collateral, the posted batch is rejected, and the canonical state of the Eclipse L2 is rolled back to the last valid batch commitment. Here, Eclipse's governance would have the ability to elect a new executor
If the challenge period elapses with no successful fraud proof, the executor recovers its collateral along with a reward
Consequently, the Eclipse bridge contract will now complete any withdrawal transactions that were included in the finalized batch
In this final section, we will detail Eclipse's fraud proof system design, inspired by Anatoly Yakovenko and John Adler. Generally, for any fraud proof, a verifier must:
Identify a transaction containing an invalid state transition
Provide the inputs to said transaction with the invalid state transition
Demonstrate that re-executing said transaction with the given inputs results in an output that is not equal to what was committed on-chain
In Eclipse's case, (1) Celestia merklizes blobs of batches of blocks that Eclipse's SVM executor posts, allowing transaction inclusion proofs via Merkle witnesses. For (2), unlike EVM-based L2s, which post a Merkle root to the global state tree, for performance reasons Eclipse does not update a global state tree on a transaction-by-transaction basis, but we will explain how we ensure the correctness of inputs in more detail below. Finally, in the case of (3), Eclipse's verifier generates a zk-proof of the output(s) for a given transaction, unlike the interactive verification game approach common across EVM-based L2s.
All Eclipse transactions can be represented as taking a list of input accounts, executing a transaction, and producing a list of resultant output accounts:
The critical observation for our fraud proof design is that for transaction execution, it is always the case that any S_InputAccount must have been the S_OutputAccount of some previous transaction. This allows us to reference the last transaction in the chain that produced a given input account instead of providing a Merkle witness to a global state tree. As a result of our design, we introduce additional fraud accusation types, such as a reference to the previous transaction not being valid or the input account already being "spent" by some later transaction. We describe this process in more detail below:
Transaction data (posted by the sequencer)
Transaction data (posted by the SVM executor) which contains the following:
Transaction count [3]
Celestia namespace location of the transaction data
Account hash [4] for each input, with transaction count resulting in each
List of sysvars used and value of each, with transaction count resulting in each (if applicable) [5]
Transaction output, if the transaction was successful; otherwise, an indicator that the transaction failed (either because it failed to parse or because it was unable to execute)
In addition, the batches of transaction data posted to Celestia have their commitments relayed to the Ethereum contract. The commitments consist of:
The Celestia namespace location of the transaction data of the last transaction included in the batch
The Celestia namespace location of the execution data [6] of all included transactions
A list of deposits, withdrawals, and overrides, each of which comes with the transaction count of the associated Eclipse transaction
As explained above, there are several ways a batch can be found to be incorrect:
One of the linked Celestia namespace locations is malformed or does not point to data of the required type
There is a transaction on Celestia with no associated execution data, which can be due to two reasons:
The transaction, which was supposed to be the most recent in the batch, has no associated execution data.
The execution data of a different transaction is missing
There is a transaction whose execution data is incorrect, which could be caused by the following:
The transaction count associated with an account hash or sysvar does not produce the claimed output.
The transaction count associated with an account hash or sysvar is outdated
The transaction output is incorrect, or the transaction uses an input that is not listed:
In this case, a zk-proof of the correct execution of the transaction or a zk-proof that the transaction uses an input that is not listed is needed. This can be obtained in two ways:
A verifier posts the proof, or
A verifier posts the index of the transaction claimed to be fraudulent, and the Eclipse bridge contract uses this to solicit a zk-proof from RISC Zero's Bonsai
There was a deposit from Ethereum more than N batches ago, but there is no corresponding deposit in the transaction list (included in the batch commitment posted to the bridge contract) for the N past batches. Alternatively, there is a deposit in the transaction list with no related Ethereum deposit transaction, or the transaction exists but has already been included in another Eclipse batch
There is a deposit or withdrawal executed with no corresponding entry in the transaction list
There is a deposit or withdrawal in the transaction list whose associated Eclipse transaction is not performing the expected action or whose transaction count is not within its expected transaction count range. In such a case, either one of the following would happen:
The bridge would automatically determine this is the case and refuse the corresponding batch
A verifier notices the invalid state transition and posts proof of the offending transaction, which is then verified by the bridge contract
If any commitment batch is found to be incorrect, the Eclipse bridge contract will roll back the bridge to that of the last provably correct batch commitment. Note that transactions are never removed from the chain, even in the case of fraud, so only the commitment needs to be re-computed.
This article aimed to give a high-level guide to Eclipse's trust-minimized bridge on Ethereum and explain some details about our fraud proof design. Given the modular nature of our L2 and the nascence of our technology stack, we will continue to release articles and documentation about various aspects of Eclipse in the coming weeks.
To get involved with Eclipse Testnet, please follow our instructions here. You can contact us on Twitter or Discord with specific inquiries about our Testnet, bridge, or technical questions.
[1]: The node which computes the results of SVM transactions and applies the eventual output to Eclipse’s new state
[2]: An operator which passes on-chain events between Ethereum and Eclipse
[3]: Note that the executor, not the sequencer, posts this. If it were included in the data posted by the sequencer, it would add the complication that the sequencer could skip over a count, making it impossible for the executor to do their job correctly. This could be compensated for in the fraud proof design, but it would add extra complexity. A second advantage of having only the executor post the count is that it makes it easy to allow transaction overrides to be posted to Celestia, if desired.
[4]: SVM accounts can be represented with a unique hash. The only way this hash is modified is via a transaction.
[5]: To do this without an excessive amount of hashing, we will run a trace on each executed program to see which parts of each used sysvar are actually accessed. This is possible, but will require modifying Solana's BPF interpreter.
[6]: This includes data for attempted transactions that failed to execute.