From afb3e2907086515fdc59c90ee3da18a8fc4d726e Mon Sep 17 00:00:00 2001 From: Cody Wang Date: Tue, 30 Sep 2025 13:06:42 -0400 Subject: [PATCH 1/2] add max flashblocks --- crates/op-rbuilder/src/args/op.rs | 11 ++ .../src/builders/flashblocks/config.rs | 10 ++ .../src/builders/flashblocks/payload.rs | 100 ++++++++--------- crates/op-rbuilder/src/tests/flashblocks.rs | 101 ++++++++++++++++++ 4 files changed, 174 insertions(+), 48 deletions(-) diff --git a/crates/op-rbuilder/src/args/op.rs b/crates/op-rbuilder/src/args/op.rs index bd860f155..75e208cc5 100644 --- a/crates/op-rbuilder/src/args/op.rs +++ b/crates/op-rbuilder/src/args/op.rs @@ -166,6 +166,17 @@ pub struct FlashblocksArgs { env = "FLASHBLOCK_NUMBER_CONTRACT_ADDRESS" )] pub flashblocks_number_contract_address: Option
, + + /// Maximum number of flashblocks per block + /// + /// This caps the maximum number of flashblocks that can be produced per block, + /// regardless of the calculated number based on timing. + #[arg( + long = "flashblocks.max-per-block", + env = "FLASHBLOCKS_MAX_PER_BLOCK", + default_value = "10" + )] + pub flashblocks_max_per_block: u64, } impl Default for FlashblocksArgs { diff --git a/crates/op-rbuilder/src/builders/flashblocks/config.rs b/crates/op-rbuilder/src/builders/flashblocks/config.rs index f2dca7759..b3f491175 100644 --- a/crates/op-rbuilder/src/builders/flashblocks/config.rs +++ b/crates/op-rbuilder/src/builders/flashblocks/config.rs @@ -38,6 +38,12 @@ pub struct FlashblocksConfig { /// /// If set a builder tx will be added to the start of every flashblock instead of the regular builder tx. pub flashblocks_number_contract_address: Option
, + + /// Maximum number of flashblocks per block. + /// + /// This caps the maximum number of flashblocks that can be produced per block, + /// regardless of the calculated number based on timing. + pub max_flashblocks_per_block: u64, } impl Default for FlashblocksConfig { @@ -49,6 +55,7 @@ impl Default for FlashblocksConfig { fixed: false, calculate_state_root: true, flashblocks_number_contract_address: None, + max_flashblocks_per_block: 10, } } } @@ -73,6 +80,8 @@ impl TryFrom for FlashblocksConfig { let flashblocks_number_contract_address = args.flashblocks.flashblocks_number_contract_address; + let max_flashblocks_per_block = args.flashblocks.flashblocks_max_per_block; + Ok(Self { ws_addr, interval, @@ -80,6 +89,7 @@ impl TryFrom for FlashblocksConfig { fixed, calculate_state_root, flashblocks_number_contract_address, + max_flashblocks_per_block, }) } } diff --git a/crates/op-rbuilder/src/builders/flashblocks/payload.rs b/crates/op-rbuilder/src/builders/flashblocks/payload.rs index ae11a6da6..68caec463 100644 --- a/crates/op-rbuilder/src/builders/flashblocks/payload.rs +++ b/crates/op-rbuilder/src/builders/flashblocks/payload.rs @@ -807,62 +807,66 @@ where /// Calculate number of flashblocks. /// If dynamic is enabled this function will take time drift into the account. pub(super) fn calculate_flashblocks(&self, timestamp: u64) -> (u64, Duration) { - if self.config.specific.fixed { - return ( + let (calculated_flashblocks, first_offset) = if self.config.specific.fixed { + ( self.config.flashblocks_per_block(), // We adjust first FB to ensure that we have at least some time to make all FB in time self.config.specific.interval - self.config.specific.leeway_time, + ) + } else { + // We use this system time to determine remining time to build a block + // Things to consider: + // FCU(a) - FCU with attributes + // FCU(a) could arrive with `block_time - fb_time < delay`. In this case we could only produce 1 flashblock + // FCU(a) could arrive with `delay < fb_time` - in this case we will shrink first flashblock + // FCU(a) could arrive with `fb_time < delay < block_time - fb_time` - in this case we will issue less flashblocks + let target_time = std::time::SystemTime::UNIX_EPOCH + Duration::from_secs(timestamp) + - self.config.specific.leeway_time; + let now = std::time::SystemTime::now(); + let Ok(time_drift) = target_time.duration_since(now) else { + error!( + target: "payload_builder", + message = "FCU arrived too late or system clock are unsynced", + ?target_time, + ?now, + ); + let fallback_flashblocks = self.config.flashblocks_per_block().min(self.config.specific.max_flashblocks_per_block); + return (fallback_flashblocks, self.config.specific.interval); + }; + self.metrics.flashblocks_time_drift.record( + self.config + .block_time + .as_millis() + .saturating_sub(time_drift.as_millis()) as f64, ); - } - // We use this system time to determine remining time to build a block - // Things to consider: - // FCU(a) - FCU with attributes - // FCU(a) could arrive with `block_time - fb_time < delay`. In this case we could only produce 1 flashblock - // FCU(a) could arrive with `delay < fb_time` - in this case we will shrink first flashblock - // FCU(a) could arrive with `fb_time < delay < block_time - fb_time` - in this case we will issue less flashblocks - let target_time = std::time::SystemTime::UNIX_EPOCH + Duration::from_secs(timestamp) - - self.config.specific.leeway_time; - let now = std::time::SystemTime::now(); - let Ok(time_drift) = target_time.duration_since(now) else { - error!( + debug!( target: "payload_builder", - message = "FCU arrived too late or system clock are unsynced", + message = "Time drift for building round", ?target_time, - ?now, - ); - return ( - self.config.flashblocks_per_block(), - self.config.specific.interval, + time_drift = self.config.block_time.as_millis().saturating_sub(time_drift.as_millis()), + ?timestamp ); + // This is extra check to ensure that we would account at least for block time in case we have any timer discrepancies. + let time_drift = time_drift.min(self.config.block_time); + let interval = self.config.specific.interval.as_millis() as u64; + let time_drift = time_drift.as_millis() as u64; + let first_flashblock_offset = time_drift.rem(interval); + if first_flashblock_offset == 0 { + // We have perfect division, so we use interval as first fb offset + (time_drift.div(interval), Duration::from_millis(interval)) + } else { + // Non-perfect division, so we account for it. + ( + time_drift.div(interval) + 1, + Duration::from_millis(first_flashblock_offset), + ) + } }; - self.metrics.flashblocks_time_drift.record( - self.config - .block_time - .as_millis() - .saturating_sub(time_drift.as_millis()) as f64, - ); - debug!( - target: "payload_builder", - message = "Time drift for building round", - ?target_time, - time_drift = self.config.block_time.as_millis().saturating_sub(time_drift.as_millis()), - ?timestamp - ); - // This is extra check to ensure that we would account at least for block time in case we have any timer discrepancies. - let time_drift = time_drift.min(self.config.block_time); - let interval = self.config.specific.interval.as_millis() as u64; - let time_drift = time_drift.as_millis() as u64; - let first_flashblock_offset = time_drift.rem(interval); - if first_flashblock_offset == 0 { - // We have perfect division, so we use interval as first fb offset - (time_drift.div(interval), Duration::from_millis(interval)) - } else { - // Non-perfect division, so we account for it. - ( - time_drift.div(interval) + 1, - Duration::from_millis(first_flashblock_offset), - ) - } + + // Apply the maximum flashblocks per block cap + let final_flashblocks = calculated_flashblocks.min(self.config.specific.max_flashblocks_per_block); + + (final_flashblocks, first_offset) } } diff --git a/crates/op-rbuilder/src/tests/flashblocks.rs b/crates/op-rbuilder/src/tests/flashblocks.rs index 8204af75f..a49917be0 100644 --- a/crates/op-rbuilder/src/tests/flashblocks.rs +++ b/crates/op-rbuilder/src/tests/flashblocks.rs @@ -18,6 +18,7 @@ use crate::{ flashblocks_fixed: false, flashblocks_calculate_state_root: true, flashblocks_number_contract_address: None, + flashblocks_max_per_block: 10, }, ..Default::default() })] @@ -57,6 +58,7 @@ async fn smoke_dynamic_base(rbuilder: LocalInstance) -> eyre::Result<()> { flashblocks_fixed: false, flashblocks_calculate_state_root: true, flashblocks_number_contract_address: None, + flashblocks_max_per_block: 10, }, ..Default::default() })] @@ -96,6 +98,7 @@ async fn smoke_dynamic_unichain(rbuilder: LocalInstance) -> eyre::Result<()> { flashblocks_fixed: true, flashblocks_calculate_state_root: true, flashblocks_number_contract_address: None, + flashblocks_max_per_block: 10, }, ..Default::default() })] @@ -135,6 +138,7 @@ async fn smoke_classic_unichain(rbuilder: LocalInstance) -> eyre::Result<()> { flashblocks_fixed: true, flashblocks_calculate_state_root: true, flashblocks_number_contract_address: None, + flashblocks_max_per_block: 10, }, ..Default::default() })] @@ -174,6 +178,7 @@ async fn smoke_classic_base(rbuilder: LocalInstance) -> eyre::Result<()> { flashblocks_fixed: false, flashblocks_calculate_state_root: true, flashblocks_number_contract_address: None, + flashblocks_max_per_block: 10, }, ..Default::default() })] @@ -220,6 +225,7 @@ async fn unichain_dynamic_with_lag(rbuilder: LocalInstance) -> eyre::Result<()> flashblocks_fixed: false, flashblocks_calculate_state_root: true, flashblocks_number_contract_address: None, + flashblocks_max_per_block: 10, }, ..Default::default() })] @@ -259,6 +265,7 @@ async fn dynamic_with_full_block_lag(rbuilder: LocalInstance) -> eyre::Result<() flashblocks_fixed: false, flashblocks_calculate_state_root: true, flashblocks_number_contract_address: None, + flashblocks_max_per_block: 10, }, ..Default::default() })] @@ -320,6 +327,7 @@ async fn test_flashblock_min_filtering(rbuilder: LocalInstance) -> eyre::Result< flashblocks_fixed: false, flashblocks_calculate_state_root: true, flashblocks_number_contract_address: None, + flashblocks_max_per_block: 10, }, ..Default::default() })] @@ -377,6 +385,7 @@ async fn test_flashblock_max_filtering(rbuilder: LocalInstance) -> eyre::Result< flashblocks_fixed: false, flashblocks_calculate_state_root: true, flashblocks_number_contract_address: None, + flashblocks_max_per_block: 10, }, ..Default::default() })] @@ -423,6 +432,7 @@ async fn test_flashblock_min_max_filtering(rbuilder: LocalInstance) -> eyre::Res flashblocks_fixed: false, flashblocks_calculate_state_root: false, flashblocks_number_contract_address: None, + flashblocks_max_per_block: 10, }, ..Default::default() })] @@ -456,3 +466,94 @@ async fn test_flashblocks_no_state_root_calculation(rbuilder: LocalInstance) -> Ok(()) } + +#[rb_test(flashblocks, args = OpRbuilderArgs { + chain_block_time: 1000, + flashblocks: FlashblocksArgs { + enabled: true, + flashblocks_port: 1239, + flashblocks_addr: "127.0.0.1".into(), + flashblocks_block_time: 200, + flashblocks_leeway_time: 100, + flashblocks_fixed: true, + flashblocks_calculate_state_root: true, + flashblocks_number_contract_address: None, + flashblocks_max_per_block: 3, // Cap at 3 flashblocks instead of default 5 + }, + ..Default::default() +})] +async fn test_max_flashblocks_per_block_cap(rbuilder: LocalInstance) -> eyre::Result<()> { + let driver = rbuilder.driver().await?; + let flashblocks_listener = rbuilder.spawn_flashblocks_listener(); + + // Send transactions to ensure blocks have activity + for _ in 0..5 { + let _ = driver + .create_transaction() + .random_valid_transfer() + .send() + .await?; + } + + // Build a block - normally would produce 5 flashblocks (1000ms / 200ms = 5) + // But with max_flashblocks_per_block: 3, it should cap at 3 + let block = driver.build_new_block().await?; + assert_eq!(block.transactions.len(), 8, "Block should contain all transactions"); // 5 normal txn + deposit + 2 builder txn + + let flashblocks = flashblocks_listener.get_flashblocks(); + // Should produce only 3 flashblocks + 1 base flashblock = 4 total + assert_eq!(4, flashblocks.len(), "Should be capped at 3 flashblocks + 1 base = 4 total"); + + // Verify flashblock indices are within expected range + for fb in &flashblocks { + assert!(fb.index <= 3, "Flashblock index should not exceed 3, got index {}", fb.index); + } + + flashblocks_listener.stop().await +} + +#[rb_test(flashblocks, args = OpRbuilderArgs { + chain_block_time: 2000, + flashblocks: FlashblocksArgs { + enabled: true, + flashblocks_port: 1239, + flashblocks_addr: "127.0.0.1".into(), + flashblocks_block_time: 100, // Short interval would normally create 20 flashblocks + flashblocks_leeway_time: 50, + flashblocks_fixed: false, + flashblocks_calculate_state_root: true, + flashblocks_number_contract_address: None, + flashblocks_max_per_block: 5, // Cap at 5 flashblocks + }, + ..Default::default() +})] +async fn test_max_flashblocks_dynamic_timing(rbuilder: LocalInstance) -> eyre::Result<()> { + let driver = rbuilder.driver().await?; + let flashblocks_listener = rbuilder.spawn_flashblocks_listener(); + + // Send transactions + for _ in 0..3 { + let _ = driver + .create_transaction() + .random_valid_transfer() + .send() + .await?; + } + + // Build block with current timestamp (dynamic timing) + // Would normally create ~20 flashblocks (2000ms / 100ms = 20) + // But should be capped at 5 + let block = driver.build_new_block_with_current_timestamp(None).await?; + assert!(block.transactions.len() >= 5, "Block should contain transactions"); + + let flashblocks = flashblocks_listener.get_flashblocks(); + // Should be capped at 5 flashblocks + 1 base = 6 total + assert!(flashblocks.len() <= 6, "Should be capped at 5 flashblocks + 1 base = 6 total, got {}", flashblocks.len()); + + // Verify no flashblock index exceeds the cap + for fb in &flashblocks { + assert!(fb.index <= 5, "Flashblock index should not exceed 5, got index {}", fb.index); + } + + flashblocks_listener.stop().await +} From be32f4a52fbf37a56ac5d18fa9b735ad78ee4515 Mon Sep 17 00:00:00 2001 From: Cody Wang Date: Tue, 30 Sep 2025 13:35:30 -0400 Subject: [PATCH 2/2] optimize --- crates/op-rbuilder/src/args/op.rs | 2 +- .../src/builders/flashblocks/config.rs | 5 +- .../src/builders/flashblocks/payload.rs | 102 +++++++++--------- crates/op-rbuilder/src/tests/flashblocks.rs | 59 ++++++---- 4 files changed, 97 insertions(+), 71 deletions(-) diff --git a/crates/op-rbuilder/src/args/op.rs b/crates/op-rbuilder/src/args/op.rs index 75e208cc5..f1f040606 100644 --- a/crates/op-rbuilder/src/args/op.rs +++ b/crates/op-rbuilder/src/args/op.rs @@ -176,7 +176,7 @@ pub struct FlashblocksArgs { env = "FLASHBLOCKS_MAX_PER_BLOCK", default_value = "10" )] - pub flashblocks_max_per_block: u64, + pub max_flashblocks_per_block: u64, } impl Default for FlashblocksArgs { diff --git a/crates/op-rbuilder/src/builders/flashblocks/config.rs b/crates/op-rbuilder/src/builders/flashblocks/config.rs index b3f491175..cd587233c 100644 --- a/crates/op-rbuilder/src/builders/flashblocks/config.rs +++ b/crates/op-rbuilder/src/builders/flashblocks/config.rs @@ -80,7 +80,7 @@ impl TryFrom for FlashblocksConfig { let flashblocks_number_contract_address = args.flashblocks.flashblocks_number_contract_address; - let max_flashblocks_per_block = args.flashblocks.flashblocks_max_per_block; + let max_flashblocks_per_block = args.flashblocks.max_flashblocks_per_block; Ok(Self { ws_addr, @@ -103,6 +103,7 @@ impl FlashBlocksConfigExt for BuilderConfig { if self.block_time.as_millis() == 0 { return 0; } - (self.block_time.as_millis() / self.specific.interval.as_millis()) as u64 + let calculated = (self.block_time.as_millis() / self.specific.interval.as_millis()) as u64; + calculated.min(self.specific.max_flashblocks_per_block) } } diff --git a/crates/op-rbuilder/src/builders/flashblocks/payload.rs b/crates/op-rbuilder/src/builders/flashblocks/payload.rs index 68caec463..2a92ac1c8 100644 --- a/crates/op-rbuilder/src/builders/flashblocks/payload.rs +++ b/crates/op-rbuilder/src/builders/flashblocks/payload.rs @@ -807,66 +807,68 @@ where /// Calculate number of flashblocks. /// If dynamic is enabled this function will take time drift into the account. pub(super) fn calculate_flashblocks(&self, timestamp: u64) -> (u64, Duration) { - let (calculated_flashblocks, first_offset) = if self.config.specific.fixed { - ( + if self.config.specific.fixed { + return ( self.config.flashblocks_per_block(), // We adjust first FB to ensure that we have at least some time to make all FB in time self.config.specific.interval - self.config.specific.leeway_time, - ) - } else { - // We use this system time to determine remining time to build a block - // Things to consider: - // FCU(a) - FCU with attributes - // FCU(a) could arrive with `block_time - fb_time < delay`. In this case we could only produce 1 flashblock - // FCU(a) could arrive with `delay < fb_time` - in this case we will shrink first flashblock - // FCU(a) could arrive with `fb_time < delay < block_time - fb_time` - in this case we will issue less flashblocks - let target_time = std::time::SystemTime::UNIX_EPOCH + Duration::from_secs(timestamp) - - self.config.specific.leeway_time; - let now = std::time::SystemTime::now(); - let Ok(time_drift) = target_time.duration_since(now) else { - error!( - target: "payload_builder", - message = "FCU arrived too late or system clock are unsynced", - ?target_time, - ?now, - ); - let fallback_flashblocks = self.config.flashblocks_per_block().min(self.config.specific.max_flashblocks_per_block); - return (fallback_flashblocks, self.config.specific.interval); - }; - self.metrics.flashblocks_time_drift.record( - self.config - .block_time - .as_millis() - .saturating_sub(time_drift.as_millis()) as f64, ); - debug!( + } + // We use this system time to determine remining time to build a block + // Things to consider: + // FCU(a) - FCU with attributes + // FCU(a) could arrive with `block_time - fb_time < delay`. In this case we could only produce 1 flashblock + // FCU(a) could arrive with `delay < fb_time` - in this case we will shrink first flashblock + // FCU(a) could arrive with `fb_time < delay < block_time - fb_time` - in this case we will issue less flashblocks + let target_time = std::time::SystemTime::UNIX_EPOCH + Duration::from_secs(timestamp) + - self.config.specific.leeway_time; + let now = std::time::SystemTime::now(); + let Ok(time_drift) = target_time.duration_since(now) else { + error!( target: "payload_builder", - message = "Time drift for building round", + message = "FCU arrived too late or system clock are unsynced", ?target_time, - time_drift = self.config.block_time.as_millis().saturating_sub(time_drift.as_millis()), - ?timestamp + ?now, + ); + return ( + self.config.flashblocks_per_block(), + self.config.specific.interval, ); - // This is extra check to ensure that we would account at least for block time in case we have any timer discrepancies. - let time_drift = time_drift.min(self.config.block_time); - let interval = self.config.specific.interval.as_millis() as u64; - let time_drift = time_drift.as_millis() as u64; - let first_flashblock_offset = time_drift.rem(interval); - if first_flashblock_offset == 0 { - // We have perfect division, so we use interval as first fb offset - (time_drift.div(interval), Duration::from_millis(interval)) - } else { - // Non-perfect division, so we account for it. - ( - time_drift.div(interval) + 1, - Duration::from_millis(first_flashblock_offset), - ) - } + }; + self.metrics.flashblocks_time_drift.record( + self.config + .block_time + .as_millis() + .saturating_sub(time_drift.as_millis()) as f64, + ); + debug!( + target: "payload_builder", + message = "Time drift for building round", + ?target_time, + time_drift = self.config.block_time.as_millis().saturating_sub(time_drift.as_millis()), + ?timestamp + ); + // This is extra check to ensure that we would account at least for block time in case we have any timer discrepancies. + let time_drift = time_drift.min(self.config.block_time); + let interval = self.config.specific.interval.as_millis() as u64; + let time_drift = time_drift.as_millis() as u64; + let first_flashblock_offset = time_drift.rem(interval); + let (calculated_flashblocks, first_offset) = if first_flashblock_offset == 0 { + // We have perfect division, so we use interval as first fb offset + (time_drift.div(interval), Duration::from_millis(interval)) + } else { + // Non-perfect division, so we account for it. + ( + time_drift.div(interval) + 1, + Duration::from_millis(first_flashblock_offset), + ) }; // Apply the maximum flashblocks per block cap - let final_flashblocks = calculated_flashblocks.min(self.config.specific.max_flashblocks_per_block); - - (final_flashblocks, first_offset) + ( + calculated_flashblocks.min(self.config.specific.max_flashblocks_per_block), + first_offset, + ) } } diff --git a/crates/op-rbuilder/src/tests/flashblocks.rs b/crates/op-rbuilder/src/tests/flashblocks.rs index a49917be0..f508e8936 100644 --- a/crates/op-rbuilder/src/tests/flashblocks.rs +++ b/crates/op-rbuilder/src/tests/flashblocks.rs @@ -18,7 +18,7 @@ use crate::{ flashblocks_fixed: false, flashblocks_calculate_state_root: true, flashblocks_number_contract_address: None, - flashblocks_max_per_block: 10, + max_flashblocks_per_block: 10, }, ..Default::default() })] @@ -58,7 +58,7 @@ async fn smoke_dynamic_base(rbuilder: LocalInstance) -> eyre::Result<()> { flashblocks_fixed: false, flashblocks_calculate_state_root: true, flashblocks_number_contract_address: None, - flashblocks_max_per_block: 10, + max_flashblocks_per_block: 10, }, ..Default::default() })] @@ -98,7 +98,7 @@ async fn smoke_dynamic_unichain(rbuilder: LocalInstance) -> eyre::Result<()> { flashblocks_fixed: true, flashblocks_calculate_state_root: true, flashblocks_number_contract_address: None, - flashblocks_max_per_block: 10, + max_flashblocks_per_block: 10, }, ..Default::default() })] @@ -138,7 +138,7 @@ async fn smoke_classic_unichain(rbuilder: LocalInstance) -> eyre::Result<()> { flashblocks_fixed: true, flashblocks_calculate_state_root: true, flashblocks_number_contract_address: None, - flashblocks_max_per_block: 10, + max_flashblocks_per_block: 10, }, ..Default::default() })] @@ -178,7 +178,7 @@ async fn smoke_classic_base(rbuilder: LocalInstance) -> eyre::Result<()> { flashblocks_fixed: false, flashblocks_calculate_state_root: true, flashblocks_number_contract_address: None, - flashblocks_max_per_block: 10, + max_flashblocks_per_block: 10, }, ..Default::default() })] @@ -225,7 +225,7 @@ async fn unichain_dynamic_with_lag(rbuilder: LocalInstance) -> eyre::Result<()> flashblocks_fixed: false, flashblocks_calculate_state_root: true, flashblocks_number_contract_address: None, - flashblocks_max_per_block: 10, + max_flashblocks_per_block: 10, }, ..Default::default() })] @@ -265,7 +265,7 @@ async fn dynamic_with_full_block_lag(rbuilder: LocalInstance) -> eyre::Result<() flashblocks_fixed: false, flashblocks_calculate_state_root: true, flashblocks_number_contract_address: None, - flashblocks_max_per_block: 10, + max_flashblocks_per_block: 10, }, ..Default::default() })] @@ -327,7 +327,7 @@ async fn test_flashblock_min_filtering(rbuilder: LocalInstance) -> eyre::Result< flashblocks_fixed: false, flashblocks_calculate_state_root: true, flashblocks_number_contract_address: None, - flashblocks_max_per_block: 10, + max_flashblocks_per_block: 10, }, ..Default::default() })] @@ -385,7 +385,7 @@ async fn test_flashblock_max_filtering(rbuilder: LocalInstance) -> eyre::Result< flashblocks_fixed: false, flashblocks_calculate_state_root: true, flashblocks_number_contract_address: None, - flashblocks_max_per_block: 10, + max_flashblocks_per_block: 10, }, ..Default::default() })] @@ -432,7 +432,7 @@ async fn test_flashblock_min_max_filtering(rbuilder: LocalInstance) -> eyre::Res flashblocks_fixed: false, flashblocks_calculate_state_root: false, flashblocks_number_contract_address: None, - flashblocks_max_per_block: 10, + max_flashblocks_per_block: 10, }, ..Default::default() })] @@ -478,7 +478,7 @@ async fn test_flashblocks_no_state_root_calculation(rbuilder: LocalInstance) -> flashblocks_fixed: true, flashblocks_calculate_state_root: true, flashblocks_number_contract_address: None, - flashblocks_max_per_block: 3, // Cap at 3 flashblocks instead of default 5 + max_flashblocks_per_block: 3, // Cap at 3 flashblocks instead of default 5 }, ..Default::default() })] @@ -498,15 +498,27 @@ async fn test_max_flashblocks_per_block_cap(rbuilder: LocalInstance) -> eyre::Re // Build a block - normally would produce 5 flashblocks (1000ms / 200ms = 5) // But with max_flashblocks_per_block: 3, it should cap at 3 let block = driver.build_new_block().await?; - assert_eq!(block.transactions.len(), 8, "Block should contain all transactions"); // 5 normal txn + deposit + 2 builder txn + assert_eq!( + block.transactions.len(), + 8, + "Block should contain all transactions" + ); // 5 normal txn + deposit + 2 builder txn let flashblocks = flashblocks_listener.get_flashblocks(); // Should produce only 3 flashblocks + 1 base flashblock = 4 total - assert_eq!(4, flashblocks.len(), "Should be capped at 3 flashblocks + 1 base = 4 total"); + assert_eq!( + 4, + flashblocks.len(), + "Should be capped at 3 flashblocks + 1 base = 4 total" + ); // Verify flashblock indices are within expected range for fb in &flashblocks { - assert!(fb.index <= 3, "Flashblock index should not exceed 3, got index {}", fb.index); + assert!( + fb.index <= 3, + "Flashblock index should not exceed 3, got index {}", + fb.index + ); } flashblocks_listener.stop().await @@ -523,7 +535,7 @@ async fn test_max_flashblocks_per_block_cap(rbuilder: LocalInstance) -> eyre::Re flashblocks_fixed: false, flashblocks_calculate_state_root: true, flashblocks_number_contract_address: None, - flashblocks_max_per_block: 5, // Cap at 5 flashblocks + max_flashblocks_per_block: 5, // Cap at 5 flashblocks }, ..Default::default() })] @@ -544,15 +556,26 @@ async fn test_max_flashblocks_dynamic_timing(rbuilder: LocalInstance) -> eyre::R // Would normally create ~20 flashblocks (2000ms / 100ms = 20) // But should be capped at 5 let block = driver.build_new_block_with_current_timestamp(None).await?; - assert!(block.transactions.len() >= 5, "Block should contain transactions"); + assert!( + block.transactions.len() >= 5, + "Block should contain transactions" + ); let flashblocks = flashblocks_listener.get_flashblocks(); // Should be capped at 5 flashblocks + 1 base = 6 total - assert!(flashblocks.len() <= 6, "Should be capped at 5 flashblocks + 1 base = 6 total, got {}", flashblocks.len()); + assert!( + flashblocks.len() <= 6, + "Should be capped at 5 flashblocks + 1 base = 6 total, got {}", + flashblocks.len() + ); // Verify no flashblock index exceeds the cap for fb in &flashblocks { - assert!(fb.index <= 5, "Flashblock index should not exceed 5, got index {}", fb.index); + assert!( + fb.index <= 5, + "Flashblock index should not exceed 5, got index {}", + fb.index + ); } flashblocks_listener.stop().await