Skip to content
Merged
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
12 changes: 12 additions & 0 deletions Cargo.lock

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

6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,12 @@ reth-rpc-engine-api = { git = "https://github.com/paradigmxyz/reth.git", version
reth_ethereum_primitives = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }


# Test dependencies
# Consensus dependencies
reth-consensus = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0", default-features = false }
reth-consensus-common = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0", default-features = false }
reth-ethereum-consensus = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0", default-features = false }

# Test dependencies
reth-testing-utils = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0", default-features = false }
reth-db = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0", default-features = false }
reth-tasks = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0", default-features = false }
Expand Down
3 changes: 3 additions & 0 deletions bin/lumen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ reth-cli-util.workspace = true
reth-ethereum-cli.workspace = true
reth-ethereum = { workspace = true, features = ["node", "cli", "pool"] }
reth-node-builder.workspace = true
reth-node-api.workspace = true
reth-chainspec.workspace = true
reth-primitives-traits.workspace = true
reth-engine-local.workspace = true
Expand All @@ -32,6 +33,8 @@ reth-payload-builder.workspace = true
reth-revm.workspace = true
reth-provider.workspace = true
reth-trie-db.workspace = true
reth-consensus.workspace = true
reth-ethereum-primitives.workspace = true

# Alloy dependencies
alloy-network.workspace = true
Expand Down
10 changes: 4 additions & 6 deletions bin/lumen/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use alloy_rpc_types::engine::{
use clap::Parser;
use lumen_rollkit::{
config::RollkitConfig,
consensus::RollkitConsensusBuilder,
rpc::txpool::{RollkitTxpoolApiImpl, RollkitTxpoolApiServer},
};
use reth_ethereum::{
Expand All @@ -28,10 +29,7 @@ use reth_ethereum::{
rpc::RpcAddOns,
Node, NodeAdapter, NodeComponentsBuilder,
},
node::{
EthereumConsensusBuilder, EthereumExecutorBuilder, EthereumNetworkBuilder,
EthereumPoolBuilder,
},
node::{EthereumExecutorBuilder, EthereumNetworkBuilder, EthereumPoolBuilder},
EthereumEthApiBuilder,
},
primitives::SealedBlock,
Expand Down Expand Up @@ -127,7 +125,7 @@ where
BasicPayloadServiceBuilder<RollkitPayloadBuilderBuilder>,
EthereumNetworkBuilder,
EthereumExecutorBuilder,
EthereumConsensusBuilder,
RollkitConsensusBuilder,
>;
type AddOns = RollkitNodeAddOns<
NodeAdapter<N, <Self::ComponentsBuilder as NodeComponentsBuilder<N>>::Components>,
Expand All @@ -142,7 +140,7 @@ where
RollkitPayloadBuilderBuilder::new(&self.args),
))
.network(EthereumNetworkBuilder::default())
.consensus(EthereumConsensusBuilder::default())
.consensus(RollkitConsensusBuilder::default())
}

fn add_ons(&self) -> Self::AddOns {
Expand Down
9 changes: 9 additions & 0 deletions crates/rollkit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@ reth-primitives.workspace = true
reth-primitives-traits.workspace = true
reth-engine-primitives.workspace = true
reth-transaction-pool.workspace = true
reth-consensus.workspace = true
reth-consensus-common.workspace = true
reth-ethereum-consensus.workspace = true
reth-chainspec.workspace = true
reth-node-api.workspace = true
reth-ethereum = { workspace = true, features = ["node-api", "node"] }
reth-ethereum-primitives.workspace = true
reth-execution-types.workspace = true

# Alloy dependencies
alloy-rpc-types-engine.workspace = true
Expand All @@ -31,6 +39,7 @@ async-trait.workspace = true
jsonrpsee = { workspace = true, features = ["server", "macros"] }
jsonrpsee-core.workspace = true
jsonrpsee-proc-macros.workspace = true
eyre.workspace = true

[dev-dependencies]
serde_json.workspace = true
Expand Down
118 changes: 118 additions & 0 deletions crates/rollkit/src/consensus.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
//! Rollkit custom consensus implementation that allows same timestamps across blocks.

use reth_chainspec::ChainSpec;
use reth_consensus::{Consensus, ConsensusError, FullConsensus, HeaderValidator};
use reth_consensus_common::validation::validate_body_against_header;
use reth_ethereum::node::builder::{components::ConsensusBuilder, BuilderContext};
use reth_ethereum_consensus::EthBeaconConsensus;
use reth_ethereum_primitives::{Block, BlockBody, EthPrimitives, Receipt};
use reth_execution_types::BlockExecutionResult;
use reth_node_api::{FullNodeTypes, NodeTypes};
use reth_primitives::{RecoveredBlock, SealedBlock, SealedHeader};
use std::sync::Arc;

/// Builder for `RollkitConsensus`
#[derive(Debug, Default, Clone)]
#[non_exhaustive]
pub struct RollkitConsensusBuilder;

impl RollkitConsensusBuilder {
/// Create a new `RollkitConsensusBuilder`
pub const fn new() -> Self {
Self
}

/// Build the consensus implementation
pub fn build(chain_spec: Arc<ChainSpec>) -> Arc<RollkitConsensus> {
Arc::new(RollkitConsensus::new(chain_spec))
}
}

impl<Node> ConsensusBuilder<Node> for RollkitConsensusBuilder
where
Node: FullNodeTypes,
Node::Types: NodeTypes<ChainSpec = ChainSpec, Primitives = EthPrimitives>,
{
type Consensus = Arc<dyn FullConsensus<EthPrimitives, Error = ConsensusError>>;

async fn build_consensus(self, ctx: &BuilderContext<Node>) -> eyre::Result<Self::Consensus> {
Ok(Arc::new(RollkitConsensus::new(ctx.chain_spec())) as Self::Consensus)
}
}

/// Rollkit consensus implementation that allows blocks with the same timestamp.
///
/// This consensus implementation wraps the standard Ethereum beacon consensus
/// but modifies the timestamp validation to allow multiple blocks to have the
/// same timestamp, which is required for Rollkit's operation.
#[derive(Debug, Clone)]
pub struct RollkitConsensus {
/// Inner Ethereum beacon consensus for standard validation
inner: EthBeaconConsensus<ChainSpec>,
}

impl RollkitConsensus {
/// Create a new Rollkit consensus instance
pub const fn new(chain_spec: Arc<ChainSpec>) -> Self {
let inner = EthBeaconConsensus::new(chain_spec);
Self { inner }
}
}

impl HeaderValidator for RollkitConsensus {
fn validate_header(&self, header: &SealedHeader) -> Result<(), ConsensusError> {
// Use inner consensus for basic header validation
self.inner.validate_header(header)
}

fn validate_header_against_parent(
&self,
header: &SealedHeader,
parent: &SealedHeader,
) -> Result<(), ConsensusError> {
match self.inner.validate_header_against_parent(header, parent) {
Ok(()) => Ok(()),
// upstream the check is that its greater than the parent's timestamp, if not we get
// TimestampIsInPast we check if the timestamp is equal to the parent's timestamp, if so we
// allow it
Err(ConsensusError::TimestampIsInPast { .. }) => {
if header.timestamp == parent.timestamp {
Ok(())
} else {
Err(ConsensusError::TimestampIsInPast {
parent_timestamp: parent.timestamp,
timestamp: header.timestamp,
})
}
}
Err(e) => Err(e),
}
}
}

impl Consensus<Block> for RollkitConsensus {
type Error = ConsensusError;

fn validate_body_against_header(
&self,
body: &BlockBody,
header: &SealedHeader,
) -> Result<(), Self::Error> {
validate_body_against_header(body, header.header())
}

fn validate_block_pre_execution(&self, block: &SealedBlock) -> Result<(), Self::Error> {
// Use inner consensus for pre-execution validation
self.inner.validate_block_pre_execution(block)
}
}

impl FullConsensus<EthPrimitives> for RollkitConsensus {
fn validate_block_post_execution(
&self,
block: &RecoveredBlock<Block>,
result: &BlockExecutionResult<Receipt>,
) -> Result<(), ConsensusError> {
<EthBeaconConsensus<ChainSpec> as FullConsensus<EthPrimitives>>::validate_block_post_execution(&self.inner, block, result)
}
}
5 changes: 5 additions & 0 deletions crates/rollkit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
//! This crate provides Rollkit-specific functionality including:
//! - Custom payload attributes for Rollkit
//! - Rollkit-specific types and traits
//! - Custom consensus implementation

/// Rollkit-specific types and related definitions.
pub mod types;
Expand All @@ -13,9 +14,13 @@ pub mod config;
/// RPC modules for Rollkit functionality.
pub mod rpc;

/// Custom consensus implementation for Rollkit.
pub mod consensus;

#[cfg(test)]
mod tests;

// Re-export public types
pub use config::{RollkitConfig, DEFAULT_MAX_TXPOOL_BYTES};
pub use consensus::{RollkitConsensus, RollkitConsensusBuilder};
pub use types::{PayloadAttributesError, RollkitPayloadAttributes};
Loading