diff --git a/bin/node/src/args.rs b/bin/node/src/args.rs index cde67a02..69fa4dd7 100644 --- a/bin/node/src/args.rs +++ b/bin/node/src/args.rs @@ -2,12 +2,17 @@ use clap::Args; use std::time::Duration; use url::Url; +use xlayer_builder::args::BuilderArgs; use xlayer_monitor::FullLinkMonitorArgs; /// X Layer specific configuration flags #[derive(Debug, Clone, Args, PartialEq, Eq, Default)] #[command(next_help_heading = "X Layer")] pub struct XLayerArgs { + /// Flashblock builder configuration + #[command(flatten)] + pub builder: BuilderArgs, + /// Enable legacy rpc routing #[command(flatten)] pub legacy: LegacyRpcArgs, @@ -291,10 +296,7 @@ mod tests { legacy_rpc_url: Some("invalid-url".to_string()), legacy_rpc_timeout: Duration::from_secs(30), }, - monitor: FullLinkMonitorArgs::default(), - enable_flashblocks_subscription: false, - flashblocks_subscription_max_addresses: 1000, - sequencer_mode: false, + ..Default::default() }; let result = args.validate(); diff --git a/bin/node/src/main.rs b/bin/node/src/main.rs index deec5428..06d1bffd 100644 --- a/bin/node/src/main.rs +++ b/bin/node/src/main.rs @@ -19,9 +19,8 @@ use reth::{ }; use reth_node_api::FullNodeComponents; use reth_optimism_cli::Cli; -use reth_optimism_node::OpNode; +use reth_optimism_node::{args::RollupArgs, OpNode}; use reth_rpc_server_types::RethRpcModule; -use xlayer_builder::args::OpRbuilderArgs; use xlayer_chainspec::XLayerChainSpecParser; use xlayer_flashblocks::handler::FlashblocksService; @@ -36,9 +35,9 @@ static ALLOC: reth_cli_util::allocator::Allocator = reth_cli_util::allocator::ne #[derive(Debug, Clone, PartialEq, Eq, clap::Args)] #[command(next_help_heading = "Rollup")] struct Args { - /// Upstream rollup args + flashblock specific args + /// Upstream rollup args #[command(flatten)] - pub node_args: OpRbuilderArgs, + pub rollup_args: RollupArgs, #[command(flatten)] pub xlayer_args: XLayerArgs, @@ -77,7 +76,7 @@ fn main() { info!(target: "xlayer::monitor", "Global tracer initialized with output path: {}", args.xlayer_args.monitor.output_path); } - let op_node = OpNode::new(args.node_args.rollup_args.clone()); + let op_node = OpNode::new(args.rollup_args.clone()); let genesis_block = builder.config().chain.genesis().number.unwrap_or_default(); info!("X Layer genesis block = {}", genesis_block); @@ -95,7 +94,7 @@ fn main() { // For X Layer full link monitor let monitor = XLayerMonitor::new( xlayer_args.monitor, - args.node_args.flashblocks.enabled, + xlayer_args.builder.flashblocks.enabled, xlayer_args.sequencer_mode, ); @@ -106,7 +105,10 @@ fn main() { // Create the X Layer payload service builder // It handles both flashblocks and default modes internally - let payload_builder = XLayerPayloadServiceBuilder::new(args.node_args.clone())?; + let payload_builder = XLayerPayloadServiceBuilder::new( + args.xlayer_args.builder.clone(), + args.rollup_args.compute_pending_block, + )?; let NodeHandle { node, node_exit_future } = builder .with_types_and_provider::>() @@ -120,13 +122,14 @@ fn main() { let new_op_eth_api = Arc::new(ctx.registry.eth_api().clone()); // Initialize flashblocks RPC service if not in flashblocks sequencer mode - if !args.node_args.flashblocks.enabled { + if !args.xlayer_args.builder.flashblocks.enabled { if let Some(flashblock_rx) = new_op_eth_api.subscribe_received_flashblocks() { let service = FlashblocksService::new( ctx.node().clone(), flashblock_rx, - args.node_args.clone(), + args.xlayer_args.builder.flashblocks, + args.rollup_args.flashblocks_url.is_some(), )?; service.spawn(); info!(target: "reth::cli", "xlayer flashblocks service initialized"); diff --git a/bin/node/src/payload.rs b/bin/node/src/payload.rs index 1cdb42ef..1f0579e5 100644 --- a/bin/node/src/payload.rs +++ b/bin/node/src/payload.rs @@ -5,7 +5,7 @@ use reth_optimism_evm::OpEvmConfig; use reth_optimism_node::node::OpPayloadBuilder; use reth_optimism_payload_builder::config::{OpDAConfig, OpGasLimitConfig}; use xlayer_builder::{ - args::OpRbuilderArgs, + args::BuilderArgs, payload::{BuilderConfig, FlashblocksServiceBuilder}, traits::{NodeBounds, PoolBounds}, }; @@ -25,12 +25,21 @@ pub struct XLayerPayloadServiceBuilder { } impl XLayerPayloadServiceBuilder { - pub fn new(xlayer_builder_args: OpRbuilderArgs) -> eyre::Result { - Self::with_config(xlayer_builder_args, OpDAConfig::default(), OpGasLimitConfig::default()) + pub fn new( + xlayer_builder_args: BuilderArgs, + compute_pending_block: bool, + ) -> eyre::Result { + Self::with_config( + xlayer_builder_args, + compute_pending_block, + OpDAConfig::default(), + OpGasLimitConfig::default(), + ) } pub fn with_config( - xlayer_builder_args: OpRbuilderArgs, + xlayer_builder_args: BuilderArgs, + compute_pending_block: bool, da_config: OpDAConfig, gas_limit_config: OpGasLimitConfig, ) -> eyre::Result { @@ -40,10 +49,9 @@ impl XLayerPayloadServiceBuilder { builder_config, ))) } else { - let payload_builder = - OpPayloadBuilder::new(xlayer_builder_args.rollup_args.compute_pending_block) - .with_da_config(da_config) - .with_gas_limit_config(gas_limit_config); + let payload_builder = OpPayloadBuilder::new(compute_pending_block) + .with_da_config(da_config) + .with_gas_limit_config(gas_limit_config); XLayerPayloadServiceBuilderInner::Default(BasicPayloadServiceBuilder::new( payload_builder, )) diff --git a/crates/builder/src/args/mod.rs b/crates/builder/src/args/mod.rs index 5bbc5789..d86eb0d2 100644 --- a/crates/builder/src/args/mod.rs +++ b/crates/builder/src/args/mod.rs @@ -1,5 +1,5 @@ -pub use op::{FlashblocksArgs, OpRbuilderArgs}; +pub use op::{BuilderArgs, FlashblocksArgs}; use reth_optimism_cli::chainspec::OpChainSpecParser; -pub type Cli = reth_optimism_cli::Cli; +pub type Cli = reth_optimism_cli::Cli; mod op; diff --git a/crates/builder/src/args/op.rs b/crates/builder/src/args/op.rs index 6f6486d4..fe0b61c8 100644 --- a/crates/builder/src/args/op.rs +++ b/crates/builder/src/args/op.rs @@ -1,24 +1,17 @@ -//! Additional Node command arguments. +//! Flashblock builder command arguments. //! -//! Copied from OptimismNode to allow easy extension. - -//! clap [Args](clap::Args) for optimism rollup configuration +//! Builder-specific configuration for the flashblock payload builder. use crate::tx::signer::Signer; use alloy_primitives::Address; use anyhow::{anyhow, Result}; use clap::Parser; use reth_optimism_cli::commands::Commands; -use reth_optimism_node::args::RollupArgs; use std::path::PathBuf; -/// Parameters for rollup configuration +/// Parameters for the flashblock builder configuration. #[derive(Debug, Clone, PartialEq, Eq, clap::Args)] -#[command(next_help_heading = "Rollup")] -pub struct OpRbuilderArgs { - /// Rollup configuration - #[command(flatten)] - pub rollup_args: RollupArgs, +pub struct BuilderArgs { /// Builder secret key for signing last transaction in block #[arg(long = "rollup.builder-secret-key", env = "BUILDER_SECRET_KEY")] pub builder_signer: Option, @@ -52,7 +45,7 @@ pub struct OpRbuilderArgs { pub flashblocks: FlashblocksArgs, } -impl Default for OpRbuilderArgs { +impl Default for BuilderArgs { fn default() -> Self { let args = crate::args::Cli::parse_from(["dummy", "node"]); let Commands::Node(node_command) = args.command else { unreachable!() }; @@ -71,7 +64,7 @@ fn expand_path(s: &str) -> Result { /// Parameters for Flashblocks configuration /// The names in the struct are prefixed with `flashblocks` to avoid conflicts /// with the standard block building configuration since these args are flattened -/// into the main `OpRbuilderArgs` struct with the other rollup/node args. +/// into the main `BuilderArgs` struct with the other rollup/node args. #[derive(Debug, Clone, PartialEq, Eq, clap::Args)] pub struct FlashblocksArgs { /// When set to true, the builder will build flashblocks @@ -108,14 +101,6 @@ pub struct FlashblocksArgs { )] pub flashblocks_disable_state_root: bool, - /// Whether to builder running with rollup boost - #[arg( - long = "flashblocks.disable-rollup-boost", - default_value = "false", - env = "FLASHBLOCK_DISABLE_ROLLUP_BOOST" - )] - pub flashblocks_disable_rollup_boost: bool, - /// Whether to disable async state root calculation on full payload resolution #[arg( long = "flashblocks.disable-async-calculate-state-root", diff --git a/crates/builder/src/metrics/tokio.rs b/crates/builder/src/metrics/tokio.rs index 3761f5cd..a174003f 100644 --- a/crates/builder/src/metrics/tokio.rs +++ b/crates/builder/src/metrics/tokio.rs @@ -13,7 +13,7 @@ use tokio_metrics::{RuntimeMetrics, RuntimeMonitor, TaskMetrics, TaskMonitor}; /// Metrics for a single monitored tokio task. #[derive(Metrics, Clone)] -#[metrics(scope = "op_rbuilder.tokio_task")] +#[metrics(scope = "flashblock_builder.tokio_task")] pub struct TokioTaskMetricsRecorder { /// Total number of times the task has been instrumented (spawned) pub instrumented_count: Counter, @@ -52,7 +52,7 @@ pub struct TokioTaskMetricsRecorder { /// Note: Only stable tokio metrics are exposed here. Additional metrics like /// steal counts, schedule counts, and overflow counts require the `tokio_unstable` flag. #[derive(Metrics, Clone)] -#[metrics(scope = "op_rbuilder.tokio_runtime")] +#[metrics(scope = "flashblock_builder.tokio_runtime")] pub struct TokioRuntimeMetricsRecorder { /// Number of worker threads in the runtime pub workers_count: Gauge, diff --git a/crates/builder/src/payload/builder_tx.rs b/crates/builder/src/payload/builder_tx.rs index 15468a57..2cbaa5a1 100644 --- a/crates/builder/src/payload/builder_tx.rs +++ b/crates/builder/src/payload/builder_tx.rs @@ -137,107 +137,121 @@ impl BuilderTransactionError { } } -pub trait BuilderTransactions { +pub trait BuilderTransactions { // Simulates and returns the signed builder transactions. The simulation modifies and commit // changes to the db so call new_simulation_state to simulate on a new copy of the state fn simulate_builder_txs( &self, - ctx: &OpPayloadBuilderCtx, + ctx: &OpPayloadBuilderCtx, db: &mut State, + is_first_flashblock: bool, + is_last_flashblock: bool, ) -> Result, BuilderTransactionError>; fn simulate_builder_txs_with_state_copy( &self, state_provider: impl StateProvider + Clone, - ctx: &OpPayloadBuilderCtx, + ctx: &OpPayloadBuilderCtx, db: &State, + is_first_flashblock: bool, + is_last_flashblock: bool, ) -> Result, BuilderTransactionError> { let mut simulation_state = self.new_simulation_state(state_provider, db); - self.simulate_builder_txs(ctx, &mut simulation_state) + self.simulate_builder_txs( + ctx, + &mut simulation_state, + is_first_flashblock, + is_last_flashblock, + ) } + #[expect(clippy::too_many_arguments)] fn add_builder_txs( &self, state_provider: impl StateProvider + Clone, - info: &mut ExecutionInfo, - builder_ctx: &OpPayloadBuilderCtx, + info: &mut ExecutionInfo, + builder_ctx: &OpPayloadBuilderCtx, db: &mut State, top_of_block: bool, + is_first_flashblock: bool, + is_last_flashblock: bool, ) -> Result, BuilderTransactionError> { - { - let builder_txs = - self.simulate_builder_txs_with_state_copy(state_provider, builder_ctx, db)?; - - let mut evm = - builder_ctx.evm_config.evm_with_env(&mut *db, builder_ctx.evm_env.clone()); - - let mut invalid = HashSet::new(); - - for builder_tx in builder_txs.iter() { - if builder_tx.is_top_of_block != top_of_block { - // don't commit tx if the buidler tx is not being added in the intended - // position in the block - continue; - } - if invalid.contains(&builder_tx.signed_tx.signer()) { - warn!(target: "payload_builder", tx_hash = ?builder_tx.signed_tx.tx_hash(), "builder signer invalid as previous builder tx reverted"); - continue; - } + let builder_txs = self.simulate_builder_txs_with_state_copy( + state_provider, + builder_ctx, + db, + is_first_flashblock, + is_last_flashblock, + )?; + + let mut evm = builder_ctx.evm_config.evm_with_env(&mut *db, builder_ctx.evm_env.clone()); + + let mut invalid = HashSet::new(); + + for builder_tx in builder_txs.iter() { + if builder_tx.is_top_of_block != top_of_block { + // don't commit tx if the buidler tx is not being added in the intended + // position in the block + continue; + } + if invalid.contains(&builder_tx.signed_tx.signer()) { + warn!(target: "payload_builder", tx_hash = ?builder_tx.signed_tx.tx_hash(), "builder signer invalid as previous builder tx reverted"); + continue; + } - let ResultAndState { result, state } = match evm.transact(&builder_tx.signed_tx) { - Ok(res) => res, - Err(err) => { - if let Some(err) = err.as_invalid_tx_err() { - if err.is_nonce_too_low() { - // if the nonce is too low, we can skip this transaction - trace!(target: "payload_builder", %err, ?builder_tx.signed_tx, "skipping nonce too low builder transaction"); - } else { - // if the transaction is invalid, we can skip it and all of its - // descendants - trace!(target: "payload_builder", %err, ?builder_tx.signed_tx, "skipping invalid builder transaction and its descendants"); - invalid.insert(builder_tx.signed_tx.signer()); - } - - continue; + let ResultAndState { result, state } = match evm.transact(&builder_tx.signed_tx) { + Ok(res) => res, + Err(err) => { + if let Some(err) = err.as_invalid_tx_err() { + if err.is_nonce_too_low() { + // if the nonce is too low, we can skip this transaction + trace!(target: "payload_builder", %err, ?builder_tx.signed_tx, "skipping nonce too low builder transaction"); + } else { + // if the transaction is invalid, we can skip it and all of its + // descendants + trace!(target: "payload_builder", %err, ?builder_tx.signed_tx, "skipping invalid builder transaction and its descendants"); + invalid.insert(builder_tx.signed_tx.signer()); } - // this is an error that we should treat as fatal for this attempt - return Err(BuilderTransactionError::EvmExecutionError(Box::new(err))); - } - }; - if !result.is_success() { - warn!(target: "payload_builder", tx_hash = ?builder_tx.signed_tx.tx_hash(), result = ?result, "builder tx reverted"); - invalid.insert(builder_tx.signed_tx.signer()); - continue; + continue; + } + // this is an error that we should treat as fatal for this attempt + return Err(BuilderTransactionError::EvmExecutionError(Box::new(err))); } + }; - // Add gas used by the transaction to cumulative gas used, before creating the receipt - let gas_used = result.gas_used(); - info.cumulative_gas_used += gas_used; - info.cumulative_da_bytes_used += builder_tx.da_size; - - let ctx = ReceiptBuilderCtx { - tx: builder_tx.signed_tx.inner(), - evm: &evm, - result, - state: &state, - cumulative_gas_used: info.cumulative_gas_used, - }; - info.receipts.push(builder_ctx.build_receipt(ctx, None)); - - // Commit changes - evm.db_mut().commit(state); - - // Append sender and transaction to the respective lists - info.executed_senders.push(builder_tx.signed_tx.signer()); - info.executed_transactions.push(builder_tx.signed_tx.clone().into_inner()); + if !result.is_success() { + warn!(target: "payload_builder", tx_hash = ?builder_tx.signed_tx.tx_hash(), result = ?result, "builder tx reverted"); + invalid.insert(builder_tx.signed_tx.signer()); + continue; } - // Release the db reference by dropping evm - drop(evm); - - Ok(builder_txs) + // Add gas used by the transaction to cumulative gas used, before creating the receipt + let gas_used = result.gas_used(); + info.cumulative_gas_used += gas_used; + info.cumulative_da_bytes_used += builder_tx.da_size; + + let ctx = ReceiptBuilderCtx { + tx: builder_tx.signed_tx.inner(), + evm: &evm, + result, + state: &state, + cumulative_gas_used: info.cumulative_gas_used, + }; + info.receipts.push(builder_ctx.build_receipt(ctx, None)); + + // Commit changes + evm.db_mut().commit(state); + + // Append sender and transaction to the respective lists + info.executed_senders.push(builder_tx.signed_tx.signer()); + info.executed_transactions.push(builder_tx.signed_tx.clone().into_inner()); } + + // Release the db reference by dropping evm + drop(evm); + + Ok(builder_txs) } // Creates a copy of the state to simulate against @@ -261,7 +275,7 @@ pub trait BuilderTransactions, + ctx: &OpPayloadBuilderCtx, db: impl DatabaseRef, ) -> Result, BuilderTransactionError> { let nonce = get_nonce(db, from.address)?; @@ -282,7 +296,7 @@ pub trait BuilderTransactions>, - ctx: &OpPayloadBuilderCtx, + ctx: &OpPayloadBuilderCtx, db: &mut State, ) -> Result<(), BuilderTransactionError> { let mut evm = ctx.evm_config.evm_with_env(&mut *db, ctx.evm_env.clone()); @@ -358,19 +372,18 @@ pub trait BuilderTransactions { +pub(super) struct BuilderTxBase { pub signer: Option, - _marker: std::marker::PhantomData, } -impl BuilderTxBase { +impl BuilderTxBase { pub(super) fn new(signer: Option) -> Self { - Self { signer, _marker: std::marker::PhantomData } + Self { signer } } pub(super) fn simulate_builder_tx( &self, - ctx: &OpPayloadBuilderCtx, + ctx: &OpPayloadBuilderCtx, db: impl DatabaseRef, ) -> Result, BuilderTransactionError> { match self.signer { @@ -415,7 +428,7 @@ impl BuilderTxBase { fn signed_builder_tx( &self, - ctx: &OpPayloadBuilderCtx, + ctx: &OpPayloadBuilderCtx, db: impl DatabaseRef, signer: Signer, gas_used: u64, diff --git a/crates/builder/src/payload/context.rs b/crates/builder/src/payload/context.rs index 81276d4f..9bfbf3d0 100644 --- a/crates/builder/src/payload/context.rs +++ b/crates/builder/src/payload/context.rs @@ -4,7 +4,6 @@ use alloy_evm::Database; use alloy_op_evm::block::receipt_builder::OpReceiptBuilder; use alloy_primitives::{BlockHash, Bytes, U256}; use alloy_rpc_types_eth::Withdrawals; -use core::fmt::Debug; use op_alloy_consensus::OpDepositReceipt; use op_revm::OpSpecId; use reth::payload::PayloadBuilderAttributes; @@ -45,7 +44,7 @@ use alloy_eips::eip2718::WithEncoded; /// Container type that holds all necessities to build a new payload. #[derive(Debug)] -pub struct OpPayloadBuilderCtx { +pub struct OpPayloadBuilderCtx { /// The type that knows how to perform system calls and configure the evm. pub evm_config: OpEvmConfig, /// The DA config for the payload builder @@ -66,21 +65,15 @@ pub struct OpPayloadBuilderCtx { pub builder_signer: Option, /// The metrics for the builder pub metrics: Arc, - /// Extra context for the payload builder - pub extra_ctx: ExtraCtx, /// Max gas that can be used by a transaction. pub max_gas_per_txn: Option, } -impl OpPayloadBuilderCtx { +impl OpPayloadBuilderCtx { pub(super) fn with_cancel(self, cancel: CancellationToken) -> Self { Self { cancel, ..self } } - pub(super) fn with_extra_ctx(self, extra_ctx: ExtraCtx) -> Self { - Self { extra_ctx, ..self } - } - /// Returns the parent block the payload will be build on. pub fn parent(&self) -> &SealedHeader { &self.config.parent_header @@ -136,10 +129,7 @@ impl OpPayloadBuilderCtx { /// This will return the culmative DA bytes * scalar after Jovian /// after Ecotone, this will always return Some(0) as blobs aren't supported /// pre Ecotone, these fields aren't used. - pub fn blob_fields( - &self, - info: &ExecutionInfo, - ) -> (Option, Option) { + pub fn blob_fields(&self, info: &ExecutionInfo) -> (Option, Option) { // For payload validation if let Some(blob_fields) = info.optional_blob_fields { return blob_fields; @@ -228,7 +218,7 @@ impl OpPayloadBuilderCtx { } } -impl OpPayloadBuilderCtx { +impl OpPayloadBuilderCtx { /// Constructs a receipt for the given transaction. pub fn build_receipt( &self, @@ -262,10 +252,10 @@ impl OpPayloadBuilderCtx { } /// Executes all sequencer transactions that are included in the payload attributes. - pub(super) fn execute_sequencer_transactions( + pub(super) fn execute_sequencer_transactions( &self, db: &mut State, - ) -> Result, PayloadBuilderError> { + ) -> Result { let mut info = ExecutionInfo::with_capacity(self.attributes().transactions.len()); let mut evm = self.evm_config.evm_with_env(&mut *db, self.evm_env.clone()); @@ -359,9 +349,9 @@ impl OpPayloadBuilderCtx { /// Executes cached transactions received via P2P, used to replay previously sequenced flashblock /// transactions when the builder changes before the full block is built. - pub(super) fn execute_cached_flashblocks_transactions( + pub(super) fn execute_cached_flashblocks_transactions( &self, - info: &mut ExecutionInfo, + info: &mut ExecutionInfo, db: &mut State, cached_txs: Vec>>, ) -> Result<(), PayloadBuilderError> { @@ -466,9 +456,9 @@ impl OpPayloadBuilderCtx { /// Executes the given best transactions and updates the execution info. /// /// Returns `Ok(Some(())` if the job was cancelled. - pub(super) fn execute_best_transactions( + pub(super) fn execute_best_transactions( &self, - info: &mut ExecutionInfo, + info: &mut ExecutionInfo, db: &mut State, best_txs: &mut impl PayloadTxsBounds, block_gas_limit: u64, diff --git a/crates/builder/src/payload/flashblocks/builder_tx.rs b/crates/builder/src/payload/flashblocks/builder_tx.rs index 15a6790c..17e5f63b 100644 --- a/crates/builder/src/payload/flashblocks/builder_tx.rs +++ b/crates/builder/src/payload/flashblocks/builder_tx.rs @@ -4,7 +4,6 @@ use alloy_op_evm::OpEvm; use alloy_primitives::{Address, B256}; use alloy_rpc_types_eth::TransactionInput; use alloy_sol_types::{sol, SolCall, SolEvent}; -use core::fmt::Debug; use op_alloy_rpc_types::OpTransactionRequest; use reth_evm::{precompiles::PrecompilesMap, ConfigureEvm}; use reth_revm::State; @@ -13,11 +12,8 @@ use tracing::warn; use crate::{ payload::{ - builder_tx::BuilderTxBase, - context::OpPayloadBuilderCtx, - flashblocks::payload::{FlashblocksExecutionInfo, FlashblocksExtraCtx}, - get_nonce, BuilderTransactionCtx, BuilderTransactionError, BuilderTransactions, - SimulationSuccessResult, + builder_tx::BuilderTxBase, context::OpPayloadBuilderCtx, get_nonce, BuilderTransactionCtx, + BuilderTransactionError, BuilderTransactions, SimulationSuccessResult, }, tx::signer::Signer, }; @@ -53,7 +49,7 @@ sol!( // This will be the end of block transaction of a regular block #[derive(Debug, Clone)] pub(super) struct FlashblocksBuilderTx { - pub base_builder_tx: BuilderTxBase, + pub base_builder_tx: BuilderTxBase, } impl FlashblocksBuilderTx { @@ -63,20 +59,22 @@ impl FlashblocksBuilderTx { } } -impl BuilderTransactions for FlashblocksBuilderTx { +impl BuilderTransactions for FlashblocksBuilderTx { fn simulate_builder_txs( &self, - ctx: &OpPayloadBuilderCtx, + ctx: &OpPayloadBuilderCtx, db: &mut State, + is_first_flashblock: bool, + is_last_flashblock: bool, ) -> Result, BuilderTransactionError> { let mut builder_txs = Vec::::new(); - if ctx.is_first_flashblock() { + if is_first_flashblock { let flashblocks_builder_tx = self.base_builder_tx.simulate_builder_tx(ctx, &mut *db)?; builder_txs.extend(flashblocks_builder_tx.clone()); } - if ctx.is_last_flashblock() { + if is_last_flashblock { let base_tx = self.base_builder_tx.simulate_builder_tx(ctx, &mut *db)?; builder_txs.extend(base_tx); } @@ -89,7 +87,7 @@ impl BuilderTransactions for Flas pub(super) struct FlashblocksNumberBuilderTx { pub signer: Signer, pub flashblock_number_address: Address, - pub base_builder_tx: BuilderTxBase, + pub base_builder_tx: BuilderTxBase, } impl FlashblocksNumberBuilderTx { @@ -100,7 +98,7 @@ impl FlashblocksNumberBuilderTx { fn signed_increment_flashblocks_tx( &self, - ctx: &OpPayloadBuilderCtx, + ctx: &OpPayloadBuilderCtx, evm: &mut OpEvm, ) -> Result { let calldata = IFlashblockNumber::incrementFlashblockNumberCall {}; @@ -110,7 +108,7 @@ impl FlashblocksNumberBuilderTx { fn increment_flashblocks_tx( &self, calldata: T, - ctx: &OpPayloadBuilderCtx, + ctx: &OpPayloadBuilderCtx, evm: &mut OpEvm, ) -> Result { let SimulationSuccessResult { gas_used, .. } = self.simulate_flashblocks_call( @@ -136,7 +134,7 @@ impl FlashblocksNumberBuilderTx { &self, calldata: T, expected_logs: Vec, - ctx: &OpPayloadBuilderCtx, + ctx: &OpPayloadBuilderCtx, evm: &mut OpEvm, ) -> Result, BuilderTransactionError> { let tx_req = OpTransactionRequest::default() @@ -154,17 +152,17 @@ impl FlashblocksNumberBuilderTx { } } -impl BuilderTransactions - for FlashblocksNumberBuilderTx -{ +impl BuilderTransactions for FlashblocksNumberBuilderTx { fn simulate_builder_txs( &self, - ctx: &OpPayloadBuilderCtx, + ctx: &OpPayloadBuilderCtx, db: &mut State, + is_first_flashblock: bool, + _is_last_flashblock: bool, ) -> Result, BuilderTransactionError> { let mut builder_txs = Vec::::new(); - if ctx.is_first_flashblock() { + if is_first_flashblock { // fallback block builder tx builder_txs.extend(self.base_builder_tx.simulate_builder_tx(ctx, &mut *db)?); } else { diff --git a/crates/builder/src/payload/flashblocks/config.rs b/crates/builder/src/payload/flashblocks/config.rs index f0d204f1..932cb245 100644 --- a/crates/builder/src/payload/flashblocks/config.rs +++ b/crates/builder/src/payload/flashblocks/config.rs @@ -1,6 +1,6 @@ use alloy_primitives::Address; -use crate::{args::OpRbuilderArgs, payload::BuilderConfig}; +use crate::{args::BuilderArgs, payload::BuilderConfig}; use core::{ net::{Ipv4Addr, SocketAddr}, time::Duration, @@ -21,9 +21,6 @@ pub struct FlashblocksConfig { /// Should we disable state root calculation for each flashblock pub disable_state_root: bool, - /// Should we disable running builder in rollup boost mode - pub disable_rollup_boost: bool, - /// Should we disable async state root calculation on full payload resolution pub disable_async_calculate_state_root: bool, @@ -71,7 +68,6 @@ impl Default for FlashblocksConfig { ws_addr: SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), 1111), interval: Duration::from_millis(250), disable_state_root: false, - disable_rollup_boost: false, disable_async_calculate_state_root: false, number_contract_address: None, send_offset_ms: 0, @@ -88,10 +84,10 @@ impl Default for FlashblocksConfig { } } -impl TryFrom for FlashblocksConfig { +impl TryFrom for FlashblocksConfig { type Error = eyre::Report; - fn try_from(args: OpRbuilderArgs) -> Result { + fn try_from(args: BuilderArgs) -> Result { let interval = Duration::from_millis(args.flashblocks.flashblocks_block_time); let ws_addr = SocketAddr::new( @@ -101,8 +97,6 @@ impl TryFrom for FlashblocksConfig { let disable_state_root = args.flashblocks.flashblocks_disable_state_root; - let disable_rollup_boost = args.flashblocks.flashblocks_disable_rollup_boost; - let disable_async_calculate_state_root = args.flashblocks.flashblocks_disable_async_calculate_state_root; @@ -112,7 +106,6 @@ impl TryFrom for FlashblocksConfig { ws_addr, interval, disable_state_root, - disable_rollup_boost, disable_async_calculate_state_root, number_contract_address, send_offset_ms: args.flashblocks.flashblocks_send_offset_ms, diff --git a/crates/builder/src/payload/flashblocks/ctx.rs b/crates/builder/src/payload/flashblocks/context.rs similarity index 96% rename from crates/builder/src/payload/flashblocks/ctx.rs rename to crates/builder/src/payload/flashblocks/context.rs index ce1dfb1e..534c7213 100644 --- a/crates/builder/src/payload/flashblocks/ctx.rs +++ b/crates/builder/src/payload/flashblocks/context.rs @@ -18,7 +18,7 @@ use std::sync::Arc; use tokio_util::sync::CancellationToken; #[derive(Debug, Clone)] -pub(super) struct OpPayloadSyncerCtx { +pub(super) struct FlashblockHandlerContext { /// The type that knows how to perform system calls and configure the evm. evm_config: OpEvmConfig, /// The DA config for the payload builder @@ -31,7 +31,7 @@ pub(super) struct OpPayloadSyncerCtx { metrics: Arc, } -impl OpPayloadSyncerCtx { +impl FlashblockHandlerContext { pub(super) fn new( client: &Client, builder_config: BuilderConfig, @@ -87,7 +87,6 @@ impl OpPayloadSyncerCtx { cancel, builder_signer: None, metrics: self.metrics, - extra_ctx: (), max_gas_per_txn: self.max_gas_per_txn, } } diff --git a/crates/builder/src/payload/flashblocks/handler.rs b/crates/builder/src/payload/flashblocks/handler.rs index 3822b8ca..06dff8c3 100644 --- a/crates/builder/src/payload/flashblocks/handler.rs +++ b/crates/builder/src/payload/flashblocks/handler.rs @@ -1,8 +1,8 @@ use crate::{ payload::{ flashblocks::{ - cache::FlashblockPayloadsCache, ctx::OpPayloadSyncerCtx, p2p::Message, - payload::FlashblocksExecutionInfo, wspub::WebSocketPublisher, + cache::FlashblockPayloadsCache, context::FlashblockHandlerContext, p2p::Message, + wspub::WebSocketPublisher, }, utils::execution::ExecutionInfo, }, @@ -37,6 +37,8 @@ use tracing::warn; /// In the case of a payload built by this node, it is broadcast to peers and an event is sent to the payload builder. /// In the case of a payload received from a peer, it is executed and if successful, an event is sent to the payload builder. pub(crate) struct PayloadHandler { + // handler context for external flashblock execution + ctx: FlashblockHandlerContext, // receives new flashblock payloads built by this builder. built_fb_payload_rx: mpsc::Receiver, // receives new full block payloads built by this builder. @@ -51,8 +53,6 @@ pub(crate) struct PayloadHandler { p2p_cache: FlashblockPayloadsCache, // websocket publisher for broadcasting flashblocks to all connected subscribers. ws_pub: Arc, - // context required for execution of blocks during syncing - ctx: OpPayloadSyncerCtx, // chain client client: Client, // task executor @@ -69,6 +69,7 @@ where { #[allow(clippy::too_many_arguments)] pub(crate) fn new( + ctx: FlashblockHandlerContext, built_fb_payload_rx: mpsc::Receiver, built_payload_rx: mpsc::Receiver, p2p_rx: mpsc::Receiver, @@ -76,7 +77,6 @@ where payload_events_handle: tokio::sync::broadcast::Sender>, p2p_cache: FlashblockPayloadsCache, ws_pub: Arc, - ctx: OpPayloadSyncerCtx, client: Client, task_executor: Tasks, cancel: tokio_util::sync::CancellationToken, @@ -202,7 +202,7 @@ where fn execute_built_payload( payload: OpBuiltPayload, - ctx: OpPayloadSyncerCtx, + ctx: FlashblockHandlerContext, client: Client, cancel: tokio_util::sync::CancellationToken, ) -> eyre::Result<(OpBuiltPayload, OpFlashblockPayload)> @@ -335,6 +335,7 @@ where &mut state, &builder_ctx, &mut info, + None, true, ) .wrap_err("failed to build flashblock")?; @@ -359,8 +360,8 @@ where #[allow(clippy::too_many_arguments)] fn execute_transactions( - ctx: &OpPayloadSyncerCtx, - info: &mut ExecutionInfo, + ctx: &FlashblockHandlerContext, + info: &mut ExecutionInfo, state: &mut State, txs: Vec, gas_limit: u64, @@ -440,7 +441,7 @@ fn execute_transactions( } fn build_receipt( - ctx: &OpPayloadSyncerCtx, + ctx: &FlashblockHandlerContext, receipt_ctx: ReceiptBuilderCtx<'_, OpTransactionSigned, E>, deposit_nonce: Option, timestamp: u64, diff --git a/crates/builder/src/payload/flashblocks/mod.rs b/crates/builder/src/payload/flashblocks/mod.rs index 92ba3e4a..5e495b6c 100644 --- a/crates/builder/src/payload/flashblocks/mod.rs +++ b/crates/builder/src/payload/flashblocks/mod.rs @@ -7,7 +7,7 @@ mod best_txs; mod builder_tx; mod cache; mod config; -mod ctx; +mod context; mod handler; mod p2p; mod payload; diff --git a/crates/builder/src/payload/flashblocks/p2p.rs b/crates/builder/src/payload/flashblocks/p2p.rs index d2267e41..f339d2b5 100644 --- a/crates/builder/src/payload/flashblocks/p2p.rs +++ b/crates/builder/src/payload/flashblocks/p2p.rs @@ -5,7 +5,7 @@ use reth_optimism_payload_builder::OpBuiltPayload as RethOpBuiltPayload; use reth_optimism_primitives::OpBlock; use serde::{Deserialize, Serialize}; -pub(super) const AGENT_VERSION: &str = "op-rbuilder/1.0.0"; +pub(super) const AGENT_VERSION: &str = "flashblock-builder/1.0.0"; pub(super) const FLASHBLOCKS_STREAM_PROTOCOL: crate::p2p::StreamProtocol = crate::p2p::StreamProtocol::new("/flashblocks/1.0.0"); diff --git a/crates/builder/src/payload/flashblocks/payload.rs b/crates/builder/src/payload/flashblocks/payload.rs index b94908ff..9d0e38f4 100644 --- a/crates/builder/src/payload/flashblocks/payload.rs +++ b/crates/builder/src/payload/flashblocks/payload.rs @@ -89,13 +89,7 @@ type NextBestFlashblocksTxs = BestFlashblocksTxs< >; #[derive(Debug, Default, Clone)] -pub(super) struct FlashblocksExecutionInfo { - /// Index of the last consumed flashblock - last_flashblock_index: usize, -} - -#[derive(Debug, Default, Clone)] -pub struct FlashblocksExtraCtx { +pub(super) struct FlashblocksState { /// Current flashblock index flashblock_index: u64, /// Target flashblock count per block @@ -114,13 +108,19 @@ pub struct FlashblocksExtraCtx { da_footprint_per_batch: Option, /// Whether to disable state root calculation for each flashblock disable_state_root: bool, - /// Whether to disable running builder in rollup boost mode - disable_rollup_boost: bool, + /// Index into `ExecutionInfo` tracking the last consumed flashblock. + /// Used for slicing transactions/receipts per flashblock. + last_flashblock_tx_index: usize, } -impl FlashblocksExtraCtx { +impl FlashblocksState { + fn new(target_flashblock_count: u64, disable_state_root: bool) -> Self { + Self { target_flashblock_count, disable_state_root, ..Default::default() } + } + + /// Creates state for the next flashblock with updated limits fn next( - self, + &self, target_gas_for_batch: u64, target_da_for_batch: Option, target_da_footprint_for_batch: Option, @@ -130,30 +130,54 @@ impl FlashblocksExtraCtx { target_gas_for_batch, target_da_for_batch, target_da_footprint_for_batch, - ..self + ..*self } } -} -impl OpPayloadBuilderCtx { - /// Returns the current flashblock index - pub(crate) fn flashblock_index(&self) -> u64 { - self.extra_ctx.flashblock_index + fn with_batch_limits( + mut self, + gas_per_batch: u64, + da_per_batch: Option, + da_footprint_per_batch: Option, + target_gas_for_batch: u64, + target_da_for_batch: Option, + target_da_footprint_for_batch: Option, + ) -> Self { + self.gas_per_batch = gas_per_batch; + self.da_per_batch = da_per_batch; + self.da_footprint_per_batch = da_footprint_per_batch; + self.target_gas_for_batch = target_gas_for_batch; + self.target_da_for_batch = target_da_for_batch; + self.target_da_footprint_for_batch = target_da_footprint_for_batch; + self + } + + fn flashblock_index(&self) -> u64 { + self.flashblock_index } - /// Returns the target flashblock count - pub(crate) fn target_flashblock_count(&self) -> u64 { - self.extra_ctx.target_flashblock_count + fn target_flashblock_count(&self) -> u64 { + self.target_flashblock_count } - /// Returns if the flashblock is the first fallback block - pub(crate) fn is_first_flashblock(&self) -> bool { - self.flashblock_index() == 0 + fn is_first_flashblock(&self) -> bool { + self.flashblock_index == 0 } - /// Returns if the flashblock is the last one - pub(crate) fn is_last_flashblock(&self) -> bool { - self.flashblock_index() == self.target_flashblock_count() + fn is_last_flashblock(&self) -> bool { + self.flashblock_index == self.target_flashblock_count + } + + fn set_last_flashblock_tx_index(&mut self, index: usize) { + self.last_flashblock_tx_index = index; + } + + /// Extracts new transactions since the last flashblock + fn slice_new_transactions<'a>( + &self, + all_transactions: &'a [OpTransactionSigned], + ) -> &'a [OpTransactionSigned] { + &all_transactions[self.last_flashblock_tx_index..] } } @@ -256,7 +280,7 @@ impl OpPayloadBuilder + Send + Sync, + BuilderTx: BuilderTransactions + Send + Sync, Tasks: TaskSpawner + Clone + Unpin + 'static, { fn get_op_payload_builder_ctx( @@ -265,8 +289,7 @@ where OpPayloadBuilderAttributes, >, cancel: CancellationToken, - extra_ctx: FlashblocksExtraCtx, - ) -> eyre::Result> { + ) -> eyre::Result { let chain_spec = self.client.chain_spec(); let timestamp = config.attributes.timestamp(); @@ -299,7 +322,7 @@ where .next_evm_env(&config.parent_header, &block_env_attributes) .wrap_err("failed to create next evm env")?; - Ok(OpPayloadBuilderCtx:: { + Ok(OpPayloadBuilderCtx { evm_config: self.evm_config.clone(), chain_spec, config, @@ -310,7 +333,6 @@ where gas_limit_config: self.config.gas_limit_config.clone(), builder_signer: self.config.builder_signer, metrics: self.metrics.clone(), - extra_ctx, max_gas_per_txn: self.config.max_gas_per_txn, }) } @@ -333,17 +355,13 @@ where let disable_state_root = self.config.specific.disable_state_root; let ctx = self - .get_op_payload_builder_ctx( - config.clone(), - block_cancel.clone(), - FlashblocksExtraCtx { - target_flashblock_count: self.config.flashblocks_per_block(), - disable_state_root, - ..Default::default() - }, - ) + .get_op_payload_builder_ctx(config.clone(), block_cancel.clone()) .map_err(|e| PayloadBuilderError::Other(e.into()))?; + // Initialize flashblocks state for this block + let mut fb_state = + FlashblocksState::new(self.config.flashblocks_per_block(), disable_state_root); + let state_provider = self.client.state_by_block_hash(ctx.parent().hash())?; let db = StateProviderDatabase::new(&state_provider); // 1. execute the pre steps and seal an early block with that @@ -380,8 +398,15 @@ where // For X Layer - skip if replaying if !ctx.attributes().no_tx_pool && !rebuild_external_payload - && let Err(e) = - self.builder_tx.add_builder_txs(&state_provider, &mut info, &ctx, &mut state, false) + && let Err(e) = self.builder_tx.add_builder_txs( + &state_provider, + &mut info, + &ctx, + &mut state, + false, + fb_state.is_first_flashblock(), + fb_state.is_last_flashblock(), + ) { error!( target: "payload_builder", @@ -392,7 +417,7 @@ where // We should always calculate state root for fallback payload let (fallback_payload, fb_payload, bundle_state, new_tx_hashes) = - build_block(&mut state, &ctx, &mut info, true)?; + build_block(&mut state, &ctx, &mut info, Some(&mut fb_state), true)?; // For X Layer - skip if replaying if !rebuild_external_payload { self.built_fb_payload_tx @@ -479,22 +504,23 @@ where let da_footprint_per_batch = info.da_footprint_scalar.map(|_| ctx.block_gas_limit() / target_flashblocks); - let extra_ctx = FlashblocksExtraCtx { - flashblock_index: 1, - target_flashblock_count: target_flashblocks, - target_gas_for_batch: gas_per_batch, - target_da_for_batch: da_per_batch, + fb_state = fb_state.with_batch_limits( gas_per_batch, da_per_batch, da_footprint_per_batch, - disable_state_root, - target_da_footprint_for_batch: da_footprint_per_batch, - disable_rollup_boost: self.config.specific.disable_rollup_boost, + gas_per_batch, + da_per_batch, + da_footprint_per_batch, + ); + fb_state = FlashblocksState { + flashblock_index: 1, + target_flashblock_count: target_flashblocks, + ..fb_state }; let fb_cancel = block_cancel.child_token(); let mut ctx = self - .get_op_payload_builder_ctx(config, fb_cancel.clone(), extra_ctx) + .get_op_payload_builder_ctx(config, fb_cancel.clone()) .map_err(|e| PayloadBuilderError::Other(e.into()))?; // Create best_transaction iterator @@ -517,7 +543,7 @@ where debug!( target: "payload_builder", id = %fb_payload.payload_id, - flashblock_index = ctx.flashblock_index(), + flashblock_index = fb_state.flashblock_index(), block_number = ctx.block_number(), "Received signal to build flashblock", ); @@ -525,13 +551,14 @@ where } else { // Channel closed - block building cancelled self.resolve_best_payload(&ctx, best_payload, fallback_payload, &resolve_payload); - self.record_flashblocks_metrics(&ctx, &info, target_flashblocks); + self.record_flashblocks_metrics(&ctx, &fb_state, &info, target_flashblocks); return Ok(()); } // Build flashblock after receiving signal - let next_flashblocks_ctx = match self.build_next_flashblock( + let next_fb_state = match self.build_next_flashblock( &ctx, + &mut fb_state, &mut info, &mut state, &state_provider, @@ -539,7 +566,7 @@ where &block_cancel, &mut best_payload, ) { - Ok(Some(next_flashblocks_ctx)) => next_flashblocks_ctx, + Ok(Some(next_fb_state)) => next_fb_state, Ok(None) => { self.resolve_best_payload( &ctx, @@ -547,14 +574,14 @@ where fallback_payload, &resolve_payload, ); - self.record_flashblocks_metrics(&ctx, &info, target_flashblocks); + self.record_flashblocks_metrics(&ctx, &fb_state, &info, target_flashblocks); return Ok(()); } Err(err) => { error!( target: "payload_builder", id = %fb_payload.payload_id, - flashblock_index = ctx.flashblock_index(), + flashblock_index = fb_state.flashblock_index(), block_number = ctx.block_number(), ?err, "Failed to build flashblock", @@ -569,7 +596,7 @@ where } }; - ctx = ctx.with_extra_ctx(next_flashblocks_ctx); + fb_state = next_fb_state; } } @@ -579,18 +606,19 @@ where P: StateRootProvider + HashedPostStateProvider + StorageRootProvider, >( &self, - ctx: &OpPayloadBuilderCtx, - info: &mut ExecutionInfo, + ctx: &OpPayloadBuilderCtx, + fb_state: &mut FlashblocksState, + info: &mut ExecutionInfo, state: &mut State, state_provider: impl reth::providers::StateProvider + Clone, best_txs: &mut NextBestFlashblocksTxs, block_cancel: &CancellationToken, best_payload: &mut (OpBuiltPayload, BundleState), - ) -> eyre::Result> { - let flashblock_index = ctx.flashblock_index(); - let mut target_gas_for_batch = ctx.extra_ctx.target_gas_for_batch; - let mut target_da_for_batch = ctx.extra_ctx.target_da_for_batch; - let mut target_da_footprint_for_batch = ctx.extra_ctx.target_da_footprint_for_batch; + ) -> eyre::Result> { + let flashblock_index = fb_state.flashblock_index(); + let mut target_gas_for_batch = fb_state.target_gas_for_batch; + let mut target_da_for_batch = fb_state.target_da_for_batch; + let mut target_da_footprint_for_batch = fb_state.target_da_footprint_for_batch; info!( target: "payload_builder", @@ -606,14 +634,21 @@ where ); let flashblock_build_start_time = Instant::now(); - let builder_txs = - match self.builder_tx.add_builder_txs(&state_provider, info, ctx, state, true) { - Ok(builder_txs) => builder_txs, - Err(e) => { - error!(target: "payload_builder", "Error simulating builder txs: {}", e); - vec![] - } - }; + let builder_txs = match self.builder_tx.add_builder_txs( + &state_provider, + info, + ctx, + state, + true, + fb_state.is_first_flashblock(), + fb_state.is_last_flashblock(), + ) { + Ok(builder_txs) => builder_txs, + Err(e) => { + error!(target: "payload_builder", "Error simulating builder txs: {}", e); + vec![] + } + }; // only reserve builder tx gas / da size that has not been committed yet // committed builder txs would have counted towards the gas / da used @@ -658,8 +693,8 @@ where ) .wrap_err("failed to execute best transactions")?; // Extract last transactions - let new_transactions = info.executed_transactions[info.extra.last_flashblock_index..] - .to_vec() + let new_transactions = fb_state + .slice_new_transactions(&info.executed_transactions) .iter() .map(|tx| tx.tx_hash()) .collect::>(); @@ -677,17 +712,21 @@ where .record(payload_transaction_simulation_time); ctx.metrics.payload_transaction_simulation_gauge.set(payload_transaction_simulation_time); - if let Err(e) = self.builder_tx.add_builder_txs(&state_provider, info, ctx, state, false) { + if let Err(e) = self.builder_tx.add_builder_txs( + &state_provider, + info, + ctx, + state, + false, + fb_state.is_first_flashblock(), + fb_state.is_last_flashblock(), + ) { error!(target: "payload_builder", "Error simulating builder txs: {}", e); }; let total_block_built_duration = Instant::now(); - let build_result = build_block( - state, - ctx, - info, - !ctx.extra_ctx.disable_state_root || ctx.attributes().no_tx_pool, - ); + let calculate_state_root = !fb_state.disable_state_root || ctx.attributes().no_tx_pool; + let build_result = build_block(state, ctx, info, Some(fb_state), calculate_state_root); let total_block_built_duration = total_block_built_duration.elapsed(); ctx.metrics.total_block_built_duration.record(total_block_built_duration); ctx.metrics.total_block_built_gauge.set(total_block_built_duration); @@ -701,11 +740,6 @@ where fb_payload.index = flashblock_index; fb_payload.base = None; - // If main token got canceled in here that means we received get_payload and we should drop everything and now update best_payload - // To ensure that we will return same blocks as rollup-boost (to leverage caches) - if !ctx.extra_ctx.disable_rollup_boost && block_cancel.is_cancelled() { - return Ok(None); - } let flashblock_byte_size = self .ws_pub .publish(&fb_payload) @@ -729,7 +763,7 @@ where ); // Update bundle_state for next iteration - if let Some(da_limit) = ctx.extra_ctx.da_per_batch { + if let Some(da_limit) = fb_state.da_per_batch { if let Some(da) = target_da_for_batch.as_mut() { *da += da_limit; } else { @@ -739,16 +773,15 @@ where } } - let target_gas_for_batch = - ctx.extra_ctx.target_gas_for_batch + ctx.extra_ctx.gas_per_batch; + let target_gas_for_batch = fb_state.target_gas_for_batch + fb_state.gas_per_batch; if let (Some(footprint), Some(da_footprint_limit)) = - (target_da_footprint_for_batch.as_mut(), ctx.extra_ctx.da_footprint_per_batch) + (target_da_footprint_for_batch.as_mut(), fb_state.da_footprint_per_batch) { *footprint += da_footprint_limit; } - let next_extra_ctx = ctx.extra_ctx.clone().next( + let next_fb_state = fb_state.next( target_gas_for_batch, target_da_for_batch, target_da_footprint_for_batch, @@ -761,18 +794,18 @@ where flashblock_index = flashblock_index, current_gas = info.cumulative_gas_used, current_da = info.cumulative_da_bytes_used, - target_flashblocks = ctx.target_flashblock_count(), + target_flashblocks = fb_state.target_flashblock_count(), "Flashblock built" ); - Ok(Some(next_extra_ctx)) + Ok(Some(next_fb_state)) } } } fn resolve_best_payload( &self, - ctx: &OpPayloadBuilderCtx, + ctx: &OpPayloadBuilderCtx, best_payload: (OpBuiltPayload, BundleState), fallback_payload: OpBuiltPayload, resolve_payload: &BlockCell, @@ -838,15 +871,16 @@ where /// Do some logging and metric recording when we stop build flashblocks fn record_flashblocks_metrics( &self, - ctx: &OpPayloadBuilderCtx, - info: &ExecutionInfo, + ctx: &OpPayloadBuilderCtx, + fb_state: &FlashblocksState, + info: &ExecutionInfo, flashblocks_per_block: u64, ) { ctx.metrics.block_built_success.increment(1); - ctx.metrics.flashblock_count.record(ctx.flashblock_index() as f64); + ctx.metrics.flashblock_count.record(fb_state.flashblock_index() as f64); ctx.metrics .missing_flashblocks_count - .record(flashblocks_per_block.saturating_sub(ctx.flashblock_index()) as f64); + .record(flashblocks_per_block.saturating_sub(fb_state.flashblock_index()) as f64); ctx.metrics.payload_num_tx.record(info.executed_transactions.len() as f64); ctx.metrics.payload_num_tx_gauge.set(info.executed_transactions.len() as f64); @@ -855,7 +889,7 @@ where event = "build_complete", id = %ctx.payload_id(), flashblocks_per_block = flashblocks_per_block, - flashblock_index = ctx.flashblock_index(), + flashblock_index = fb_state.flashblock_index(), "Flashblocks building complete" ); } @@ -867,8 +901,7 @@ impl PayloadBuilder where Pool: PoolBounds, Client: ClientBounds, - BuilderTx: - BuilderTransactions + Clone + Send + Sync, + BuilderTx: BuilderTransactions + Clone + Send + Sync, Tasks: TaskSpawner + Clone + Unpin + 'static, { type Attributes = OpPayloadBuilderAttributes; @@ -883,13 +916,12 @@ where } } -fn execute_pre_steps( +fn execute_pre_steps( state: &mut State, - ctx: &OpPayloadBuilderCtx, -) -> Result, PayloadBuilderError> + ctx: &OpPayloadBuilderCtx, +) -> Result where DB: Database + std::fmt::Debug, - ExtraCtx: std::fmt::Debug + Default, { // 1. apply pre-execution changes ctx.evm_config @@ -903,16 +935,16 @@ where Ok(info) } -pub(super) fn build_block( +pub(super) fn build_block( state: &mut State, - ctx: &OpPayloadBuilderCtx, - info: &mut ExecutionInfo, + ctx: &OpPayloadBuilderCtx, + info: &mut ExecutionInfo, + fb_state: Option<&mut FlashblocksState>, calculate_state_root: bool, ) -> Result<(OpBuiltPayload, OpFlashblockPayload, BundleState, Vec), PayloadBuilderError> where DB: Database + AsRef

, P: StateRootProvider + HashedPostStateProvider + StorageRootProvider, - ExtraCtx: std::fmt::Debug + Default, { // We use it to preserve state, so we run merge_transitions on transition state at most once let untouched_transition_state = state.transition_state.clone(); @@ -1072,7 +1104,8 @@ where let block_hash = sealed_block.hash(); // pick the new transactions from the info field and update the last flashblock index - let new_transactions = info.executed_transactions[info.extra.last_flashblock_index..].to_vec(); + let last_idx = fb_state.as_ref().map_or(0, |s| s.last_flashblock_tx_index); + let new_transactions = info.executed_transactions[last_idx..].to_vec(); let new_transactions_encoded = new_transactions.iter().map(|tx| tx.encoded_2718().into()).collect::>(); @@ -1080,8 +1113,10 @@ where // For X Layer, monitoring logs let new_tx_hashes = new_transactions.iter().map(|tx| tx.tx_hash()).collect::>(); - let new_receipts = info.receipts[info.extra.last_flashblock_index..].to_vec(); - info.extra.last_flashblock_index = info.executed_transactions.len(); + let new_receipts = info.receipts[last_idx..].to_vec(); + if let Some(fb) = fb_state { + fb.set_last_flashblock_tx_index(info.executed_transactions.len()); + } let receipts_with_hash = new_transactions .iter() .zip(new_receipts.iter()) diff --git a/crates/builder/src/payload/flashblocks/service.rs b/crates/builder/src/payload/flashblocks/service.rs index ef3494b0..6d434323 100644 --- a/crates/builder/src/payload/flashblocks/service.rs +++ b/crates/builder/src/payload/flashblocks/service.rs @@ -3,7 +3,7 @@ use super::{ cache::FlashblockPayloadsCache, handler::PayloadHandler, p2p::{Message, AGENT_VERSION, FLASHBLOCKS_STREAM_PROTOCOL}, - payload::{FlashblocksExecutionInfo, FlashblocksExtraCtx, OpPayloadBuilder}, + payload::OpPayloadBuilder, wspub::WebSocketPublisher, FlashblocksConfig, }; @@ -36,12 +36,7 @@ impl FlashblocksServiceBuilder { where Node: NodeBounds, Pool: PoolBounds, - BuilderTx: BuilderTransactions - + Unpin - + Clone - + Send - + Sync - + 'static, + BuilderTx: BuilderTransactions + Unpin + Clone + Send + Sync + 'static, { // TODO: is there a different global token? // this is effectively unused right now due to the usage of reth's `task_executor`. @@ -147,7 +142,7 @@ impl FlashblocksServiceBuilder { let (payload_service, payload_builder_handle) = PayloadBuilderService::new(payload_generator, ctx.provider().canonical_state_stream()); - let syncer_ctx = super::ctx::OpPayloadSyncerCtx::new( + let handler_ctx = super::context::FlashblockHandlerContext::new( &ctx.provider().clone(), self.0.clone(), OpEvmConfig::optimism(ctx.chain_spec()), @@ -156,6 +151,7 @@ impl FlashblocksServiceBuilder { .wrap_err("failed to create flashblocks payload builder context")?; let payload_handler = PayloadHandler::new( + handler_ctx, built_fb_payload_rx, built_payload_rx, incoming_message_rx, @@ -163,7 +159,6 @@ impl FlashblocksServiceBuilder { payload_service.payload_events_handle(), p2p_cache.clone(), ws_pub.clone(), - syncer_ctx, ctx.provider().clone(), ctx.task_executor().clone(), cancel, diff --git a/crates/builder/src/payload/flashblocks/wspub.rs b/crates/builder/src/payload/flashblocks/wspub.rs index 573facdd..d3f29e1d 100644 --- a/crates/builder/src/payload/flashblocks/wspub.rs +++ b/crates/builder/src/payload/flashblocks/wspub.rs @@ -72,7 +72,7 @@ impl WebSocketPublisher { info!( target: "payload_builder", event = "flashblock_sent", - message = "Sending flashblock to rollup-boost", + message = "Sending flashblock to subscribers", id = %payload.payload_id, index = payload.index, base = payload.base.is_some(), diff --git a/crates/builder/src/payload/mod.rs b/crates/builder/src/payload/mod.rs index 50aa0a1a..4de61d15 100644 --- a/crates/builder/src/payload/mod.rs +++ b/crates/builder/src/payload/mod.rs @@ -4,7 +4,7 @@ use reth_optimism_evm::OpEvmConfig; use reth_optimism_payload_builder::config::{OpDAConfig, OpGasLimitConfig}; use crate::{ - args::OpRbuilderArgs, + args::BuilderArgs, traits::{NodeBounds, PoolBounds}, tx::signer::Signer, }; @@ -30,7 +30,7 @@ pub use flashblocks::{FlashblocksBuilder, FlashblocksServiceBuilder, WebSocketPu pub trait PayloadBuilder: Send + Sync + 'static { /// The type that has an implementation specific variant of the Config struct. /// This is used to configure the payload builder service during startup. - type Config: TryFrom + Clone + Debug + Send + Sync + 'static; + type Config: TryFrom + Clone + Debug + Send + Sync + 'static; /// The type that is used to instantiate the payload builder service /// that will be used by reth to build blocks whenever the node is @@ -128,13 +128,13 @@ impl Default for BuilderConfig { } } -impl TryFrom for BuilderConfig +impl TryFrom for BuilderConfig where - S: TryFrom + Clone, + S: TryFrom + Clone, { type Error = S::Error; - fn try_from(args: OpRbuilderArgs) -> Result { + fn try_from(args: BuilderArgs) -> Result { Ok(Self { builder_signer: args.builder_signer, block_time: Duration::from_millis(args.chain_block_time), diff --git a/crates/builder/src/payload/utils/execution.rs b/crates/builder/src/payload/utils/execution.rs index 9b656260..77cdd0b7 100644 --- a/crates/builder/src/payload/utils/execution.rs +++ b/crates/builder/src/payload/utils/execution.rs @@ -1,6 +1,5 @@ //! Heavily influenced by [reth](https://github.com/paradigmxyz/reth/blob/1e965caf5fa176f244a31c0d2662ba1b590938db/crates/optimism/payload/src/builder.rs#L570) use alloy_primitives::{Address, U256}; -use core::fmt::Debug; use derive_more::Display; use op_revm::OpTransactionError; use reth_optimism_primitives::{OpReceipt, OpTransactionSigned}; @@ -25,7 +24,7 @@ pub enum TxnExecutionResult { } #[derive(Default, Debug)] -pub struct ExecutionInfo { +pub struct ExecutionInfo { /// All executed transactions (unrecovered). pub executed_transactions: Vec, /// The recovered senders for the executed transactions. @@ -38,15 +37,13 @@ pub struct ExecutionInfo { pub cumulative_da_bytes_used: u64, /// Tracks fees from executed mempool transactions pub total_fees: U256, - /// Extra execution information that can be attached by individual builders. - pub extra: Extra, /// DA Footprint Scalar for Jovian pub da_footprint_scalar: Option, /// Optional blob fields for payload validation pub optional_blob_fields: Option<(Option, Option)>, } -impl ExecutionInfo { +impl ExecutionInfo { /// Create a new instance with allocated slots. pub fn with_capacity(capacity: usize) -> Self { Self { @@ -56,7 +53,6 @@ impl ExecutionInfo { cumulative_gas_used: 0, cumulative_da_bytes_used: 0, total_fees: U256::ZERO, - extra: Default::default(), da_footprint_scalar: None, optional_blob_fields: None, } diff --git a/crates/builder/src/tests/data_availability.rs b/crates/builder/src/tests/data_availability.rs index 64632076..cd696117 100644 --- a/crates/builder/src/tests/data_availability.rs +++ b/crates/builder/src/tests/data_availability.rs @@ -1,5 +1,5 @@ use crate::{ - args::{FlashblocksArgs, OpRbuilderArgs}, + args::{BuilderArgs, FlashblocksArgs}, tests::{BlockTransactionsExt, ChainDriverExt, LocalInstance, TransactionBuilderExt}, }; use alloy_provider::Provider; @@ -92,7 +92,7 @@ async fn block_fill(rbuilder: LocalInstance) -> eyre::Result<()> { /// to the DA footprint limit. The DA footprint is calculated as: /// total_da_bytes_used * da_footprint_gas_scalar (stored in blob_gas_used). /// This must not exceed the block gas limit, accounting for the builder transaction. -#[rb_test(args = OpRbuilderArgs { +#[rb_test(args = BuilderArgs { flashblocks: FlashblocksArgs { enabled: true, flashblocks_port: 0, diff --git a/crates/builder/src/tests/flashblocks.rs b/crates/builder/src/tests/flashblocks.rs index 0d5c1d7f..3f8600b0 100644 --- a/crates/builder/src/tests/flashblocks.rs +++ b/crates/builder/src/tests/flashblocks.rs @@ -7,14 +7,14 @@ use op_alloy_consensus::OpTxEnvelope; use std::time::Duration; use crate::{ - args::{FlashblocksArgs, OpRbuilderArgs}, + args::{BuilderArgs, FlashblocksArgs}, tests::{ count_txs_to, flashblocks_number_contract::FlashblocksNumber, BlockTransactionsExt, ChainDriver, LocalInstance, TransactionBuilderExt, FLASHBLOCKS_NUMBER_ADDRESS, }, }; -#[rb_test(args = OpRbuilderArgs { +#[rb_test(args = BuilderArgs { chain_block_time: 1000, flashblocks: FlashblocksArgs { enabled: true, @@ -50,7 +50,7 @@ async fn test_flashblocks_no_state_root_calculation(rbuilder: LocalInstance) -> Ok(()) } -#[rb_test(args = OpRbuilderArgs { +#[rb_test(args = BuilderArgs { chain_block_time: 1000, flashblocks: FlashblocksArgs { flashblocks_number_contract_address: Some(FLASHBLOCKS_NUMBER_ADDRESS), @@ -180,7 +180,7 @@ async fn create_flashblock_transactions( } /// Smoke test for flashblocks with end buffer. -#[rb_test(args = OpRbuilderArgs { +#[rb_test(args = BuilderArgs { chain_block_time: 1000, flashblocks: FlashblocksArgs { enabled: true, @@ -213,7 +213,7 @@ async fn smoke_basic(rbuilder: LocalInstance) -> eyre::Result<()> { } /// Smoke test with send_offset_ms -#[rb_test(args = OpRbuilderArgs { +#[rb_test(args = BuilderArgs { chain_block_time: 1000, flashblocks: FlashblocksArgs { enabled: true, @@ -248,7 +248,7 @@ async fn smoke_with_offset(rbuilder: LocalInstance) -> eyre::Result<()> { /// Test significant FCU delay (700ms into 1000ms block) /// Should produce fewer flashblocks due to less remaining time -#[rb_test(args = OpRbuilderArgs { +#[rb_test(args = BuilderArgs { chain_block_time: 1000, flashblocks: FlashblocksArgs { enabled: true, @@ -291,7 +291,7 @@ async fn late_fcu_reduces_flashblocks(rbuilder: LocalInstance) -> eyre::Result<( /// With 1000ms block time, 200ms flashblock interval, and 50ms end buffer: /// - Available time = 1000 - lag - 50 = 950 - lag /// - Flashblocks per block = ceil((available_time) / 200) + 1 (base flashblock) -#[rb_test(args = OpRbuilderArgs { +#[rb_test(args = BuilderArgs { chain_block_time: 1000, flashblocks: FlashblocksArgs { enabled: true, diff --git a/crates/builder/src/tests/forks.rs b/crates/builder/src/tests/forks.rs index 93f11833..59d70651 100644 --- a/crates/builder/src/tests/forks.rs +++ b/crates/builder/src/tests/forks.rs @@ -1,5 +1,5 @@ use crate::{ - args::{FlashblocksArgs, OpRbuilderArgs}, + args::{BuilderArgs, FlashblocksArgs}, tests::{BlockTransactionsExt, LocalInstance}, }; use alloy_eips::{eip1559::MIN_PROTOCOL_BASE_FEE, BlockNumberOrTag::Latest, Encodable2718}; @@ -7,7 +7,7 @@ use alloy_primitives::bytes; use macros::rb_test; use std::time::Duration; -#[rb_test(args = OpRbuilderArgs { +#[rb_test(args = BuilderArgs { flashblocks: FlashblocksArgs { enabled: true, flashblocks_port: 0, diff --git a/crates/builder/src/tests/framework/driver.rs b/crates/builder/src/tests/framework/driver.rs index a4927f2e..432986cd 100644 --- a/crates/builder/src/tests/framework/driver.rs +++ b/crates/builder/src/tests/framework/driver.rs @@ -12,7 +12,7 @@ use reth_optimism_node::OpPayloadAttributes; use super::{EngineApi, Ipc, LocalInstance, TransactionBuilder}; use crate::{ - args::OpRbuilderArgs, + args::BuilderArgs, tests::{ExternalNode, Protocol, DEFAULT_DENOMINATOR, DEFAULT_ELASTICITY, DEFAULT_GAS_LIMIT}, tx::signer::Signer, }; @@ -25,7 +25,7 @@ pub struct ChainDriver { provider: RootProvider, signer: Option, gas_limit: Option, - args: OpRbuilderArgs, + args: BuilderArgs, validation_nodes: Vec, } @@ -56,7 +56,7 @@ impl ChainDriver { provider, signer: Default::default(), gas_limit: None, - args: OpRbuilderArgs::default(), + args: BuilderArgs::default(), validation_nodes: vec![], } } diff --git a/crates/builder/src/tests/framework/engine_api_builder.rs b/crates/builder/src/tests/framework/engine_api_builder.rs index 06dc7d3c..3e6bebde 100644 --- a/crates/builder/src/tests/framework/engine_api_builder.rs +++ b/crates/builder/src/tests/framework/engine_api_builder.rs @@ -97,7 +97,7 @@ where } #[async_trait::async_trait] -impl OpRbuilderEngineApiServer +impl FlashblockBuilderEngineApiServer for OpEngineApiExt where Provider: HeaderProvider + BlockReader + StateProviderFactory + 'static, @@ -207,7 +207,7 @@ where impl IntoEngineApiRpcModule for OpEngineApiExt where - Self: OpRbuilderEngineApiServer, + Self: FlashblockBuilderEngineApiServer, { fn into_rpc_module(self) -> RpcModule<()> { self.into_rpc().remove_context() @@ -222,7 +222,7 @@ where /// This follows the Optimism specs that can be found at: /// #[rpc(server, namespace = "engine", server_bounds(Engine::PayloadAttributes: jsonrpsee::core::DeserializeOwned))] -pub trait OpRbuilderEngineApi { +pub trait FlashblockBuilderEngineApi { /// Sends the given payload to the execution layer client, as specified for the Shanghai fork. /// /// See also diff --git a/crates/builder/src/tests/framework/external.rs b/crates/builder/src/tests/framework/external.rs index 2dc24517..4f67ed25 100644 --- a/crates/builder/src/tests/framework/external.rs +++ b/crates/builder/src/tests/framework/external.rs @@ -29,7 +29,7 @@ const RPC_CONTAINER_IPC_PATH: &str = "/home/op-reth-shared/rpc.ipc"; /// This type represents an Optimism execution client node that is running inside a /// docker container. This node is used to validate the correctness of the blocks built -/// by op-rbuilder. +/// by the flashblock-builder. /// /// When this node is attached to a `ChainDriver`, it will automatically catch up with the /// provided chain and will transparently ingest all newly built blocks by the driver. diff --git a/crates/builder/src/tests/framework/instance.rs b/crates/builder/src/tests/framework/instance.rs index d62b4b46..b5be46fd 100644 --- a/crates/builder/src/tests/framework/instance.rs +++ b/crates/builder/src/tests/framework/instance.rs @@ -1,5 +1,5 @@ use crate::{ - args::OpRbuilderArgs, + args::BuilderArgs, payload::{BuilderConfig, FlashblocksBuilder, PayloadBuilder}, tests::{ builder_signer, create_test_db, @@ -34,6 +34,7 @@ use reth_node_builder::{NodeBuilder, NodeConfig}; use reth_optimism_chainspec::OpChainSpec; use reth_optimism_cli::commands::Commands; use reth_optimism_node::{ + args::RollupArgs, node::{OpAddOns, OpAddOnsBuilder, OpEngineValidatorBuilder, OpPoolBuilder}, OpNode, }; @@ -53,7 +54,7 @@ use tokio_util::sync::CancellationToken; pub struct LocalInstance { signer: Signer, config: NodeConfig, - args: OpRbuilderArgs, + args: BuilderArgs, task_manager: Option, exit_future: NodeExitFuture, _node_handle: Box, @@ -66,7 +67,7 @@ impl LocalInstance { /// /// This method does not prefund any accounts, so before sending any transactions /// make sure that sender accounts are funded. - pub async fn new(args: OpRbuilderArgs) -> eyre::Result { + pub async fn new(args: BuilderArgs) -> eyre::Result { Box::pin(Self::new_with_config::

(args, default_node_config())).await } @@ -76,12 +77,16 @@ impl LocalInstance { /// This method does not prefund any accounts, so before sending any transactions /// make sure that sender accounts are funded. pub async fn new_with_config( - args: OpRbuilderArgs, + args: BuilderArgs, config: NodeConfig, ) -> eyre::Result { let mut args = args; let task_manager = task_manager(); - let op_node = OpNode::new(args.rollup_args.clone()); + + // Create RollupArgs separately via CLI parse trick (same pattern as BuilderArgs) + let rollup_args = RollupArgs { enable_tx_conditional: true, ..Default::default() }; + + let op_node = OpNode::new(rollup_args.clone()); let reverted_cache = Cache::builder().max_capacity(100).build(); let reverted_cache_clone = reverted_cache.clone(); @@ -91,10 +96,9 @@ impl LocalInstance { let signer = args.builder_signer.unwrap_or(builder_signer()); args.builder_signer = Some(signer); - args.rollup_args.enable_tx_conditional = true; let builder_config = BuilderConfig::::try_from(args.clone()) - .expect("Failed to convert rollup args to builder config"); + .expect("Failed to convert builder args to builder config"); let da_config = builder_config.da_config.clone(); let gas_limit_config = builder_config.gas_limit_config.clone(); @@ -104,8 +108,8 @@ impl LocalInstance { OpEngineValidatorBuilder, OpEngineApiBuilder, > = OpAddOnsBuilder::default() - .with_sequencer(args.rollup_args.sequencer.clone()) - .with_enable_tx_conditional(args.rollup_args.enable_tx_conditional) + .with_sequencer(rollup_args.sequencer.clone()) + .with_enable_tx_conditional(rollup_args.enable_tx_conditional) .with_da_config(da_config) .with_gas_limit_config(gas_limit_config) .build(); @@ -117,7 +121,7 @@ impl LocalInstance { .with_components( op_node .components() - .pool(pool_component(&args)) + .pool(pool_component(&rollup_args)) .payload(P::new_service(builder_config)?), ) .with_add_ons(addons) @@ -167,7 +171,7 @@ impl LocalInstance { &self.config } - pub const fn args(&self) -> &OpRbuilderArgs { + pub const fn args(&self) -> &BuilderArgs { &self.args } @@ -291,8 +295,7 @@ fn task_manager() -> TaskManager { TaskManager::new(tokio::runtime::Handle::current()) } -fn pool_component(args: &OpRbuilderArgs) -> OpPoolBuilder { - let rollup_args = &args.rollup_args; +fn pool_component(rollup_args: &RollupArgs) -> OpPoolBuilder { OpPoolBuilder::default() .with_enable_tx_conditional(rollup_args.enable_tx_conditional) .with_supervisor(rollup_args.supervisor_http.clone(), rollup_args.supervisor_safety_level) diff --git a/crates/builder/src/tests/framework/macros/Cargo.toml b/crates/builder/src/tests/framework/macros/Cargo.toml index 04543e84..54039407 100644 --- a/crates/builder/src/tests/framework/macros/Cargo.toml +++ b/crates/builder/src/tests/framework/macros/Cargo.toml @@ -2,7 +2,7 @@ name = "macros" version = "0.1.0" edition = "2024" -description = "Macros supporting the tests infrastructure for op-rbuilder" +description = "Macros supporting the tests infrastructure for flashblock-builder" [lib] proc-macro = true diff --git a/crates/builder/src/tests/framework/macros/src/lib.rs b/crates/builder/src/tests/framework/macros/src/lib.rs index 9307d73a..c9d8a129 100644 --- a/crates/builder/src/tests/framework/macros/src/lib.rs +++ b/crates/builder/src/tests/framework/macros/src/lib.rs @@ -88,7 +88,7 @@ fn generate_instance_init( (None, Some(config_expr)) => { quote! { crate::tests::LocalInstance::new_with_config::({ - let mut args = crate::args::OpRbuilderArgs::default(); + let mut args = crate::args::BuilderArgs::default(); args.flashblocks.enabled = true; args.flashblocks.flashblocks_port = crate::tests::get_available_port(); args.flashblocks.flashblocks_end_buffer_ms = 75; diff --git a/crates/builder/src/tests/miner_gas_limit.rs b/crates/builder/src/tests/miner_gas_limit.rs index b81b7285..1e372029 100644 --- a/crates/builder/src/tests/miner_gas_limit.rs +++ b/crates/builder/src/tests/miner_gas_limit.rs @@ -1,5 +1,5 @@ use crate::{ - args::{FlashblocksArgs, OpRbuilderArgs}, + args::{BuilderArgs, FlashblocksArgs}, tests::{BlockTransactionsExt, LocalInstance}, }; use alloy_provider::Provider; @@ -29,7 +29,7 @@ async fn miner_gas_limit(rbuilder: LocalInstance) -> eyre::Result<()> { /// There is a deposit transaction for 182,706 gas, and builder transactions are 21,600 gas /// /// (785,000 - 182,706 - 21,600 - 21,600) / 53,000 = 10.54 = 10 transactions can fit -#[rb_test(args = OpRbuilderArgs { +#[rb_test(args = BuilderArgs { flashblocks: FlashblocksArgs { enabled: true, flashblocks_port: 0, diff --git a/crates/builder/src/tests/smoke.rs b/crates/builder/src/tests/smoke.rs index c724c28b..c76d1af8 100644 --- a/crates/builder/src/tests/smoke.rs +++ b/crates/builder/src/tests/smoke.rs @@ -1,5 +1,5 @@ use crate::{ - args::{FlashblocksArgs, OpRbuilderArgs}, + args::{BuilderArgs, FlashblocksArgs}, tests::{BuilderTxValidation, LocalInstance, TransactionBuilderExt}, }; use alloy_primitives::TxHash; @@ -18,7 +18,7 @@ use tracing::info; /// /// Generated blocks are also validated against an external op-reth node to /// ensure their correctness. -#[rb_test(args = OpRbuilderArgs { +#[rb_test(args = BuilderArgs { flashblocks: FlashblocksArgs { enabled: true, flashblocks_port: 0, @@ -169,7 +169,7 @@ async fn test_no_tx_pool(rbuilder: LocalInstance) -> eyre::Result<()> { Ok(()) } -#[rb_test(args = OpRbuilderArgs { +#[rb_test(args = BuilderArgs { max_gas_per_txn: Some(25000), ..Default::default() })] @@ -216,7 +216,7 @@ async fn chain_produces_big_tx_with_gas_limit(rbuilder: LocalInstance) -> eyre:: Ok(()) } -#[rb_test(args = OpRbuilderArgs { +#[rb_test(args = BuilderArgs { ..Default::default() })] async fn chain_produces_big_tx_without_gas_limit(rbuilder: LocalInstance) -> eyre::Result<()> { @@ -252,7 +252,7 @@ async fn chain_produces_big_tx_without_gas_limit(rbuilder: LocalInstance) -> eyr /// Validates that each block contains builder transactions using the /// BuilderTxValidation utility. -#[rb_test(args = OpRbuilderArgs { +#[rb_test(args = BuilderArgs { flashblocks: FlashblocksArgs { enabled: true, flashblocks_port: 0, diff --git a/crates/builder/src/tests/utils/extensions.rs b/crates/builder/src/tests/utils/extensions.rs index 5c32e27b..00096e00 100644 --- a/crates/builder/src/tests/utils/extensions.rs +++ b/crates/builder/src/tests/utils/extensions.rs @@ -156,11 +156,11 @@ impl ChainDriverExt for ChainDriver

{ } } -pub trait OpRbuilderArgsTestExt { +pub trait BuilderArgsTestExt { fn test_default() -> Self; } -impl OpRbuilderArgsTestExt for crate::args::OpRbuilderArgs { +impl BuilderArgsTestExt for crate::args::BuilderArgs { fn test_default() -> Self { let mut default = Self::default(); default.flashblocks.flashblocks_port = 0; // randomize port diff --git a/crates/flashblocks/src/handler.rs b/crates/flashblocks/src/handler.rs index 91e70194..c8bd75b1 100644 --- a/crates/flashblocks/src/handler.rs +++ b/crates/flashblocks/src/handler.rs @@ -4,7 +4,7 @@ use std::net::SocketAddr; use std::sync::Arc; use tracing::{debug, info, trace, warn}; use xlayer_builder::{ - args::OpRbuilderArgs, metrics::tokio::FlashblocksTaskMetrics, metrics::BuilderMetrics, + args::FlashblocksArgs, metrics::tokio::FlashblocksTaskMetrics, metrics::BuilderMetrics, payload::WebSocketPublisher, }; @@ -15,7 +15,7 @@ where node: Node, flashblock_rx: FlashBlockRx, ws_pub: Arc, - op_args: OpRbuilderArgs, + relay_flashblocks: bool, } impl FlashblocksService @@ -25,12 +25,10 @@ where pub fn new( node: Node, flashblock_rx: FlashBlockRx, - op_args: OpRbuilderArgs, + args: FlashblocksArgs, + relay_flashblocks: bool, ) -> Result { - let ws_addr = SocketAddr::new( - op_args.flashblocks.flashblocks_addr.parse()?, - op_args.flashblocks.flashblocks_port, - ); + let ws_addr = SocketAddr::new(args.flashblocks_addr.parse()?, args.flashblocks_port); let metrics = Arc::new(BuilderMetrics::default()); let task_metrics = Arc::new(FlashblocksTaskMetrics::new()); @@ -39,21 +37,21 @@ where ws_addr, metrics, &task_metrics.websocket_publisher, - op_args.flashblocks.ws_subscriber_limit, + args.ws_subscriber_limit, ) .map_err(|e| eyre::eyre!("Failed to create WebSocket publisher: {e}"))?, ); info!(target: "flashblocks", "WebSocket publisher initialized at {}", ws_addr); - Ok(Self { node, flashblock_rx, ws_pub, op_args }) + Ok(Self { node, flashblock_rx, ws_pub, relay_flashblocks }) } pub fn spawn(mut self) { debug!(target: "flashblocks", "Initializing flashblocks service"); let task_executor = self.node.task_executor().clone(); - if self.op_args.rollup_args.flashblocks_url.is_some() { + if self.relay_flashblocks { task_executor.spawn_critical( "xlayer-flashblocks-service", Box::pin(async move { diff --git a/crates/tests/operations/manager.rs b/crates/tests/operations/manager.rs index 81039523..ade45245 100644 --- a/crates/tests/operations/manager.rs +++ b/crates/tests/operations/manager.rs @@ -15,8 +15,6 @@ pub const DEFAULT_L2_CHAIN_ID: u64 = 195; pub const DEFAULT_L2_SEQ_URL: &str = "http://localhost:8123"; /// Default L2 RPC node URL for testing pub const DEFAULT_L2_NETWORK_URL: &str = "http://localhost:8124"; -/// Default L2 op-rbuilder URL for testing -pub const DEFAULT_L2_BUILDER_URL: &str = "http://localhost:8125"; // Default L2 RPC node with flashblocks enabled pub const DEFAULT_L2_NETWORK_URL_FB: &str = "http://localhost:8124"; // Default L2 RPC node with flashblocks disabled