Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor & Fix Bugs in Payload Selection Logic #4950

Merged
merged 4 commits into from
Nov 29, 2023

Conversation

ethDreamer
Copy link
Member

@ethDreamer ethDreamer commented Nov 24, 2023

Issue Addressed

The existing payload selection logic is very difficult to reason about and there are two different bugs:

// This is the logic before this PR
fn select_payload() {
    if builder_enabled {
        match chain_health {
            healthy => {
                (local_result, relay) = fetch_local_and_builder_payloads_concurrently()
                local = match local_result? {
                   // ^ this line is a bug as it will cause the function to error if local fails but relay doesn't
                   ...
                }
                return match (relay, local) {
                    (Err, Ok) => Payload::Local,
                    (Ok(None), Ok) => Payload::Local,
                    (Ok(Some(relay)), Ok(local)) => {
                        if !always_prefer_builder_payload {
                            if local_value > relay_value {
                                return Payload::Local
                            } else if should_override_builder && percentage < ignore_builder_override_suggestion_threshold {
                                return Payload::Local
                            }
                        }
                        match verify_builder_bid(relay) {
                            Ok(()) => Payload::Builder,
                            Err(not_invalid) => Payload::Local,
                            Err(invalid) => Payload::Local,
                        }
                    }
                    (Ok(Some(relay)), Err) => {
                        match verify_builder_bid(relay) {
                            Ok(()) => Payload::Builder,
                            Err(not_invalid) => Payload::Builder, // this is a bug actually, see below
                            Err(invalid) => Error,
                        }
                    }
                    (Err, Err) => Error,
                    (Ok(None), Err) => Error,
                }
            }
            premerge | optimistic | unhealthy => (),
        }
    }
    Payload::Local
}

fn verify_builder_bid(relay) {
    if relay.value() < builder_profit_threshold {
        return Err(not_invalid)
        // this is a bug because all other error validations haven't run yet so we don't know if it's really invalid
    }
    if relay.actual_payload_validity_checks() {
        return Err(invalid)
    }
    Ok(())
}

I have refactored this code for simplicity and fixing bugs:

fn select_payload() {
    if !builder_enabled {
        return Payload::Local;
    }
    if chain_health != healthy {
        return Payload::Local;
    }
    
    // bug fixed here so the function doesn't return early if local fetch fails
    (local, relay) = fetch_local_and_builder_payloads_concurrently();
    match (relay, local) {
        (Err, Ok(local)) => Payload::Local,
        (Ok(None), Ok(local)) => Payload::Local,
        (Err, Err) => Error,
        (Ok(None), Err) => Error,
        Ok(Some(relay), Ok(local)) => {
            if verify_builder_bid(relay).is_err() {
                return Payload::Local,
            }
            if always_prefer_builder_payload {
                return Payload::Builder,
            }
            if local_value > relay_value {
                return Payload::Local,
            }
            if relay_value < builder_profit_threshold {
                return Payload::Local,
            }
            if should_override_builder && percentage < ignore_builder_override_suggestion_threshold {
                return Payload::Local
            }
            Payload::Builder
        }
        Ok(Some(relay), Err) => {
            if verify_builder_bid(relay).is_err() {
                Error
            } else {
                Payload::Builder,
            }
        }
    }
}

fn verify_builder_bid(relay) {
    if relay.actual_payload_validity_checks() {
        return Err(invalid)
    }
    Ok(())
}

@ethDreamer ethDreamer added bug Something isn't working ready-for-review The code is ready for review code-quality labels Nov 24, 2023
Copy link
Member

@michaelsproul michaelsproul left a comment

Choose a reason for hiding this comment

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

Nice fixes and a much clearer refactor!

I just had one suggestion about naming.

beacon_node/execution_layer/src/lib.rs Outdated Show resolved Hide resolved
@michaelsproul michaelsproul added v4.6.0 ETA Q1 2024 waiting-on-author The reviewer has suggested changes and awaits thier implementation. and removed ready-for-review The code is ready for review labels Nov 27, 2023
@ethDreamer ethDreamer added ready-for-review The code is ready for review and removed waiting-on-author The reviewer has suggested changes and awaits thier implementation. labels Nov 28, 2023
@michaelsproul michaelsproul added ready-for-merge This PR is ready to merge. and removed ready-for-review The code is ready for review labels Nov 29, 2023
@michaelsproul michaelsproul merged commit 43d9815 into sigp:unstable Nov 29, 2023
23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working code-quality ready-for-merge This PR is ready to merge. v4.6.0 ETA Q1 2024
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants