-
Notifications
You must be signed in to change notification settings - Fork 8
chore: split the main file into a few making it easier to read #12
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
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| use alloy_eips::{eip4895::Withdrawals, Decodable2718}; | ||
| use alloy_primitives::{Address, Bytes, B256}; | ||
| use alloy_rpc_types::{ | ||
| engine::{PayloadAttributes as EthPayloadAttributes, PayloadId}, | ||
| Withdrawal, | ||
| }; | ||
| use reth_engine_local::payload::UnsupportedLocalAttributes; | ||
| use reth_ethereum::{ | ||
| node::api::payload::{PayloadAttributes, PayloadBuilderAttributes}, | ||
| TransactionSigned, | ||
| }; | ||
| use reth_payload_builder::EthPayloadBuilderAttributes; | ||
| use serde::{Deserialize, Serialize}; | ||
|
|
||
| use crate::error::RollkitEngineError; | ||
|
|
||
| /// Rollkit payload attributes that support passing transactions via Engine API | ||
| #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] | ||
| pub struct RollkitEnginePayloadAttributes { | ||
| /// Standard Ethereum payload attributes | ||
| #[serde(flatten)] | ||
| pub inner: EthPayloadAttributes, | ||
| /// Transactions to be included in the payload (passed via Engine API) | ||
| pub transactions: Option<Vec<Bytes>>, | ||
| /// Optional gas limit for the payload | ||
| #[serde(rename = "gasLimit")] | ||
| pub gas_limit: Option<u64>, | ||
| } | ||
|
|
||
| impl UnsupportedLocalAttributes for RollkitEnginePayloadAttributes {} | ||
|
|
||
| impl PayloadAttributes for RollkitEnginePayloadAttributes { | ||
| fn timestamp(&self) -> u64 { | ||
| self.inner.timestamp() | ||
| } | ||
|
|
||
| fn withdrawals(&self) -> Option<&Vec<Withdrawal>> { | ||
| self.inner.withdrawals() | ||
| } | ||
|
|
||
| fn parent_beacon_block_root(&self) -> Option<B256> { | ||
| self.inner.parent_beacon_block_root() | ||
| } | ||
| } | ||
|
|
||
| /// Rollkit payload builder attributes | ||
| #[derive(Clone, Debug, PartialEq, Eq)] | ||
| pub struct RollkitEnginePayloadBuilderAttributes { | ||
| /// Ethereum payload builder attributes | ||
| pub ethereum_attributes: EthPayloadBuilderAttributes, | ||
| /// Decoded transactions from the Engine API | ||
| pub transactions: Vec<TransactionSigned>, | ||
| /// Gas limit for the payload | ||
| pub gas_limit: Option<u64>, | ||
| } | ||
|
|
||
| impl PayloadBuilderAttributes for RollkitEnginePayloadBuilderAttributes { | ||
| type RpcPayloadAttributes = RollkitEnginePayloadAttributes; | ||
| type Error = RollkitEngineError; | ||
|
|
||
| fn try_new( | ||
| parent: B256, | ||
| attributes: RollkitEnginePayloadAttributes, | ||
| _version: u8, | ||
| ) -> Result<Self, Self::Error> { | ||
| let ethereum_attributes = EthPayloadBuilderAttributes::new(parent, attributes.inner); | ||
|
|
||
| // Decode transactions from bytes if provided | ||
| let transactions = attributes | ||
| .transactions | ||
| .unwrap_or_default() | ||
| .into_iter() | ||
| .map(|tx_bytes| { | ||
| TransactionSigned::network_decode(&mut tx_bytes.as_ref()) | ||
| .map_err(|e| RollkitEngineError::InvalidTransactionData(e.to_string())) | ||
| }) | ||
| .collect::<Result<Vec<_>, _>>()?; | ||
|
|
||
| Ok(Self { | ||
| ethereum_attributes, | ||
| transactions, | ||
| gas_limit: attributes.gas_limit, | ||
| }) | ||
| } | ||
|
|
||
| fn payload_id(&self) -> PayloadId { | ||
| self.ethereum_attributes.id | ||
| } | ||
|
|
||
| fn parent(&self) -> B256 { | ||
| self.ethereum_attributes.parent | ||
| } | ||
|
|
||
| fn timestamp(&self) -> u64 { | ||
| self.ethereum_attributes.timestamp | ||
| } | ||
|
|
||
| fn parent_beacon_block_root(&self) -> Option<B256> { | ||
| self.ethereum_attributes.parent_beacon_block_root | ||
| } | ||
|
|
||
| fn suggested_fee_recipient(&self) -> Address { | ||
| self.ethereum_attributes.suggested_fee_recipient | ||
| } | ||
|
|
||
| fn prev_randao(&self) -> B256 { | ||
| self.ethereum_attributes.prev_randao | ||
| } | ||
|
|
||
| fn withdrawals(&self) -> &Withdrawals { | ||
| &self.ethereum_attributes.withdrawals | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,232 @@ | ||
| use alloy_primitives::U256; | ||
| use clap::Parser; | ||
| use lumen_node::{RollkitPayloadBuilder, RollkitPayloadBuilderConfig}; | ||
| use lumen_rollkit::RollkitPayloadAttributes; | ||
| use reth_basic_payload_builder::{ | ||
| BuildArguments, BuildOutcome, HeaderForPayload, PayloadBuilder, PayloadConfig, | ||
| }; | ||
| use reth_ethereum::{ | ||
| chainspec::{ChainSpec, ChainSpecProvider}, | ||
| node::{ | ||
| api::{payload::PayloadBuilderAttributes, FullNodeTypes, NodeTypes}, | ||
| builder::{components::PayloadBuilderBuilder, BuilderContext}, | ||
| EthEvmConfig, | ||
| }, | ||
| pool::{PoolTransaction, TransactionPool}, | ||
| primitives::Header, | ||
| TransactionSigned, | ||
| }; | ||
| use reth_payload_builder::{EthBuiltPayload, PayloadBuilderError}; | ||
| use reth_provider::HeaderProvider; | ||
| use reth_revm::cached::CachedReads; | ||
| use serde::{Deserialize, Serialize}; | ||
| use std::sync::Arc; | ||
| use tracing::info; | ||
|
|
||
| use crate::{attributes::RollkitEnginePayloadBuilderAttributes, RollkitEngineTypes}; | ||
|
|
||
| /// Rollkit-specific command line arguments | ||
| #[derive(Debug, Clone, Parser, PartialEq, Eq, Serialize, Deserialize, Default)] | ||
| pub struct RollkitArgs { | ||
| /// Enable Rollkit mode for the node (enabled by default) | ||
| #[arg( | ||
| long = "rollkit.enable", | ||
| default_value = "true", | ||
| help = "Enable Rollkit integration for transaction processing via Engine API" | ||
| )] | ||
| pub enable_rollkit: bool, | ||
| } | ||
|
|
||
| /// Rollkit payload service builder that integrates with the rollkit payload builder | ||
| #[derive(Debug, Clone)] | ||
| #[non_exhaustive] | ||
| pub struct RollkitPayloadBuilderBuilder { | ||
| config: RollkitPayloadBuilderConfig, | ||
| } | ||
|
|
||
| impl RollkitPayloadBuilderBuilder { | ||
| /// Create a new builder with rollkit args | ||
| pub fn new(_args: &RollkitArgs) -> Self { | ||
| let config = RollkitPayloadBuilderConfig { | ||
| max_transactions: 1000, | ||
| min_gas_price: 1_000_000_000, // 1 Gwei | ||
| }; | ||
| info!("Created Rollkit payload builder with config: {:?}", config); | ||
| Self { config } | ||
| } | ||
| } | ||
|
|
||
| impl Default for RollkitPayloadBuilderBuilder { | ||
| fn default() -> Self { | ||
| Self::new(&RollkitArgs::default()) | ||
| } | ||
| } | ||
|
|
||
| /// The rollkit engine payload builder that integrates with the rollkit payload builder | ||
| #[derive(Debug, Clone)] | ||
| pub struct RollkitEnginePayloadBuilder<Pool, Client> | ||
| where | ||
| Pool: Clone, | ||
| Client: Clone, | ||
| { | ||
| pub(crate) rollkit_builder: Arc<RollkitPayloadBuilder<Client>>, | ||
| #[allow(dead_code)] | ||
| pub(crate) pool: Pool, | ||
| #[allow(dead_code)] | ||
| pub(crate) config: RollkitPayloadBuilderConfig, | ||
| } | ||
|
|
||
| impl<Node, Pool> PayloadBuilderBuilder<Node, Pool, EthEvmConfig> for RollkitPayloadBuilderBuilder | ||
| where | ||
| Node: FullNodeTypes< | ||
| Types: NodeTypes< | ||
| Payload = RollkitEngineTypes, | ||
| ChainSpec = ChainSpec, | ||
| Primitives = reth_ethereum::EthPrimitives, | ||
| >, | ||
| >, | ||
| Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TransactionSigned>> | ||
| + Unpin | ||
| + 'static, | ||
| { | ||
| type PayloadBuilder = RollkitEnginePayloadBuilder<Pool, Node::Provider>; | ||
|
|
||
| async fn build_payload_builder( | ||
| self, | ||
| ctx: &BuilderContext<Node>, | ||
| pool: Pool, | ||
| evm_config: EthEvmConfig, | ||
| ) -> eyre::Result<Self::PayloadBuilder> { | ||
| let rollkit_builder = Arc::new(RollkitPayloadBuilder::new( | ||
| Arc::new(ctx.provider().clone()), | ||
| evm_config, | ||
| )); | ||
|
|
||
| Ok(RollkitEnginePayloadBuilder { | ||
| rollkit_builder, | ||
| pool, | ||
| config: self.config, | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| impl<Pool, Client> PayloadBuilder for RollkitEnginePayloadBuilder<Pool, Client> | ||
| where | ||
| Client: reth_ethereum::provider::StateProviderFactory | ||
| + ChainSpecProvider<ChainSpec = ChainSpec> | ||
| + HeaderProvider<Header = Header> | ||
| + Clone | ||
| + Send | ||
| + Sync | ||
| + 'static, | ||
| Pool: TransactionPool<Transaction: PoolTransaction<Consensus = TransactionSigned>>, | ||
| { | ||
| type Attributes = RollkitEnginePayloadBuilderAttributes; | ||
| type BuiltPayload = EthBuiltPayload; | ||
|
|
||
| fn try_build( | ||
| &self, | ||
| args: BuildArguments<Self::Attributes, Self::BuiltPayload>, | ||
| ) -> Result<BuildOutcome<Self::BuiltPayload>, PayloadBuilderError> { | ||
| let BuildArguments { | ||
| cached_reads: _, | ||
| config, | ||
| cancel: _, | ||
| best_payload, | ||
| } = args; | ||
| let PayloadConfig { | ||
| parent_header, | ||
| attributes, | ||
| } = config; | ||
|
|
||
| info!( | ||
| "Rollkit engine payload builder: building payload with {} transactions", | ||
| attributes.transactions.len() | ||
| ); | ||
|
|
||
| // Convert Engine API attributes to Rollkit payload attributes | ||
| let rollkit_attrs = RollkitPayloadAttributes::new( | ||
| attributes.transactions.clone(), | ||
| attributes.gas_limit, | ||
| attributes.timestamp(), | ||
| attributes.prev_randao(), | ||
| attributes.suggested_fee_recipient(), | ||
| attributes.parent(), | ||
| parent_header.number + 1, | ||
| ); | ||
|
|
||
| // Build the payload using the rollkit payload builder - use spawn_blocking for async work | ||
| let rollkit_builder = self.rollkit_builder.clone(); | ||
| let sealed_block = tokio::task::block_in_place(|| { | ||
| tokio::runtime::Handle::current().block_on(rollkit_builder.build_payload(rollkit_attrs)) | ||
| }) | ||
| .map_err(PayloadBuilderError::other)?; | ||
|
|
||
| info!( | ||
| "Rollkit engine payload builder: built block with {} transactions, gas used: {}", | ||
| sealed_block.transaction_count(), | ||
| sealed_block.gas_used | ||
| ); | ||
|
|
||
| // Convert to EthBuiltPayload | ||
| let gas_used = sealed_block.gas_used; | ||
| let built_payload = EthBuiltPayload::new( | ||
| attributes.payload_id(), // Use the proper payload ID from attributes | ||
| Arc::new(sealed_block), | ||
| U256::from(gas_used), // Block gas used | ||
| None, // No blob sidecar for rollkit | ||
| ); | ||
|
|
||
| if let Some(best) = best_payload { | ||
| if built_payload.fees() <= best.fees() { | ||
| return Ok(BuildOutcome::Aborted { | ||
| fees: built_payload.fees(), | ||
| cached_reads: CachedReads::default(), | ||
| }); | ||
| } | ||
| } | ||
|
|
||
| Ok(BuildOutcome::Better { | ||
| payload: built_payload, | ||
| cached_reads: CachedReads::default(), | ||
| }) | ||
| } | ||
|
|
||
| fn build_empty_payload( | ||
| &self, | ||
| config: PayloadConfig<Self::Attributes, HeaderForPayload<Self::BuiltPayload>>, | ||
| ) -> Result<Self::BuiltPayload, PayloadBuilderError> { | ||
| let PayloadConfig { | ||
| parent_header, | ||
| attributes, | ||
| } = config; | ||
|
|
||
| info!("Rollkit engine payload builder: building empty payload"); | ||
|
|
||
| // Create empty rollkit attributes (no transactions) | ||
| let rollkit_attrs = RollkitPayloadAttributes::new( | ||
| vec![], | ||
| attributes.gas_limit, | ||
| attributes.timestamp(), | ||
| attributes.prev_randao(), | ||
| attributes.suggested_fee_recipient(), | ||
| attributes.parent(), | ||
| parent_header.number + 1, | ||
| ); | ||
|
|
||
| // Build empty payload - use spawn_blocking for async work | ||
| let rollkit_builder = self.rollkit_builder.clone(); | ||
| let sealed_block = tokio::task::block_in_place(|| { | ||
| tokio::runtime::Handle::current().block_on(rollkit_builder.build_payload(rollkit_attrs)) | ||
| }) | ||
| .map_err(PayloadBuilderError::other)?; | ||
|
|
||
| let gas_used = sealed_block.gas_used; | ||
| Ok(EthBuiltPayload::new( | ||
| attributes.payload_id(), | ||
| Arc::new(sealed_block), | ||
| U256::from(gas_used), | ||
| None, | ||
| )) | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| use lumen_rollkit::PayloadAttributesError; | ||
| use thiserror::Error; | ||
|
|
||
| /// Custom error type used in payload attributes validation | ||
| #[derive(Debug, Error)] | ||
| pub enum RollkitEngineError { | ||
| #[error("Invalid transaction data: {0}")] | ||
| InvalidTransactionData(String), | ||
| #[error("Gas limit exceeded")] | ||
| GasLimitExceeded, | ||
| #[error("Rollkit payload attributes error: {0}")] | ||
| PayloadAttributes(#[from] PayloadAttributesError), | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
poolandconfigfields inRollkitEnginePayloadBuilderare marked with#[allow(dead_code)]and appear to be unused. If these fields are not intended for future use, consider removing them to simplify the struct and its associated code.