Skip to content

verify balance and approval strategies concurrently#4512

Open
ashleychandy wants to merge 1 commit into
cowprotocol:mainfrom
ashleychandy:concurrent-balance-override-verification
Open

verify balance and approval strategies concurrently#4512
ashleychandy wants to merge 1 commit into
cowprotocol:mainfrom
ashleychandy:concurrent-balance-override-verification

Conversation

@ashleychandy

Copy link
Copy Markdown
Contributor

Description

Improves detection latency by verifying balance and approval strategy candidates concurrently instead of sequentially. With high RPC latency or timeouts, this reduces worst-case detection time from ~60s to ~15s (assuming all 60 candidates time out at the 1s limit) while preserving priority ordering and avoiding RPC node overload.

Changes

  • Add find_first_ordered_concurrent helper for bounded concurrent verification with priority preservation
  • Add concurrency_limit field (default: 4) to both balance::Detector and approval::Detector
  • Replace sequential verification loops with concurrent execution using FuturesUnordered
  • Stop dispatching lower-priority candidates once a higher-priority success is already in hand; in-flight
    higher-priority candidates are still awaited to ensure the best result is returned
  • Add futures crate dependency for stream utilities

Note: concurrency_limit defaults to 4 and is hardcoded for now.
A follow-up can expose this via environment variable
if tuning is needed in production.

@ashleychandy ashleychandy requested a review from a team as a code owner June 10, 2026 13:55

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces concurrent verification of approval and balance strategies up to a specified concurrency limit by adding a new find_first_ordered_concurrent helper in detector.rs. Feedback on the changes highlights three critical compilation issues: a move-out-of-index error when matching on results[drain_cursor] in detector.rs, and lifetime-related compilation errors in both approval/mod.rs and balance/mod.rs caused by explicit return type annotations on the make_fut closures.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +158 to +170
while drain_cursor < n {
match results[drain_cursor] {
None => break,
Some(Some(_)) => {
if let Some(Some(value)) = results[drain_cursor].take() {
return Some((drain_cursor, value));
}
}
Some(None) => {
drain_cursor += 1;
}
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

Matching on results[drain_cursor] by value will fail to compile with cannot move out of index of Vec because Option<Option<T>> is not Copy. Additionally, matching on a reference would cause borrow checker errors when calling .take() inside the match arm. Replacing the match with a direct .is_none() check and .take() avoids these issues and is more concise.

        while drain_cursor < n {
            if results[drain_cursor].is_none() {
                break;
            }
            if let Some(Some(value)) = results[drain_cursor].take() {
                return Some((drain_cursor, value));
            }
            drain_cursor += 1;
        }

Comment on lines +332 to +334
let make_fut = move |idx: usize| -> std::pin::Pin<
Box<dyn std::future::Future<Output = (usize, Option<ApprovalStrategy>)> + Send>,
> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The explicit return type annotation on the closure make_fut defaults to + 'static for the trait object. Since the future captures self (which is not 'static), this will cause a compilation error. Omitting the return type annotation allows the compiler to correctly infer the lifetime.

        let make_fut = move |idx: usize| {

Comment on lines +444 to +446
let make_fut = move |idx: usize| -> std::pin::Pin<
Box<dyn std::future::Future<Output = (usize, Option<Strategy>)> + Send>,
> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The explicit return type annotation on the closure make_fut defaults to + 'static for the trait object. Since the future captures self (which is not 'static), this will cause a compilation error. Omitting the return type annotation allows the compiler to correctly infer the lifetime.

        let make_fut = move |idx: usize| {

@ashleychandy

Copy link
Copy Markdown
Contributor Author

I checked both points locally and don't see the reported issues.

The results[drain_cursor] match compiles successfully.
The make_fut closure also compiles as written

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant