Skip to content

Commit

Permalink
feat(derive): Online Blob Provider (#117)
Browse files Browse the repository at this point in the history
* feat(derive): online blob provider

* feat(derive): stash blob sidecar progress

* feat(derive): blobs

* feat(derive): blobs

* feat(derive): c_kzg import

* fix(derive): remove .DS_Store

* fix(derive): gitignore .DS_Store

* fix(derive): impl sidecar fetching and fix c-kzg online feat flag

* feat(derive): blob provider tests

* fix(derive): add revm-primitives as a dependency for kzg points

* feat(derive): blob testdata and provider tests

* fix(derive): cargo toml nit
  • Loading branch information
refcell authored Apr 18, 2024
1 parent ff42d44 commit c27b31b
Show file tree
Hide file tree
Showing 16 changed files with 1,031 additions and 3 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ target

# Example targets
examples/**/target

.DS_Store
64 changes: 64 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 13 additions & 1 deletion crates/derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,14 @@ unsigned-varint = "0.8.0"
miniz_oxide = { version = "0.7.2" }
lru = "0.12.3"
spin = { version = "0.9.8", features = ["mutex"] }
revm-primitives = { version = "3.1", default-features = false, optional = true }

# `serde` feature dependencies
serde = { version = "1.0.197", default-features = false, features = ["derive"], optional = true }

# `online` feature dependencies
c-kzg = { version = "1.0.0", default-features = false, optional = true }
sha2 = { version = "0.10", default-features = false, optional = true }
alloy-provider = { git = "https://github.com/alloy-rs/alloy", rev = "e3f2f07", optional = true}
alloy-transport-http = { git = "https://github.com/alloy-rs/alloy", rev = "e3f2f07", optional = true }
reqwest = { version = "0.12", default-features = false, optional = true }
Expand All @@ -39,14 +42,23 @@ reqwest = { version = "0.12", default-features = false, optional = true }
tokio = { version = "1.36", features = ["full"] }
proptest = "1.4.0"
tracing-subscriber = "0.3.18"
alloy-node-bindings = { git = "https://github.com/alloy-rs/alloy", rev = "e3f2f07", default-features = false }
alloy-rpc-client = { git = "https://github.com/alloy-rs/alloy", rev = "e3f2f07", default-features = false }
serde_json = { version = "1.0.68", default-features = false }

[features]
default = ["serde", "k256"]
serde = ["dep:serde", "alloy-primitives/serde", "alloy-consensus/serde", "op-alloy-consensus/serde"]
k256 = ["alloy-primitives/k256", "alloy-consensus/k256", "op-alloy-consensus/k256"]
online = [
"dep:revm-primitives",
"dep:c-kzg",
"dep:sha2",
"dep:alloy-provider",
"dep:alloy-transport-http",
"dep:reqwest",
"alloy-consensus/serde"
"alloy-consensus/serde",
"c-kzg/serde",
"revm-primitives/serde",
"revm-primitives/c-kzg",
]
4 changes: 3 additions & 1 deletion crates/derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ pub mod traits;
pub mod types;

#[cfg(feature = "online")]
pub mod alloy_providers;
mod online;
#[cfg(feature = "online")]
pub use online::prelude::*;

/// The derivation pipeline is responsible for deriving L2 inputs from L1 data.
#[derive(Debug, Clone, Copy)]
Expand Down
File renamed without changes.
88 changes: 88 additions & 0 deletions crates/derive/src/online/beacon_client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
//! Contains an online implementation of the [BeaconClient] trait.

use crate::types::{
APIConfigResponse, APIGenesisResponse, APIGetBlobSidecarsResponse, IndexedBlobHash,
};
use alloc::{boxed::Box, string::String};
use alloy_provider::Provider;
use alloy_transport_http::Http;
use async_trait::async_trait;
use reqwest::Client;

/// The node version engine api method.
pub(crate) const VERSION_METHOD: &str = "eth/v1/node/version";

/// The config spec engine api method.
pub(crate) const SPEC_METHOD: &str = "eth/v1/config/spec";

/// The beacon genesis engine api method.
pub(crate) const GENESIS_METHOD: &str = "eth/v1/beacon/genesis";

/// The blob sidecars engine api method prefix.
pub(crate) const SIDECARS_METHOD_PREFIX: &str = "eth/v1/beacon/blob_sidecars/";

/// The [BeaconClient] is a thin wrapper around the Beacon API.
#[async_trait]
pub trait BeaconClient {
/// Returns the node version.
async fn node_version(&self) -> anyhow::Result<String>;

/// Returns the config spec.
async fn config_spec(&self) -> anyhow::Result<APIConfigResponse>;

/// Returns the beacon genesis.
async fn beacon_genesis(&self) -> anyhow::Result<APIGenesisResponse>;

/// Fetches blob sidecars that were confirmed in the specified L1 block with the given indexed
/// hashes. Order of the returned sidecars is guaranteed to be that of the hashes. Blob data is
/// not checked for validity.
async fn beacon_blob_side_cars(
&self,
fetch_all_sidecars: bool,
slot: u64,
hashes: &[IndexedBlobHash],
) -> anyhow::Result<APIGetBlobSidecarsResponse>;
}

/// An online implementation of the [BeaconClient] trait.
#[derive(Debug)]
pub struct OnlineBeaconClient<T: Provider<Http<Client>>> {
/// The inner Ethereum JSON-RPC provider.
inner: T,
}

impl<T: Provider<Http<Client>>> OnlineBeaconClient<T> {
/// Creates a new instance of the [OnlineBeaconClient].
pub fn new(inner: T) -> Self {
Self { inner }
}
}

#[async_trait]
impl<T: Provider<Http<Client>> + Send> BeaconClient for OnlineBeaconClient<T> {
async fn node_version(&self) -> anyhow::Result<String> {
self.inner.client().request(VERSION_METHOD, ()).await.map_err(|e| anyhow::anyhow!(e))
}

async fn config_spec(&self) -> anyhow::Result<APIConfigResponse> {
self.inner.client().request(SPEC_METHOD, ()).await.map_err(|e| anyhow::anyhow!(e))
}

async fn beacon_genesis(&self) -> anyhow::Result<APIGenesisResponse> {
self.inner.client().request(GENESIS_METHOD, ()).await.map_err(|e| anyhow::anyhow!(e))
}

async fn beacon_blob_side_cars(
&self,
fetch_all_sidecars: bool,
slot: u64,
hashes: &[IndexedBlobHash],
) -> anyhow::Result<APIGetBlobSidecarsResponse> {
let method = alloc::format!("{}{}", SIDECARS_METHOD_PREFIX, slot);
self.inner
.client()
.request(method, (fetch_all_sidecars, hashes))
.await
.map_err(|e| anyhow::anyhow!(e))
}
}
Loading

0 comments on commit c27b31b

Please sign in to comment.