From 61092f35e3f52bd8658c8f073c5246d3149c868f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roman=20Hodul=C3=A1k?= Date: Tue, 2 Sep 2025 15:27:08 +0200 Subject: [PATCH 1/4] fix(optimism): Prevent repeated executions of current flashblock sequence --- crates/optimism/flashblocks/src/service.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/crates/optimism/flashblocks/src/service.rs b/crates/optimism/flashblocks/src/service.rs index 2a9ef0db54b..52793740c6b 100644 --- a/crates/optimism/flashblocks/src/service.rs +++ b/crates/optimism/flashblocks/src/service.rs @@ -187,15 +187,15 @@ where fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { let this = self.get_mut(); - let mut new_flashblock = false; // consume new flashblocks while they're ready while let Poll::Ready(Some(result)) = this.rx.poll_next_unpin(cx) { match result { Ok(flashblock) => { if let Err(err) = this.blocks.insert(flashblock) { debug!(%err, "Failed to prepare flashblock"); - } else { - new_flashblock = true; + } + if this.current.take().is_some() { + return Poll::Ready(None); } } Err(err) => return Poll::Ready(Some(Err(err))), @@ -216,9 +216,10 @@ where } } - if !new_flashblock && this.current.is_none() { - // no new flashbblocks received since, block is still unchanged - return Poll::Pending + // is current block not taken? + if this.current.is_some() { + // execution is not needed + return Poll::Pending; } // try to build a block on top of latest @@ -282,6 +283,11 @@ where Ok(()) } + /// TRUE if there are no flashblocks. + fn is_empty(&self) -> bool { + self.inner.is_empty() + } + /// Returns the number of tracked flashblocks. fn count(&self) -> usize { self.inner.len() From 2d01388d92aa38cdef5c9eb2c959c58b64a1b4a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roman=20Hodul=C3=A1k?= Date: Tue, 2 Sep 2025 15:31:17 +0200 Subject: [PATCH 2/4] refactor(optimism): Invalidate `current` only if `FlashBlockSequence::insert` succeeds Remove unused `FlashBlockSequence::is_empty` --- crates/optimism/flashblocks/src/service.rs | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/crates/optimism/flashblocks/src/service.rs b/crates/optimism/flashblocks/src/service.rs index 52793740c6b..0147124acf0 100644 --- a/crates/optimism/flashblocks/src/service.rs +++ b/crates/optimism/flashblocks/src/service.rs @@ -190,14 +190,14 @@ where // consume new flashblocks while they're ready while let Poll::Ready(Some(result)) = this.rx.poll_next_unpin(cx) { match result { - Ok(flashblock) => { - if let Err(err) = this.blocks.insert(flashblock) { - debug!(%err, "Failed to prepare flashblock"); + Ok(flashblock) => match this.blocks.insert(flashblock) { + Ok(_) => { + if this.current.take().is_some() { + return Poll::Ready(None) + } } - if this.current.take().is_some() { - return Poll::Ready(None); - } - } + Err(err) => debug!(%err, "Failed to prepare flashblock"), + }, Err(err) => return Poll::Ready(Some(Err(err))), } } @@ -283,11 +283,6 @@ where Ok(()) } - /// TRUE if there are no flashblocks. - fn is_empty(&self) -> bool { - self.inner.is_empty() - } - /// Returns the number of tracked flashblocks. fn count(&self) -> usize { self.inner.len() From 9986873a3e1b90395357bdffee7356d56889f2e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roman=20Hodul=C3=A1k?= Date: Tue, 2 Sep 2025 15:36:13 +0200 Subject: [PATCH 3/4] refactor(optimism): Output `Poll::Ready(None)` after all flashblocks are received --- crates/optimism/flashblocks/src/service.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/crates/optimism/flashblocks/src/service.rs b/crates/optimism/flashblocks/src/service.rs index 0147124acf0..9e83c724376 100644 --- a/crates/optimism/flashblocks/src/service.rs +++ b/crates/optimism/flashblocks/src/service.rs @@ -186,6 +186,7 @@ where fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { let this = self.get_mut(); + let mut taken = false; // consume new flashblocks while they're ready while let Poll::Ready(Some(result)) = this.rx.poll_next_unpin(cx) { @@ -193,7 +194,7 @@ where Ok(flashblock) => match this.blocks.insert(flashblock) { Ok(_) => { if this.current.take().is_some() { - return Poll::Ready(None) + taken = true; } } Err(err) => debug!(%err, "Failed to prepare flashblock"), @@ -202,6 +203,12 @@ where } } + // is current block taken? + if taken { + // output none to erase it + return Poll::Ready(None); + } + // advance new canonical message, if any to reset flashblock { let fut = this.canon_receiver.recv(); From 165f818e71f1db1e1eb759b381f80d15732fca5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roman=20Hodul=C3=A1k?= Date: Tue, 2 Sep 2025 15:45:07 +0200 Subject: [PATCH 4/4] fix(optimism): Take `current` only on canonical state update --- crates/optimism/flashblocks/src/service.rs | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/crates/optimism/flashblocks/src/service.rs b/crates/optimism/flashblocks/src/service.rs index 9e83c724376..36f8ed32a6c 100644 --- a/crates/optimism/flashblocks/src/service.rs +++ b/crates/optimism/flashblocks/src/service.rs @@ -37,6 +37,7 @@ pub struct FlashBlockService< rx: S, current: Option>, blocks: FlashBlockSequence, + rebuild: bool, evm_config: EvmConfig, provider: Provider, canon_receiver: CanonStateNotifications, @@ -71,6 +72,7 @@ where canon_receiver: provider.subscribe_to_canonical_state(), provider, cached_state: None, + rebuild: false, } } @@ -186,29 +188,18 @@ where fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { let this = self.get_mut(); - let mut taken = false; // consume new flashblocks while they're ready while let Poll::Ready(Some(result)) = this.rx.poll_next_unpin(cx) { match result { Ok(flashblock) => match this.blocks.insert(flashblock) { - Ok(_) => { - if this.current.take().is_some() { - taken = true; - } - } + Ok(_) => this.rebuild = true, Err(err) => debug!(%err, "Failed to prepare flashblock"), }, Err(err) => return Poll::Ready(Some(Err(err))), } } - // is current block taken? - if taken { - // output none to erase it - return Poll::Ready(None); - } - // advance new canonical message, if any to reset flashblock { let fut = this.canon_receiver.recv(); @@ -223,9 +214,7 @@ where } } - // is current block not taken? - if this.current.is_some() { - // execution is not needed + if !this.rebuild && this.current.is_some() { return Poll::Pending; } @@ -234,6 +223,7 @@ where Ok(Some(new_pending)) => { // built a new pending block this.current = Some(new_pending.clone()); + this.rebuild = false; return Poll::Ready(Some(Ok(Some(new_pending)))); } Ok(None) => {