Skip to content

Commit

Permalink
feat(kona-derive): Updated interface (#230)
Browse files Browse the repository at this point in the history
* feat(kona-derive): pipeline output validation

* fix(kona-derive): pipeline interface and associated builder:

* fixes

* Update crates/derive/src/online/validation.rs

Co-authored-by: clabby <[email protected]>

---------

Co-authored-by: clabby <[email protected]>
  • Loading branch information
refcell and clabby authored Jun 11, 2024
1 parent d6f0ba8 commit 9c2fa66
Show file tree
Hide file tree
Showing 8 changed files with 252 additions and 158 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

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

6 changes: 6 additions & 0 deletions crates/derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,15 @@ c-kzg = { version = "1.0.2", default-features = false, optional = true }
sha2 = { version = "0.10.8", default-features = false, optional = true }
alloy-provider = { git = "https://github.com/alloy-rs/alloy", rev = "cb95183", optional = true}
alloy-transport-http = { git = "https://github.com/alloy-rs/alloy", rev = "cb95183", optional = true }
alloy-rpc-types = { git = "https://github.com/alloy-rs/alloy", rev = "cb95183", default-features = false, optional = true }
serde_json = { version = "1.0.94", default-features = false, optional = true }
reqwest = { version = "0.12.4", default-features = false, optional = true }

# `test-utils` feature dependencies
alloy-node-bindings = { git = "https://github.com/alloy-rs/alloy", rev = "cb95183", default-features = false, optional = true }
tracing-subscriber = { version = "0.3.18", optional = true }
alloy-rpc-client = { git = "https://github.com/alloy-rs/alloy", rev = "cb95183", default-features = false, optional = true }
alloy-transport = { git = "https://github.com/alloy-rs/alloy", rev = "cb95183", default-features = false, optional = true }

[dev-dependencies]
tokio = { version = "1.38", features = ["full"] }
Expand All @@ -65,10 +68,13 @@ serde = [
]
k256 = ["alloy-primitives/k256", "alloy-consensus/k256", "op-alloy-consensus/k256"]
online = [
"dep:serde_json",
"dep:revm",
"dep:c-kzg",
"dep:sha2",
"dep:alloy-provider",
"dep:alloy-rpc-types",
"dep:alloy-transport",
"dep:alloy-transport-http",
"dep:reqwest",
"alloy-provider/reqwest",
Expand Down
46 changes: 46 additions & 0 deletions crates/derive/USAGE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
## Usage

```rust
use alloc::sync::Arc;
use kona_derive::online::*;
use kona_derive::pipeline::*;
use kona_primitives::{BlockInfo, L2BlockInfo, RollupConfig};

// Creates a new chain provider using the `L1_RPC_URL` environment variable.
let l1_rpc_url = std::env::var("L1_RPC_URL").expect("L1_RPC_URL must be set");
let chain_provider = AlloyChainProvider::new_http(l1_rpc_url.parse().unwrap());

// Creates a new l2 chain provider using the `L2_RPC_URL` environment variable.
let l2_rpc_url = std::env::var("L2_RPC_URL").expect("L2_RPC_URL must be set");
let l2_chain_provider = AlloyL2ChainProvider::new_http(l2_rpc_url.parse().unwrap());

// TODO(refcell): replace this will a rollup config
// fetched from the superchain-registry via network id.
let rollup_config = Arc::new(RollupConfig::default());

// Create the beacon client used to fetch blob data.
let beacon_url = std::env::var("BEACON_URL").expect("BEACON_URL must be set");
let beacon_client = OnlineBeaconClient::new_http(beacon_url.parse().unwrap());

// Build the online blob provider.
let blob_provider = OnlineBlobProvider::<_, SimpleSlotDerivation>::new(true, beacon_client, None, None);

// Build the ethereum data source
let dap_source = EthereumDataSource::new(chain_provider.clone(), blob_provider, &rollup_config);

// The payload attributes builder that is stateful.
let attributes_builder = StatefulAttributesBuilder::new(rollup_config.clone(), l2_chain_provider.clone(), chain_provider.clone());

// Build the pipeline.
let pipeline = PipelineBuilder::new()
.rollup_config(rollup_config)
.dap_source(dap_source)
.l2_chain_provider(l2_chain_provider)
.chain_provider(chain_provider)
.builder(attributes_builder)
.build();

// The pipeline should be at the default state.
assert_eq!(pipeline.tip, BlockInfo::default());
assert_eq!(pipeline.cursor, L2BlockInfo::default());
```
3 changes: 3 additions & 0 deletions crates/derive/src/online/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ where
#[cfg(any(test, feature = "test-utils"))]
pub mod test_utils;

mod validation;
pub use validation::{OnlineValidator, Validator};

mod beacon_client;
pub use beacon_client::{BeaconClient, OnlineBeaconClient};

Expand Down
94 changes: 94 additions & 0 deletions crates/derive/src/online/validation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
//! Contains logic to validate derivation pipeline outputs.
use crate::types::{L2AttributesWithParent, L2PayloadAttributes, RawTransaction};
use alloc::{boxed::Box, vec, vec::Vec};
use alloy_provider::{Provider, ReqwestProvider};
use alloy_rpc_types::{Block, BlockNumberOrTag, Header};
use alloy_transport::TransportResult;
use anyhow::Result;
use async_trait::async_trait;
use tracing::warn;

/// Validator
///
/// The validator trait describes the interface for validating the derivation outputs.
#[async_trait]
pub trait Validator {
/// Validates the given [`L2AttributesWithParent`].
async fn validate(&self, attributes: &L2AttributesWithParent) -> bool;
}

/// OnlineValidator
///
/// Validates the [`L2AttributesWithParent`] by fetching the associated L2 block from
/// a trusted L2 RPC and constructing the L2 Attributes from the block.
#[derive(Debug, Clone)]
pub struct OnlineValidator {
/// The L2 provider.
provider: ReqwestProvider,
}

impl OnlineValidator {
/// Creates a new `OnlineValidator`.
pub fn new(provider: ReqwestProvider) -> Self {
Self { provider }
}

/// Creates a new [OnlineValidator] from the provided [reqwest::Url].
pub fn new_http(url: reqwest::Url) -> Self {
let inner = ReqwestProvider::new_http(url);
Self::new(inner)
}

/// Fetches a block [Header] and a list of raw RLP encoded transactions from the L2 provider.
///
/// This method needs to fetch the non-hydrated block and then
/// fetch the raw transactions using the `debug_*` namespace.
pub(crate) async fn get_block(
&self,
tag: BlockNumberOrTag,
) -> Result<(Header, Vec<RawTransaction>)> {
// Don't hydrate the block so we only get a list of transaction hashes.
let block: TransportResult<Block> =
self.provider.raw_request("eth_getBlockByNumber".into(), (tag, false)).await;
let block = block.map_err(|e| anyhow::anyhow!(e))?;
// For each transaction hash, fetch the raw transaction RLP.
let mut txs = vec![];
for tx in block.transactions.hashes() {
let tx: TransportResult<RawTransaction> =
self.provider.raw_request("debug_getRawTransaction".into(), tx).await;
if let Ok(tx) = tx {
txs.push(tx);
} else {
warn!("Failed to fetch transaction: {:?}", tx);
}
}
Ok((block.header, txs))
}

/// Gets the payload for the specified [BlockNumberOrTag].
pub(crate) async fn get_payload(&self, tag: BlockNumberOrTag) -> Result<L2PayloadAttributes> {
let (header, transactions) = self.get_block(tag).await?;
Ok(L2PayloadAttributes {
timestamp: header.timestamp,
prev_randao: header.mix_hash.unwrap_or_default(),
fee_recipient: header.miner,
// Withdrawals on optimism are always empty
withdrawals: Default::default(),
parent_beacon_block_root: Some(header.parent_hash),
transactions,
no_tx_pool: true,
gas_limit: Some(header.gas_limit as u64),
})
}
}

#[async_trait]
impl Validator for OnlineValidator {
async fn validate(&self, attributes: &L2AttributesWithParent) -> bool {
let expected = attributes.parent.block_info.number + 1;
let tag = BlockNumberOrTag::from(expected);
let payload = self.get_payload(tag).await.unwrap();
attributes.attributes == payload
}
}
Loading

0 comments on commit 9c2fa66

Please sign in to comment.