Skip to content

feature: add transaction forwarding #9

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

Closed
wants to merge 10 commits into from
Closed
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
441 changes: 396 additions & 45 deletions Cargo.lock

Large diffs are not rendered by default.

111 changes: 61 additions & 50 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,71 +1,80 @@
[workspace]
members = [
"bin/lumen",
"crates/common",
"crates/node",
"crates/rollkit",
"crates/tests",
]
resolver = "2"
members = ["bin/lumen", "crates/common", "crates/node", "crates/rollkit", "crates/tests"]

[workspace.package]
version = "0.1.0"
authors = ["Rollkit Contributors"]
edition = "2021"
rust-version = "1.82"
license = "MIT OR Apache-2.0"
homepage = "https://github.com/rollkit/lumen"
license = "MIT OR Apache-2.0"
repository = "https://github.com/rollkit/lumen"
authors = ["Rollkit Contributors"]
rust-version = "1.82"
version = "0.1.0"

[workspace.dependencies]
# Reth dependencies - Using the latest stable versions
reth-basic-payload-builder = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-chain-state = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-chainspec = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-cli = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-cli-util = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-rpc-eth-api = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-node-api = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-node-builder = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-engine-local = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-engine-primitives = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-errors = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-optimism-node = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-optimism-cli = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-optimism-rpc = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-optimism-forks = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-optimism-chainspec = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-optimism-payload-builder = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-optimism-primitives = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-trie-db = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-trie-common = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-rpc-eth-types = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-primitives-traits = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-provider = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-storage-api = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-tracing = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-transaction-pool = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-network = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-network-types = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-chain-state = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-ethereum = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-ethereum-cli = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-basic-payload-builder = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-engine-local = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-engine-primitives = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-ethereum-payload-builder = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-ethereum-primitives = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-evm = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-evm-ethereum = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-execution-types = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-metrics = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-network = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-network-types = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-node-api = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-node-builder = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-node-core = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-node-types = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-optimism-chainspec = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-optimism-cli = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-optimism-forks = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-optimism-node = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-optimism-payload-builder = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-optimism-primitives = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-optimism-rpc = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-payload-builder = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-payload-builder-primitives = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-payload-primitives = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-primitives = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-primitives-traits = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-provider = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-revm = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-rpc = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-rpc-api = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-rpc-builder = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-rpc-engine-api = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-rpc-eth-api = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-rpc-eth-types = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-storage-api = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-tracing = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-transaction-pool = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-trie-common = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth-trie-db = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }
reth_ethereum_primitives = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }

# Additional reth dependencies
reth-tasks = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0" }

# Test dependencies
reth-consensus = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0", default-features = false }
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 }
reth-testing-utils = { git = "https://github.com/paradigmxyz/reth.git", version = "1.5.0", default-features = false }

# Alloy dependencies
alloy = { version = "1.0.17", features = [
Expand All @@ -75,46 +84,48 @@ alloy = { version = "1.0.17", features = [
"signers",
"reqwest-rustls-tls",
], default-features = false }
alloy-consensus = { version = "1.0.17", default-features = false }
alloy-dyn-abi = { version = "1.0.17", default-features = false }
alloy-eips = { version = "1.0.17", default-features = false }
alloy-genesis = { version = "1.0.17", default-features = false }
alloy-json-rpc = { version = "1.0.17", default-features = false }
alloy-network = { version = "1.0.17", default-features = false }
alloy-primitives = { version = "1.2.0", default-features = false }
alloy-provider = { version = "1.0.17", default-features = false }
alloy-rlp = { version = "0.3", default-features = false }
alloy-rpc-client = { version = "1.0.17", default-features = false }
alloy-rpc-types = { version = "1.0.17", default-features = false }
alloy-json-rpc = { version = "1.0.17", default-features = false }
alloy-rpc-types-eth = { version = "1.0.17", default-features = false }
alloy-rpc-types-engine = { version = "1.0.17", default-features = false }
alloy-rpc-types-eth = { version = "1.0.17", default-features = false }
alloy-serde = { version = "1.0.17", default-features = false }
alloy-signer-local = { version = "1.0.17", features = ["mnemonic"] }
alloy-primitives = { version = "1.2.0", default-features = false }
alloy-consensus = { version = "1.0.17", default-features = false }
alloy-rlp = { version = "0.3", default-features = false }
alloy-genesis = { version = "1.0.17", default-features = false }

# Core dependencies
async-trait = "0.1"
clap = { version = "4.5", features = ["derive", "env"] }
eyre = "0.6"
tracing = "0.1"
tokio = { version = "1.38", features = ["full"] }
futures = "0.3"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
thiserror = "2.0"
async-trait = "0.1"
futures = "0.3"
clap = { version = "4.5", features = ["derive", "env"] }
tokio = { version = "1.38", features = ["full"] }
tracing = "0.1"

# Additional dependencies
reqwest = { version = "0.11", features = ["json"] }
chrono = { version = "0.4", features = ["serde"] }
hex = "0.4"
rand = "0.8"
reqwest = { version = "0.11", features = ["json"] }
tempfile = "3.10"
hex = "0.4"

[workspace.lints]
rust.missing_debug_implementations = "warn"
rust.missing_docs = "warn"
rust.rust_2018_idioms = { level = "deny", priority = -1 }
rust.unnameable-types = "warn"
rust.unreachable_pub = "warn"
rust.unused_must_use = "deny"
rustdoc.all = "warn"
rust.unnameable-types = "warn"

[workspace.lints.clippy]
# These are some of clippy's nursery (i.e., experimental) lints that we like.
Expand Down Expand Up @@ -202,15 +213,15 @@ significant_drop_tightening = "allow"
too_long_first_doc_paragraph = "allow"

[profile.release]
opt-level = 3
codegen-units = 1
lto = "thin"
opt-level = 3
strip = "debuginfo"
codegen-units = 1

# Memory-optimized release profile
[profile.docker]
inherits = "release"
opt-level = 2
lto = false
codegen-units = 1
incremental = false
inherits = "release"
lto = false
opt-level = 2
3 changes: 3 additions & 0 deletions bin/lumen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ reth-payload-builder.workspace = true
reth-revm.workspace = true
reth-provider.workspace = true
reth-trie-db.workspace = true
reth-network.workspace = true
reth-node-api.workspace = true
reth-transaction-pool.workspace = true

# Alloy dependencies
alloy-network.workspace = true
Expand Down
112 changes: 101 additions & 11 deletions bin/lumen/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,14 @@ use reth_ethereum::{
NodeTypes, PayloadAttributes, PayloadBuilderAttributes, PayloadTypes, PayloadValidator,
},
builder::{
components::{BasicPayloadServiceBuilder, ComponentsBuilder, PayloadBuilderBuilder},
components::{
BasicPayloadServiceBuilder, ComponentsBuilder, NetworkBuilder,
PayloadBuilderBuilder,
},
rpc::{EngineValidatorBuilder, RpcAddOns},
BuilderContext, Node, NodeAdapter, NodeComponentsBuilder,
},
node::{
EthereumConsensusBuilder, EthereumExecutorBuilder, EthereumNetworkBuilder,
EthereumPoolBuilder,
},
node::{EthereumConsensusBuilder, EthereumExecutorBuilder, EthereumPoolBuilder},
EthEvmConfig, EthereumEthApiBuilder,
},
pool::{PoolTransaction, TransactionPool},
Expand All @@ -48,9 +48,12 @@ use reth_ethereum::{
};
use reth_ethereum_cli::{chainspec::EthereumChainSpecParser, Cli};
use reth_ethereum_payload_builder::EthereumExecutionPayloadValidator;
use reth_network::{types::BasicNetworkPrimitives, NetworkHandle, PeersInfo};
use reth_node_api::{PrimitivesTy, TxTy};
use reth_payload_builder::{EthBuiltPayload, EthPayloadBuilderAttributes, PayloadBuilderError};
use reth_provider::HeaderProvider;
use reth_revm::cached::CachedReads;
use reth_transaction_pool::PoolPooledTx;
use reth_trie_db::MerklePatriciaTrie;
use serde::{Deserialize, Serialize};
use std::sync::Arc;
Expand All @@ -70,6 +73,33 @@ pub struct RollkitArgs {
help = "Enable Rollkit integration for transaction processing via Engine API"
)]
pub enable_rollkit: bool,

/// Optional sequencer HTTP endpoint (e.g. <http://localhost:8547>).
/// If unset, Lumen behaves as today (transactions land in local pool).
#[arg(
long = "sequencer-http",
value_name = "URI",
help = "Forward raw transactions to the given sequencer JSON-RPC endpoint"
)]
pub sequencer_http: Option<String>,

/// Optional Basic-Auth header (e.g. \"Basic dXNlcjpwYXNz\").
/// Can also be supplied via the `SEQUENCER_AUTH` env var.
#[arg(
long = "sequencer-auth",
env = "SEQUENCER_AUTH",
value_name = "BASIC_AUTH",
help = "Basic-Auth string to attach when forwarding to the sequencer"
)]
pub sequencer_auth: Option<String>,

/// Disable local tx-pool gossip while forwarding to a sequencer (OP-Stack parity)
#[arg(
long = "disable-tx-pool-gossip",
default_value_t = false,
help = "Disable mempool gossip when --sequencer-http is set"
)]
pub disable_tx_pool_gossip: bool,
}

/// Rollkit payload attributes that support passing transactions via Engine API
Expand Down Expand Up @@ -353,12 +383,20 @@ where
pub struct RollkitNode {
/// Rollkit-specific arguments
pub args: RollkitArgs,
/// Transaction forwarding configuration
pub forwarding: lumen_node::ForwardingConfig,
}

impl RollkitNode {
/// Create a new rollkit node with the given arguments
pub const fn new(args: RollkitArgs) -> Self {
Self { args }
pub fn new(args: RollkitArgs) -> Self {
let forwarding = lumen_node::ForwardingConfig {
sequencer_http: args.sequencer_http.clone(),
sequencer_auth: args.sequencer_auth.clone(),
disable_tx_pool_gossip: args.disable_tx_pool_gossip,
..Default::default()
};
Self { args, forwarding }
}
}

Expand All @@ -370,7 +408,56 @@ impl NodeTypes for RollkitNode {
type Payload = RollkitEngineTypes;
}

/// Rollkit node addons configuring RPC types with custom engine validator
/// Rollkit network builder that optionally disables transaction pool gossip
#[derive(Debug, Clone, Default)]
pub struct RollkitNetworkBuilder {
/// Whether to disable transaction pool gossip
disable_tx_pool_gossip: bool,
}

impl RollkitNetworkBuilder {
/// Create a new network builder with the given gossip configuration
pub const fn new(disable_tx_pool_gossip: bool) -> Self {
Self {
disable_tx_pool_gossip,
}
}
}

impl<Node, Pool> NetworkBuilder<Node, Pool> for RollkitNetworkBuilder
where
Node: FullNodeTypes<Types: NodeTypes<ChainSpec = ChainSpec>>,
Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TxTy<Node::Types>>>
+ Unpin
+ 'static,
{
type Network =
NetworkHandle<BasicNetworkPrimitives<PrimitivesTy<Node::Types>, PoolPooledTx<Pool>>>;

async fn build_network(
self,
ctx: &BuilderContext<Node>,
pool: Pool,
) -> eyre::Result<Self::Network> {
// Configure the network with optional tx gossip disabled
let network_config = ctx
.network_config_builder()?
.disable_tx_gossip(self.disable_tx_pool_gossip)
.build(ctx.provider().clone());

if self.disable_tx_pool_gossip {
info!("Rollkit: Transaction pool gossip disabled");
}

// Build the network
let network = reth_network::NetworkManager::builder(network_config).await?;
let handle = ctx.start_network(network, pool);

info!(target: "reth::cli", enode=%handle.local_node_record(), "P2P networking initialized");
Ok(handle)
}
}

pub type RollkitNodeAddOns<N> = RpcAddOns<N, EthereumEthApiBuilder, RollkitEngineValidatorBuilder>;

impl<N> Node<N> for RollkitNode
Expand All @@ -388,7 +475,7 @@ where
N,
EthereumPoolBuilder,
BasicPayloadServiceBuilder<RollkitPayloadBuilderBuilder>,
EthereumNetworkBuilder,
RollkitNetworkBuilder,
EthereumExecutorBuilder,
EthereumConsensusBuilder,
>;
Expand All @@ -404,7 +491,7 @@ where
.payload(BasicPayloadServiceBuilder::new(
RollkitPayloadBuilderBuilder::new(&self.args),
))
.network(EthereumNetworkBuilder::default())
.network(RollkitNetworkBuilder::new(self.args.disable_tx_pool_gossip))
.consensus(EthereumConsensusBuilder::default())
}

Expand Down Expand Up @@ -607,6 +694,9 @@ where
}
}

#[cfg(test)]
mod network_test;

fn main() {
info!("=== ROLLKIT-RETH NODE STARTING ===");

Expand All @@ -627,7 +717,7 @@ fn main() {
info!("=== ROLLKIT-RETH: Using custom payload builder with transaction support ===");

let handle = builder
.node(RollkitNode::new(rollkit_args))
.node(RollkitNode::new(rollkit_args.clone()))
.launch()
.await?;

Expand Down
Loading
Loading