Skip to main content

OP Stack and EigenDA

OP Stack is the set of software components that run the Optimism rollup and can be deployed independently to power third-party rollups.

By default, the OP Stack sequencer's op-batcher writes batches to Ethereum in the form of calldata or 4844 blobs to commit to the transactions included in the canonical L2 chain. In Alt-DA mode, the op-batcher and op-nodes (validators) are configured to talk to a third-party HTTP proxy server for writing (op-batcher) and reading (op-node) tx batches to and from DA. Optimism's Alt-DA spec contains a more in-depth breakdown of how these systems interact.

To implement this server spec, EigenDA provides EigenDA Proxy which is run as a dependency alongside OP Stack sequencers and full nodes to securely communicate with the EigenDA disperser.

Our OP Fork

We currently maintain a fork of the OP Stack to provide 3 features missing from the upstream OP Stack:

  1. Performance: we enable high-throughput rollups via parallel blob submissions (see Release 2)
  2. Liveness: we provide failover to Ethereum calldata if EigenDA is unavailable (see Release 1)
  3. Safety: we are working on a fully secure integration, using our hokulea extension to op's rust derivation pipeline

Kurtosis Devnet

For a quick start to explore an eigenda-powered op rollup, we extended op's kurtosis-devnet. Start by cloning the repo and cd'ing to the correct directory:

git clone git@github.com:Layr-Labs/optimism.git
cd optimism/kurtosis-devnet

Then take a look at the different just commands related to our devnet:

$ just --list
[...] # other commands
[eigenda]
eigenda-devnet-add-tx-fuzzer ENCLAVE_NAME="eigenda-devnet" *ARGS=""
eigenda-devnet-clean ENCLAVE_NAME="eigenda-devnet"
eigenda-devnet-configs ENCLAVE_NAME="eigenda-devnet"
eigenda-devnet-failback ENCLAVE_NAME="eigenda-devnet"
eigenda-devnet-failover ENCLAVE_NAME="eigenda-devnet" # to failover to ethDA. Use `eigenda-devnet-failback` to revert.
eigenda-devnet-grafana ENCLAVE_NAME="eigenda-devnet"
eigenda-devnet-restart-batcher ENCLAVE_NAME="eigenda-devnet" # Restart batcher with new flags or image.
eigenda-devnet-start VALUES_FILE="eigenda-template-values/memstore-concurrent-large-blobs.json" ENCLAVE_PREFIX="eigenda" # We also start a tx-fuzzer separately, since the optimism-package doesn't currently have that configurable as part of its package.
eigenda-devnet-sync-status ENCLAVE_NAME="eigenda-devnet"
eigenda-devnet-test-holesky *ARGS="" # Take a look at how CI does it in .github/workflows/kurtosis-devnet.yml .
eigenda-devnet-test-memstore *ARGS="" # meaning with a config file in eigenda-template-values/memstore-* .

You can run just eigenda-devnet-start to start a devnet which will spin-up an eigenda-proxy in memstore mode, simulating EigenDA. To interact with the actual EigenDA holesky testnet, you can run just eigenda-devnet-start "eigenda-template-values/holesky-concurrent-small-blobs.json". You will need to fill in the two missing secret values in that config file: eigenda-proxy.secrets.eigenda.signer-private-key-hex and eigenda-proxy.secrets.eigenda.eth-rpc. Feel free to modify any other values, or even modify the kurtosis eigenda template file directly if needed.

Deploying

Deploy your OP Stack according to the official OP deployment docs. Our fork currently only modifies the op-batcher and op-node, so make sure to also read the instructions below to deploy those.

Rollup Config

If using op-deployer to initialize your chain, make sure to set the DangerousAltDAConfig fields in your intent file (don't fret the OP FUD; EigenDA rollups don't bite):

[[chains]]
# Your chain's ID, encoded as a 32-byte hex string
id = "0x00000000000000000000000000000000000000000000000000000a25406f3e60"
# Only called dangerous because it hasn't been tested by OP Labs
[chains.dangerousAltDAConfig]
useAltDA = true
daCommitmentType = "GenericCommitment" # instead of KeccakCommitment
daChallengeWindow = 300 # unused random value
daResolveWindow = 300 # unused random value

With GenericCommitment, this will skip deploying the DAChallengeContract (see our analysis below for why we don't use it), and create a rollup.json configuration file with the following alt_da fields:

{
"alt_da": {
"da_commitment_type": "GenericCommitment",
"da_challenge_contract_address": "0x0000000000000000000000000000000000000000",
"da_challenge_window": 300,
"da_resolve_window": 300
}
}

If you are not using op-deployer and possibly generating this file manually, make sure to set da_commitment_type to use generic commitment instead of keccak commitments! The other values are meaningless, but they still need to be set somehow.

Deploying EigenDA Proxy

We push docker images to our ghcr registry on every release.

Make sure to read the different features provided by the proxy, to understand the different flag options. We provide an example holesky config which contains the env vars required to configure Proxy for retrieval from both EigenDA V1 and V2.

If deploying proxy for an op-batcher, which means blobs will be dispersed to EigenDA, make sure to set EIGENDA_PROXY_STORAGE_DISPERSAL_BACKEND=V2 to submit blobs to EigenDA V2.

Deploying OP Node

The following env config values should be set to ensure proper communication between op-node and eigenda-proxy, replacing {EIGENDA_PROXY_URL} with the URL of your EigenDA Proxy server.

  • OP_NODE_ROLLUP_CONFIG={ROLLUP_CONFIG_PATH}: path to the rollup.json file mentioned above
  • OP_NODE_ALTDA_ENABLED=true
  • OP_NODE_ALTDA_DA_SERVICE=true: this weird name means to use generic commitments instead of keccak commitments.
  • OP_NODE_ALTDA_VERIFY_ON_READ=false: another weird name which is only used for keccak commitments.
  • OP_NODE_ALTDA_DA_SERVER={EIGENDA_PROXY_URL}

Deploying OP Batcher

The following env config values should be set accordingly to ensure proper communication between OP Batcher and EigenDA Proxy, replacing {EIGENDA_PROXY_URL} with the URL of your EigenDA Proxy server.

  • OP_BATCHER_ALTDA_ENABLED=true
  • OP_BATCHER_ALTDA_DA_SERVICE=true: this weird name means to use generic commitments instead of keccak commitments.
  • OP_BATCHER_ALTDA_VERIFY_ON_READ=false: another weird name which is only used for keccak commitments.
  • OP_BATCHER_ALTDA_DA_SERVER={EIGENDA_PROXY_URL}
  • OP_BATCHER_TARGET_NUM_FRAMES=8
  • OP_BATCHER_MAX_L1_TX_SIZE_BYTES=120000: default value
  • OP_BATCHER_ALTDA_MAX_CONCURRENT_DA_REQUESTS=10

Each blob submitted to EigenDA consists of OP_BATCHER_TARGET_NUM_FRAMES number of frames, each of size OP_BATCHER_MAX_L1_TX_SIZE_BYTES. The above values submit blobs of ~1MiB. We advise not setting OP_BATCHER_MAX_L1_TX_SIZE_BYTES larger than the default in case failover is required, which will submit the frames directly to ethereum as calldata, so must fit in a single transaction (max 128KiB).

EigenDA V2 dispersals p99 latency is ~10seconds, so in order to achieve a throughput of 1MiB/s, we set OP_BATCHER_ALTDA_MAX_CONCURRENT_DA_REQUESTS=10 to allow 10 pipelined requests to fill those 10 seconds.

Details

EigenDA V1 Setting EigenDA V1, because of its blocking calls, required setting OP_BATCHER_ALTDA_MAX_CONCURRENT_DA_REQUESTS=1320 to achieve 1MiB/s throughput. This is because blob dispersals on EigenDA V1 mainnet take ~10 mins for batching and 12 mins for Ethereum finality, which means a blob submitted to the eigenda-proxy could take up to 22 mins before returning. Thus, assuming blobs of 1MiB/s by setting OP_BATCHER_TARGET_NUM_FRAMES=8, in order to reach a throughput of 1MiB/s, which means 8 requests per second each blocking for possibly up to 22mins, we would need to send up to 60*22=1320 parallel requests.

Failover

Failover was added in this PR, and is automatically supported by the batcher. Each channel will first attempt to disperse to EigenDA via the proxy. If a 503 HTTP error is received, that channel will failover and be submitted as calldata to ethereum instead. To configure when the proxy returns 503 errors, see the failover signals section of the Proxy README.

Migrating To EigenDA V2

For trusted integrations, migrating to EigenDA V2 is as simple as:

Please refer to the EigenDA Proxy README for more details. We also have a V2 migration test on our kurtosis devnet which shows how to swap the dispersal-backend from V1 to V2 without needing to restart the proxy.

Security Guarantees

The above setup provides a trusted integration level of security guarantees without adding an unnecessary trust assumption on the EigenDA disperser.

DA Challenge Contract

OP's Alt-DA spec includes a DA challenge contract, which allows L2 asset-holders to prevent a data withholding attack executed by the sequencer or DA network. EigenDA does not make use of the challenge contract because not only is uploading high-throughput bandwidth onto Ethereum not physically possible, but even for low throughput rollups, the challenge contract is not economically viable. See l2beat's analysis of the redstone rollup or donnoh's Universal Plasma and DA challenges article for an economic analysis of the challenge contract.

This means that even if our op stack fork were to implement failover to keccak commitments (currently it is only possible to failover to ethereum calldata), using the challenge contract would not provide any additional security guarantees, which is why we recommend that every eigenda-op rollup uses GenericCommitments in their rollup.json config.