Skip to content

feat: support eigenda #516

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
288 changes: 284 additions & 4 deletions Cargo.lock

Large diffs are not rendered by default.

12 changes: 11 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ members = [
"utils/build",
"utils/celestia/client",
"utils/celestia/host",
"utils/eigenda/client",
"utils/eigenda/host",
"utils/proof",
"utils/signer",
"utils/ethereum/client",
Expand Down Expand Up @@ -85,6 +87,13 @@ hana-celestia = { git = "https://github.com/celestiaorg/hana", rev = "904f086fd7
hana-host = { git = "https://github.com/celestiaorg/hana", rev = "904f086fd7335986e87a0f0432b1f07fe997f690" }
hana-oracle = { git = "https://github.com/celestiaorg/hana", rev = "904f086fd7335986e87a0f0432b1f07fe997f690" }

# hokulea
hokulea-eigenda = { git = "https://github.com/Layr-Labs/hokulea", rev = "62abcc0" }
hokulea-host-bin = { git = "https://github.com/Layr-Labs/hokulea", rev = "62abcc0" }
hokulea-proof = { git = "https://github.com/Layr-Labs/hokulea", rev = "62abcc0" }
hokulea-witgen = { git = "https://github.com/Layr-Labs/hokulea", rev = "62abcc0" }
hokulea-zkvm-verification = { git = "https://github.com/Layr-Labs/hokulea", rev = "62abcc0" }

# op-succinct
op-succinct-prove = { path = "scripts/prove" }
op-succinct-client-utils = { path = "utils/client" }
Expand All @@ -97,6 +106,8 @@ op-succinct-ethereum-client-utils = { path = "utils/ethereum/client" }
op-succinct-ethereum-host-utils = { path = "utils/ethereum/host" }
op-succinct-celestia-client-utils = { path = "utils/celestia/client" }
op-succinct-celestia-host-utils = { path = "utils/celestia/host" }
op-succinct-eigenda-client-utils = { path = "utils/eigenda/client" }
op-succinct-eigenda-host-utils = { path = "utils/eigenda/host" }
op-succinct-proof-utils = { path = "utils/proof" }
op-succinct-signer-utils = { path = "utils/signer" }
op-succinct-range-utils = { path = "programs/range/utils" }
Expand Down Expand Up @@ -166,4 +177,3 @@ substrate-bn = { git = "https://github.com/sp1-patches/bn", tag = "patch-0.6.0-s
sha3 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", package = "sha3", tag = "patch-sha3-0.10.8-sp1-4.0.0" }
p256 = { git = "https://github.com/sp1-patches/elliptic-curves", tag = "patch-p256-13.2-sp1-5.0.0" }
k256 = { git = "https://github.com/sp1-patches/elliptic-curves", tag = "patch-k256-13.4-sp1-5.0.0" }

Binary file modified elf/aggregation-elf
Binary file not shown.
Binary file modified elf/celestia-range-elf-embedded
Binary file not shown.
Binary file added elf/eigenda-range-elf-embedded
Binary file not shown.
Binary file modified elf/range-elf-bump
Binary file not shown.
Binary file modified elf/range-elf-embedded
Binary file not shown.
35 changes: 35 additions & 0 deletions programs/range/eigenda/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
[package]
name = "range-eigenda"
version = "0.1.0"
license.workspace = true
edition.workspace = true
authors.workspace = true
homepage.workspace = true
repository.workspace = true

[dependencies]
# general
rkyv.workspace = true
serde_cbor.workspace = true

# kona
kona-proof.workspace = true

# hokulea
hokulea-proof.workspace = true
hokulea-zkvm-verification.workspace = true

# sp1
sp1-zkvm.workspace = true

# op-succinct
op-succinct-client-utils.workspace = true
op-succinct-eigenda-client-utils.workspace = true
op-succinct-range-utils.workspace = true

# `tracing-subscriber` feature dependencies
tracing-subscriber = { workspace = true, optional = true }

[features]
embedded = ["sp1-zkvm/embedded"]
tracing-subscriber = ["dep:tracing-subscriber"]
44 changes: 44 additions & 0 deletions programs/range/eigenda/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//! A program to verify a Optimism L2 block STF with Ethereum DA in the zkVM.
//!
//! This binary contains the client program for executing the Optimism rollup state transition
//! across a range of blocks, which can be used to generate an on chain validity proof. Depending on
//! the compilation pipeline, it will compile to be run either in native mode or in zkVM mode. In
//! native mode, the data for verifying the batch validity is fetched from RPC, while in zkVM mode,
//! the data is supplied by the host binary to the verifiable program.

#![no_main]
sp1_zkvm::entrypoint!(main);

use hokulea_proof::{
canoe_verifier::sp1_cc::CanoeSp1CCVerifier, eigenda_blob_witness::EigenDABlobWitnessData,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NOTE: current EigenDA testnet is on holesky so maybe good to test e2e with Noop verifier first. Request has been made to migrate to sepolia.

};
use hokulea_zkvm_verification::eigenda_witness_to_preloaded_provider;
use op_succinct_client_utils::witness::{EigenDAWitnessData, WitnessData};
use op_succinct_eigenda_client_utils::executor::EigenDAWitnessExecutor;
use op_succinct_range_utils::run_range_program;
#[cfg(feature = "tracing-subscriber")]
use op_succinct_range_utils::setup_tracing;
use rkyv::rancor::Error;

fn main() {
#[cfg(feature = "tracing-subscriber")]
setup_tracing();

kona_proof::block_on(async move {
let witness_rkyv_bytes: Vec<u8> = sp1_zkvm::io::read_vec();
let witness_data = rkyv::from_bytes::<EigenDAWitnessData, Error>(&witness_rkyv_bytes)
.expect("Failed to deserialize witness data.");

let (oracle, _beacon) = witness_data.clone().get_oracle_and_blob_provider().await.unwrap();
let eigenda_witness: EigenDABlobWitnessData = serde_cbor::from_slice(
&witness_data.eigenda_data.clone().expect("eigenda witness data is not present"),
)
.expect("cannot deserialize eigenda witness");
let preloaded_blob_provider =
eigenda_witness_to_preloaded_provider(oracle, CanoeSp1CCVerifier {}, eigenda_witness)
.await
.expect("Failed to get preloaded blob provider");

run_range_program(EigenDAWitnessExecutor::new(preloaded_blob_provider), witness_data).await;
});
}
5 changes: 5 additions & 0 deletions utils/build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,9 @@ pub fn build_all() {
// "celestia-range-elf-embedded",
// Some(vec!["embedded".to_string()]),
// );
// build_program(
// "range/eigenda",
// "eigenda-range-elf-embedded",
// Some(vec!["embedded".to_string()]),
// );
}
20 changes: 20 additions & 0 deletions utils/client/src/witness/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,26 @@ impl WitnessData for DefaultWitnessData {
}
}

#[derive(Clone, Debug, Default, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
pub struct EigenDAWitnessData {
pub preimage_store: PreimageStore,
pub blob_data: BlobData,
// EigenDABlobWitnessData.
// See https://github.com/Layr-Labs/hokulea/blob/056ee9888964f1a63191384ce882a2d4f805e76e/crates/proof/src/eigenda_blob_witness.rs.
pub eigenda_data: Option<Vec<u8>>,
}

#[async_trait]
impl WitnessData for EigenDAWitnessData {
fn from_parts(preimage_store: PreimageStore, blob_data: BlobData) -> Self {
Self { preimage_store, blob_data, eigenda_data: None }
}

fn into_parts(self) -> (PreimageStore, BlobData) {
(self.preimage_store, self.blob_data)
}
}

#[derive(
Clone, Debug, Default, Serialize, Deserialize, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize,
)]
Expand Down
28 changes: 28 additions & 0 deletions utils/eigenda/client/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[package]
name = "op-succinct-eigenda-client-utils"
version = "0.1.0"
license.workspace = true
edition.workspace = true

[dependencies]
# local
op-succinct-client-utils.workspace = true

# kona
kona-derive.workspace = true
kona-driver.workspace = true
kona-executor.workspace = true
kona-genesis.workspace = true
kona-preimage.workspace = true
kona-proof.workspace = true

# hokulea
hokulea-eigenda.workspace = true
hokulea-proof = { workspace = true, features = ["sp1-cc"] }
hokulea-witgen.workspace = true

# general
anyhow.workspace = true
async-trait.workspace = true
serde_cbor.workspace = true
spin.workspace = true
76 changes: 76 additions & 0 deletions utils/eigenda/client/src/executor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use std::{fmt::Debug, sync::Arc};

use anyhow::Result;
use async_trait::async_trait;
use hokulea_eigenda::{EigenDABlobProvider, EigenDABlobSource, EigenDADataSource};
use kona_derive::{sources::EthereumDataSource, traits::BlobProvider};
use kona_driver::PipelineCursor;
use kona_genesis::RollupConfig;
use kona_preimage::CommsClient;
use kona_proof::{
l1::{OracleL1ChainProvider, OraclePipeline},
l2::OracleL2ChainProvider,
FlushableCache,
};
use op_succinct_client_utils::witness::executor::WitnessExecutor;
use spin::RwLock;

pub struct EigenDAWitnessExecutor<O, B, E>
where
O: CommsClient + FlushableCache + Send + Sync + Debug,
B: BlobProvider + Send + Sync + Debug + Clone,
E: EigenDABlobProvider + Send + Sync + Debug + Clone,
{
eigenda_blob_provider: E,
_marker: std::marker::PhantomData<(O, B)>,
}

impl<O, B, E> EigenDAWitnessExecutor<O, B, E>
where
O: CommsClient + FlushableCache + Send + Sync + Debug,
B: BlobProvider + Send + Sync + Debug + Clone,
E: EigenDABlobProvider + Send + Sync + Debug + Clone,
{
pub fn new(eigenda_blob_provider: E) -> Self {
Self { eigenda_blob_provider, _marker: std::marker::PhantomData }
}
}

#[async_trait]
impl<O, B, E> WitnessExecutor for EigenDAWitnessExecutor<O, B, E>
where
O: CommsClient + FlushableCache + Send + Sync + Debug,
B: BlobProvider + Send + Sync + Debug + Clone,
E: EigenDABlobProvider + Send + Sync + Debug + Clone,
{
type O = O;
type B = B;
type L1 = OracleL1ChainProvider<Self::O>;
type L2 = OracleL2ChainProvider<Self::O>;
type DA = EigenDADataSource<Self::L1, Self::B, E>;

async fn create_pipeline(
&self,
rollup_config: Arc<RollupConfig>,
cursor: Arc<RwLock<PipelineCursor>>,
oracle: Arc<Self::O>,
beacon: Self::B,
l1_provider: Self::L1,
l2_provider: Self::L2,
) -> Result<OraclePipeline<Self::O, Self::L1, Self::L2, Self::DA>> {
let ethereum_data_source =
EthereumDataSource::new_from_parts(l1_provider.clone(), beacon, &rollup_config);
let eigenda_blob_source = EigenDABlobSource::new(self.eigenda_blob_provider.clone());
let da_provider = EigenDADataSource::new(ethereum_data_source, eigenda_blob_source);

Ok(OraclePipeline::new(
rollup_config,
cursor,
oracle,
da_provider,
l1_provider,
l2_provider,
)
.await?)
}
}
1 change: 1 addition & 0 deletions utils/eigenda/client/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod executor;
34 changes: 34 additions & 0 deletions utils/eigenda/host/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
[package]
name = "op-succinct-eigenda-host-utils"
version = "0.1.0"
license.workspace = true
edition.workspace = true

[dependencies]
# sp1
sp1-sdk.workspace = true

# local
op-succinct-eigenda-client-utils.workspace = true
op-succinct-client-utils.workspace = true
op-succinct-host-utils.workspace = true

# kona
kona-preimage.workspace = true
kona-proof.workspace = true

# hokulea
hokulea-eigenda.workspace = true
hokulea-host-bin.workspace = true
hokulea-proof.workspace = true
hokulea-witgen.workspace = true

# alloy
alloy-eips.workspace = true
alloy-primitives.workspace = true

# general
anyhow.workspace = true
async-trait.workspace = true
rkyv.workspace = true
serde_cbor.workspace = true
90 changes: 90 additions & 0 deletions utils/eigenda/host/src/host.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
use std::sync::Arc;

use alloy_eips::BlockId;
use alloy_primitives::B256;
use anyhow::Result;
use async_trait::async_trait;
use hokulea_host_bin::cfg::SingleChainHostWithEigenDA;
use op_succinct_host_utils::{fetcher::OPSuccinctDataFetcher, host::OPSuccinctHost};

use crate::witness_generator::EigenDAWitnessGenerator;

#[derive(Clone)]
pub struct EigenDAOPSuccinctHost {
pub fetcher: Arc<OPSuccinctDataFetcher>,
pub witness_generator: Arc<EigenDAWitnessGenerator>,
}

#[async_trait]
impl OPSuccinctHost for EigenDAOPSuccinctHost {
type Args = SingleChainHostWithEigenDA;
type WitnessGenerator = EigenDAWitnessGenerator;

fn witness_generator(&self) -> &Self::WitnessGenerator {
&self.witness_generator
}

async fn fetch(
&self,
l2_start_block: u64,
l2_end_block: u64,
l1_head_hash: Option<B256>,
safe_db_fallback: bool,
) -> Result<SingleChainHostWithEigenDA> {
// If l1_head_hash is not provided, calculate a safe L1 head
let l1_head = match l1_head_hash {
Some(hash) => hash,
None => {
self.calculate_safe_l1_head(&self.fetcher, l2_end_block, safe_db_fallback).await?
}
};

let host = self.fetcher.get_host_args(l2_start_block, l2_end_block, l1_head).await?;

let eigenda_proxy_address = std::env::var("EIGENDA_PROXY_ADDRESS").ok();
Ok(SingleChainHostWithEigenDA { kona_cfg: host, eigenda_proxy_address, verbose: 1 })
}

fn get_l1_head_hash(&self, args: &Self::Args) -> Option<B256> {
Some(args.kona_cfg.l1_head)
}

async fn get_finalized_l2_block_number(
&self,
fetcher: &OPSuccinctDataFetcher,
_: u64,
) -> Result<Option<u64>> {
let finalized_l2_block_number = fetcher.get_l2_header(BlockId::finalized()).await?;
Ok(Some(finalized_l2_block_number.number))
}

async fn calculate_safe_l1_head(
&self,
fetcher: &OPSuccinctDataFetcher,
l2_end_block: u64,
safe_db_fallback: bool,
) -> Result<B256> {
// For EigenDA, use a similar approach to Ethereum DA with a conservative offset.
let (_, l1_head_number) = fetcher.get_l1_head(l2_end_block, safe_db_fallback).await?;

// Add a buffer for EigenDA similar to Ethereum DA.
let l1_head_number = l1_head_number + 20;

// Ensure we don't exceed the finalized L1 header.
let finalized_l1_header = fetcher.get_l1_header(BlockId::finalized()).await?;
let safe_l1_head_number = std::cmp::min(l1_head_number, finalized_l1_header.number);

Ok(fetcher.get_l1_header(safe_l1_head_number.into()).await?.hash_slow())
}
}

impl EigenDAOPSuccinctHost {
pub fn new(fetcher: Arc<OPSuccinctDataFetcher>) -> Self {
Self {
fetcher,
witness_generator: Arc::new(EigenDAWitnessGenerator {
executor: (), // Placeholder - will be created in witness_generator
}),
}
}
}
2 changes: 2 additions & 0 deletions utils/eigenda/host/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod host;
pub mod witness_generator;
Loading
Loading