# Understanding the Optimistic Ethereum Protocol

Work in Progress™

Our documentation is a rapidly improving work in progress. If you have questions or feel like something is missing feel free to ask in our Discord server(opens new window) where we (and our awesome community) are actively responding, or open an issue(opens new window) in the GitHub repo for this site.

# Introduction

Optimistic Ethereum (OE) is a Layer 2 scaling protocol for Ethereum applications. I.e., it makes transactions cheap. Real cheap. We aim to make transacting on Ethereum affordable and accessible to anyone.

This document is intended for anyone looking for a deeper understanding of how the protocol works 'under the hood'. If you just want to skip straight to integrating your smart contract application with OE, check out the Developer Docs.

Optimistic Ethereum is meant to look, feel and behave like Ethereum but cheaper and faster. For developers building on our OE, we aim to make the transition as seamless as possible. With very few exceptions, existing Solidity smart contracts can run on L2 exactly how they run on L1. Similarly, off-chain code (ie. UIs and wallets), should be able to interact with L2 contract with little more than an updated RPC endpoint.

# System Overview

The smart contracts in the Optimistic Ethereum (OE) protocol can be separated into a few key components. We will discuss each component in more detail below.

  • Chain: Contracts on layer-1, which hold the ordering of layer-2 transactions, and commitments to the associated layer-2 state roots.
  • Fraud Proving: Contracts on layer-1 which implement the process for proving a fraudulent state transition.
  • Execution: Contracts which implement the Optimistic Virtual Machine.
  • Bridge: Contracts which facilitate message passing between layer-1 and layer-2.
  • Predeploys: A set of essential contracts which are deployed and available in the genesis state of the system. These contracts are similar to Ethereum's precompiles, however they are written in Solidity, and can be found at addresses prefixed with 0x42.
  • Accounts: Redeployable contracts layer-2 contracts which can represent a user and provide a form of 'account abstraction'.
Diagram created with draw.io.
Editable source here.

# Chain Contracts

The Chain is composed of a set of contracts running on the Ethereum mainnet. These contracts store ordered lists of:

  1. An ordered list of all transactions applied to the L2 state.
  2. The proposed state root which would results from the application of each transaction.
  3. Transactions sent from L1 to L2, which are pending inclusion in the ordered list.

The chain is composed of the following concrete contracts:

# OVM_CanonicalTransactionChain(opens new window) (CTC)

The Canonical Transaction Chain (CTC) contract is an append-only log of transactions which must be applied to the OVM state. It defines the ordering of transactions by writing them to the CTC:batches instance of the Chain Storage Container.The CTC also allows any account to enqueue() an L2 transaction, which the Sequencer must eventually append to the rollup state.

# OVM_StateCommitmentChain(opens new window) (SCC)

The State Commitment Chain (SCC) contract contains a list of proposed state roots which Proposers assert to be a result of each transaction in the Canonical Transaction Chain (CTC). Elements here have a 1:1 correspondence with transactions in the CTC, and should be the unique state root calculated off-chain by applying the canonical transactions one by one.

# OVM_ChainStorageContainer(opens new window)

Provides reusable storage in the form of a "Ring Buffer" data structure, which will overwrite storage slots that are no longer needed. There are three Chain Storage Containers deployed, two are controlled by the CTC, one by the SCC.

# Fraud Proving Contracts

In the previous section, we mentioned that the Chain includes a list of the proposed state roots resulting from each transaction. Here we explain a bit more about how these proposals happen, and how we come to trust them.

In brief: If a proposed state root is not the correct result of executing a transaction, then a Verifier (which is anyone running an OE 'full node') can initiate a fraud proof. If the transaction is successfully proven to be fraudulent, the Verifier will receive a reward taken from funds which a Sequencer must put up as a bond.

The fraud proving system is composed of the following concrete contracts:

# OVM_FraudVerifier(opens new window)

The Fraud Verifier contract coordinates the entire fraud proof verification process. If the fraud proof is successful it prunes any state batches from State Commitment Chain which were published after the fraudulent state root.

# OVM_BondManager(opens new window)

The Bond Manager contract handles deposits in the form of an ERC20 token from bonded Proposers. It also handles the accounting of gas costs spent by a Verifier during the course of a fraud proof. In the event of a successful fraud proof, the fraudulent Proposer's bond is slashed, and the Verifier's gas costs are refunded.

# OVM_StateTransitioner(opens new window)

The State Transitioner coordinates the execution of a state transition during the evaluation of a fraud proof. It feeds verified input to the Execution Manager's run(), and controls a State Manager (which is uniquely created for each fraud proof). Once a fraud proof has been initialized, this contract is provided with the pre-state root and verifies that the OVM storage slots committed to the State Manager are contained in that state. This contract controls the State Manager and Execution Manager, and uses them to calculate the post-state root by applying the transaction. The Fraud Verifier can then check for fraud by comparing the calculated post-state root with the proposed post-state root.

# OVM_StateTransitionerFactory(opens new window)

Used by the Fraud verifier to create a unique State Transitioner for each fraud proof.

# Execution Contracts

The Execution contracts implement the Optimistic Virtual Machine, or OVM. Importantly, these contracts must execute in the same deterministic manner, whether a transaction is run on Layer 2, or Layer 1 (during a fraud proof).

# OVM_ExecutionManager(opens new window)

The Execution Manager (EM) is the core of our OVM implementation, and provides a sandboxed environment allowing us to execute OVM transactions deterministically on either Layer 1 or Layer 2. The EM's run() function is the first function called during the execution of any transaction on L2. For each context-dependent EVM operation the EM has a function which implements a corresponding OVM operation, which will read state from the State Manager contract. The EM relies on the Safety Checker to verify that code deployed to Layer 2 does not contain any context-dependent operations.

# OVM_SafetyChecker(opens new window)

The Safety Checker verifies that contracts deployed on L2 do not contain any "unsafe" operations. An operation is considered unsafe if it would access state variables which are specific to the environment (ie. L1 or L2) in which it is executed, as this could be used to "escape the sandbox" of the OVM, resulting in non-deterministic fraud proofs. That is, an attacker would be able to "prove fraud" on an honestly applied transaction. Note that a "safe" contract requires opcodes to appear in a particular pattern; omission of "unsafe" opcodes is necessary, but not sufficient.

The following opcodes are disallowed:

  • CALL*

* The CALLER, CALL, and REVERT opcodes are also disallowed, except in the special case that they appear as part of one of the following strings of bytecode:


Opcodes which are not yet assigned in the EVM are also disallowed.

# OVM_StateManager(opens new window)

The State Manager contract holds all storage values for contracts in the OVM. It can only be written to by the Execution Manager and State Transitioner. It runs on L1 during the setup and execution of a fraud proof. The same logic runs on L2, but has been implemented as a precompile in the L2 go-ethereum client.

# OVM_StateManagerFactory(opens new window)

The State Manager Factory is called by a State Transitioner's init code, to create a new State Manager for use in the Fraud Verification process.

# Bridge Contracts

The Bridge contracts implement the functionality required to pass messages between layer 1 and layer 2.

The Bridge is composed of the following concrete contracts:

# OVM_L1CrossDomainMessenger(opens new window)

The L1 Cross Domain Messenger (L1xDM) contract sends messages from L1 to L2, and relays messages from L2 onto L1. In the event that a message sent from L1 to L2 is rejected for exceeding the L2 epoch gas limit, it can be resubmitted via this contract's replay function.

# OVM_L2CrossDomainMessenger(opens new window)

The L2 Cross Domain Messenger (L2xDM) contract sends messages from L2 to L1, and is the entry point for L2 messages sent via the L1 Cross Domain Messenger.

# Predeployed Contracts

"Predeploys" are a set of essential contracts which are deployed and available in the genesis state of the system. These contracts are similar to Ethereum's precompiles, however they are written in Solidity, and can be found in the OVM at addresses prefixed with 0x42.

The following concrete contracts are predeployed:

# OVM_DeployerWhitelist(opens new window)

The Deployer Whitelist is a temporary predeploy used to provide additional safety during the initial phases of our mainnet roll out. It is owned by the Optimism team, and defines accounts which are allowed to deploy contracts on Layer 2. The Execution Manager will only allow an ovmCREATE or ovmCREATE2 operation to proceed if the deployer's address whitelisted.

# OVM_ETH(opens new window)

The ETH predeploy provides an ERC20 interface for ETH deposited to Layer 2. Note that unlike on Layer 1, Layer 2 accounts do not have a balance field.

# OVM_L1MessageSender(opens new window)

The L1MessageSender is a predeployed contract running on L2. During the execution of cross domain transaction from L1 to L2, it returns the address of the L1 account (either an EOA or contract) which sent the message to L2 via the Canonical Transaction Chain's enqueue() function. This contract exclusively serves as a getter for the ovmL1TXORIGIN operation. This is necessary because there is no corresponding EVM opcode which the optimistic solidity compiler could replace with a call to the ExecutionManager's ovmL1TXORIGIN() function. That is, if a contract on L2 wants to know which L1 address initiated a call on L2, the way to do it is by calling OVM_L1MessageSender.ovmL1TXORIGIN().

# OVM_L2ToL1MessagePasser(opens new window)

The L2 to L1 Message Passer is a utility contract which facilitate an L1 proof of the of a message on L2. The L1 Cross Domain Messenger performs this proof in its _verifyStorageProof function, which verifies the existence of the transaction hash in this contract's sentMessages mapping.

# OVM_ProxySequencerEntrypoint(opens new window)

The Proxy Sequencer Entrypoint is a predeployed proxy to the implementation of the Sequencer Entrypoint. This will enable the Optimism team to upgrade the Sequencer Entrypoint contract.

# OVM_SequencerEntrypoint(opens new window)

The Sequencer Entrypoint is a predeploy which, despite its name, can in fact be called by any account. It accepts a more efficient compressed calldata format, which it decompresses and encodes to the standard EIP155 transaction format. This contract is the implementation referenced by the Proxy Sequencer Entrypoint, thus enabling the Optimism team to upgrade the decompression of calldata from the Sequencer.

# Account Contracts

OVM Account contracts are redeployable contracts layer-2 contracts which can represent a user and provide a form of 'account abstraction'.

# OVM_ProxyEOA(opens new window)

The Proxy EOA contract uses a delegate call to execute the logic in an implementation contract. In combination with the logic implemented in the ECDSA Contract Account, this enables a form of upgradable 'account abstraction' on layer 2.

# OVM_ECDSAContractAccount(opens new window)

The ECDSA Contract Account contract can be used as the implementation for a ProxyEOA deployed by the ovmCREATEEOA operation. It enables backwards compatibility with Ethereum's Layer 1, by providing eth_sign and EIP155 formatted transaction encodings.