Skip to content

Commit

Permalink
feat: L1 traversal (#39)
Browse files Browse the repository at this point in the history
* feat: init L1 traversal

* More types

* moar

* port `alloy`
  • Loading branch information
clabby authored Feb 24, 2024
1 parent e10418f commit 3512c16
Show file tree
Hide file tree
Showing 36 changed files with 4,034 additions and 11 deletions.
294 changes: 293 additions & 1 deletion Cargo.lock

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions crates/derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,16 @@ repository.workspace = true
homepage.workspace = true

[dependencies]
# Workspace
anyhow.workspace = true

# External
alloy-primitives = { version = "0.6.3", default-features = false, features = ["rlp"] }
alloy-rlp = { version = "0.3.4", default-features = false, features = ["derive"] }
async-trait = "0.1.77"

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

[features]
serde = ["dep:serde", "alloy-primitives/serde"]
5 changes: 4 additions & 1 deletion crates/derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@
#![deny(unused_must_use, rust_2018_idioms)]
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
#![no_std]
// Temp
#![allow(dead_code, unused, unreachable_pub)]

// extern crate alloc;
extern crate alloc;

pub mod stages;
pub mod traits;
pub mod types;
89 changes: 89 additions & 0 deletions crates/derive/src/stages/l1_traversal.rs
Original file line number Diff line number Diff line change
@@ -1 +1,90 @@
//! Contains the L1 traversal stage of the derivation pipeline.
use crate::{
traits::{ChainProvider, ResettableStage},
types::{BlockInfo, RollupConfig, SystemConfig},
};
use anyhow::{anyhow, bail, Result};

/// The L1 traversal stage of the derivation pipeline.
#[derive(Debug, Clone, Copy)]
pub struct L1Traversal<F: ChainProvider> {
/// The current block in the traversal stage.
block: Option<BlockInfo>,
/// The data source for the traversal stage.
data_source: F,
/// Signals whether or not the traversal stage has been completed.
done: bool,
/// The system config
system_config: SystemConfig,
/// The rollup config
rollup_config: RollupConfig,
}

impl<F: ChainProvider> L1Traversal<F> {
/// Creates a new [L1Traversal] instance.
pub fn new(data_source: F, cfg: RollupConfig) -> Self {
Self {
block: None,
data_source,
done: false,
system_config: SystemConfig::default(),
rollup_config: cfg,
}
}

/// Returns the next L1 block in the traversal stage, if the stage has not been completed. This function can only
/// be called once, and will return `None` on subsequent calls unless the stage is reset.
pub fn next_l1_block(&mut self) -> Option<BlockInfo> {
if !self.done {
self.done = true;
self.block
} else {
None
}
}

/// Advances the internal state of the [L1Traversal] stage to the next L1 block.
pub async fn advance_l1_block(&mut self) -> Result<()> {
let block = self.block.ok_or(anyhow!("No block to advance from"))?;
let next_l1_origin = self
.data_source
.block_info_by_number(block.number + 1)
.await?;

// Check for reorgs
if block.hash != next_l1_origin.parent_hash {
bail!(
"Detected L1 reorg from {} to {} with conflicting parent",
block.hash,
next_l1_origin.hash
);
}

// Fetch receipts.
let receipts = self
.data_source
.receipts_by_hash(next_l1_origin.hash)
.await?;
self.system_config.update_with_receipts(
receipts.as_slice(),
&self.rollup_config,
next_l1_origin.timestamp,
)?;

self.block = Some(next_l1_origin);
self.done = false;
Ok(())
}
}

impl<F: ChainProvider> ResettableStage for L1Traversal<F> {
fn reset(&mut self, base: BlockInfo, cfg: SystemConfig) -> Result<()> {
self.block = Some(base);
self.done = false;
self.system_config = cfg;

// TODO: Do we want to return an error here w/ EOF?
Ok(())
}
}
18 changes: 10 additions & 8 deletions crates/derive/src/stages/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@
//! 7. Payload Attributes Derivation
//! 8. Engine Queue
pub(crate) mod batch_queue;
pub(crate) mod channel_bank;
pub(crate) mod channel_reader;
pub(crate) mod engine_queue;
pub(crate) mod frame_queue;
pub(crate) mod l1_retrieval;
pub(crate) mod l1_traversal;
pub(crate) mod payload_derivation;
mod l1_traversal;
pub use l1_traversal::L1Traversal;

mod batch_queue;
mod channel_bank;
mod channel_reader;
mod engine_queue;
mod frame_queue;
mod l1_retrieval;
mod payload_derivation;
18 changes: 18 additions & 0 deletions crates/derive/src/traits/data_sources.rs
Original file line number Diff line number Diff line change
@@ -1 +1,19 @@
//! Contains traits that describe the functionality of various data sources used in the derivation pipeline's stages.
// use alloy_rpc_types::Block;
use crate::types::{BlockInfo, Receipt};
use alloc::{boxed::Box, vec::Vec};
use alloy_primitives::B256;
use anyhow::Result;
use async_trait::async_trait;

/// Describes the functionality of a data source that can provide information from the blockchain.
#[async_trait]
pub trait ChainProvider {
/// Returns the block at the given number, or an error if the block does not exist in the data source.
async fn block_info_by_number(&self, number: u64) -> Result<BlockInfo>;

/// Returns all receipts in the block with the given hash, or an error if the block does not exist in the data
/// source.
async fn receipts_by_hash(&self, hash: B256) -> Result<Vec<Receipt>>;
}
6 changes: 5 additions & 1 deletion crates/derive/src/traits/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
//! This module contains all of the traits describing functionality of portions of the derivation pipeline.
pub mod data_sources;
mod data_sources;
pub use data_sources::ChainProvider;

mod stages;
pub use stages::ResettableStage;
11 changes: 11 additions & 0 deletions crates/derive/src/traits/stages.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//! This module contains common traits for stages within the derivation pipeline.
use anyhow::Result;

use crate::types::{BlockInfo, SystemConfig};

/// Describes the functionality fo a resettable stage within the derivation pipeline.
pub trait ResettableStage {
/// Resets the derivation stage to its initial state.
fn reset(&mut self, base: BlockInfo, cfg: SystemConfig) -> Result<()>;
}
101 changes: 101 additions & 0 deletions crates/derive/src/types/block.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
//! This module contains the various Block types.
use alloy_primitives::{BlockHash, BlockNumber, B256};

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

/// Block Header Info
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
pub struct BlockInfo {
/// The block hash
pub hash: B256,
/// The block number
pub number: u64,
/// The parent block hash
pub parent_hash: B256,
/// The block timestamp
pub timestamp: u64,
}

impl BlockInfo {
/// Instantiates a new [BlockInfo].
pub fn new(hash: B256, number: u64, parent_hash: B256, timestamp: u64) -> Self {
Self {
hash,
number,
parent_hash,
timestamp,
}
}
}

// impl TryFrom<BlockWithTransactions> for BlockInfo {
// type Error = anyhow::Error;
//
// fn try_from(block: BlockWithTransactions) -> anyhow::Result<Self> {
// Ok(BlockInfo {
// number: block.number.unwrap_or_default().to::<u64>(),
// hash: block.hash.unwrap_or_default(),
// parent_hash: block.parent_hash,
// timestamp: block.timestamp.to::<u64>(),
// })
// }
// }

/// A Block Identifier
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum BlockId {
/// The block hash
Hash(BlockHash),
/// The block number
Number(BlockNumber),
/// The block kind
Kind(BlockKind),
}

/// The Block Kind
///
/// The block kinds are:
/// - `Earliest`: The earliest known block.
/// - `Latest`: The latest pending block.
/// - `Finalized`: The latest finalized block.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum BlockKind {
/// The earliest known block.
Earliest,
/// The latest pending block.
Latest,
/// The latest finalized block.
Finalized,
}

// /// A Block with Transactions
// #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
// #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
// #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
// pub struct Block {
// /// Header of the block.
// #[serde(flatten)]
// pub header: Header,
// /// Uncles' hashes.
// pub uncles: Vec<B256>,
// /// Block Transactions. In the case of an uncle block, this field is not included in RPC
// /// responses, and when deserialized, it will be set to [BlockTransactions::Uncle].
// #[serde(
// skip_serializing_if = "BlockTransactions::is_uncle",
// default = "BlockTransactions::uncle"
// )]
// pub transactions: BlockTransactions,
// /// Integer the size of this block in bytes.
// pub size: Option<U256>,
// /// Withdrawals in the block.
// #[serde(default, skip_serializing_if = "Option::is_none")]
// pub withdrawals: Option<Vec<Withdrawal>>,
// /// Support for arbitrary additional fields.
// #[serde(flatten)]
// pub other: OtherFields,
// }
21 changes: 21 additions & 0 deletions crates/derive/src/types/eips/eip1559/basefee.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use super::constants::{DEFAULT_BASE_FEE_MAX_CHANGE_DENOMINATOR, DEFAULT_ELASTICITY_MULTIPLIER};

/// BaseFeeParams contains the config parameters that control block base fee computation
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct BaseFeeParams {
/// The base_fee_max_change_denominator from EIP-1559
pub max_change_denominator: u64,
/// The elasticity multiplier from EIP-1559
pub elasticity_multiplier: u64,
}

impl BaseFeeParams {
/// Get the base fee parameters for Ethereum mainnet
pub const fn ethereum() -> BaseFeeParams {
BaseFeeParams {
max_change_denominator: DEFAULT_BASE_FEE_MAX_CHANGE_DENOMINATOR,
elasticity_multiplier: DEFAULT_ELASTICITY_MULTIPLIER,
}
}
}
30 changes: 30 additions & 0 deletions crates/derive/src/types/eips/eip1559/constants.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use alloy_primitives::U256;

/// The default Ethereum block gas limit.
///
/// TODO: This should be a chain spec parameter.
/// See <https://github.com/paradigmxyz/reth/issues/3233>.
pub const ETHEREUM_BLOCK_GAS_LIMIT: u64 = 30_000_000;

/// The minimum tx fee below which the txpool will reject the transaction.
///
/// Configured to `7` WEI which is the lowest possible value of base fee under mainnet EIP-1559
/// parameters. `BASE_FEE_MAX_CHANGE_DENOMINATOR` <https://eips.ethereum.org/EIPS/eip-1559>
/// is `8`, or 12.5%. Once the base fee has dropped to `7` WEI it cannot decrease further because
/// 12.5% of 7 is less than 1.
///
/// Note that min base fee under different 1559 parameterizations may differ, but there's no
/// signifant harm in leaving this setting as is.
pub const MIN_PROTOCOL_BASE_FEE: u64 = 7;

/// Same as [MIN_PROTOCOL_BASE_FEE] but as a U256.
pub const MIN_PROTOCOL_BASE_FEE_U256: U256 = U256::from_limbs([7u64, 0, 0, 0]);

/// Initial base fee as defined in [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559)
pub const INITIAL_BASE_FEE: u64 = 1_000_000_000;

/// Base fee max change denominator as defined in [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559)
pub const DEFAULT_BASE_FEE_MAX_CHANGE_DENOMINATOR: u64 = 8;

/// Elasticity multiplier as defined in [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559)
pub const DEFAULT_ELASTICITY_MULTIPLIER: u64 = 2;
Loading

0 comments on commit 3512c16

Please sign in to comment.