Skip to content

Refuse an unsupported fork on the SSZ validation path - #564

Open
0w3n-d wants to merge 1 commit into
od/gloas-builder-step0-integrationfrom
od/gloas-sim-fork-gate-step1
Open

Refuse an unsupported fork on the SSZ validation path#564
0w3n-d wants to merge 1 commit into
od/gloas-builder-step0-integrationfrom
od/gloas-sim-fork-gate-step1

Conversation

@0w3n-d

@0w3n-d 0w3n-d commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Issue: #561 (step 1 of 6)

What this PR does

Closes the hole #517 left open. That PR stopped Gloas submissions being
mis-routed to the Electra-shaped JSON RPC, but simulator/tile.rs chose its
dispatch like this:

let dispatch = if let Some(url) = &sim.client.ssz_url {
    SimDispatch::Ssz { ... }          // <- no fork check at all
} else {
    let fork = submission.fork_name();
    let Some(..) = sim.client.sim_request_builder(fork) else { /* UnsupportedFork */ };

An SSZ simulator — which is how the ethrex simulation role is reached — got
every fork, including Gloas, and validated it as Fulu.

Both sides now refuse:

  • Relay: ssz_request_builder takes a fork and returns None for one it
    cannot validate, mirroring sim_request_builder. The dispatch is a single
    match so neither branch can skip the gate again. The two kinds keep
    separate fork lists, because the SSZ and JSON validators are different
    implementations — step 3 turns Gloas on for SSZ while reth still cannot.
  • Builder: the simulation role honours decoder_params.fork_name, which it
    previously received and discarded, on both /validate and
    /validate_merged.

Why 501 and not 400

SimulatorClient::ssz_request maps 400 to BlockValidationFailed, which is
demotable, and anything else to RpcError, which is not. Refusing a fork is
helix's own limitation, so a 400 would cost a builder its optimistic status for
our gap. refusing_an_unsupported_fork_cannot_demote_a_builder pins that.

What this PR deliberately does not do

Adds no Gloas support. After this the relay declines to send Gloas to an SSZ
simulator and the simulator declines to accept it — which is the correct
behaviour until step 3, not a workaround.

Tests

6 new, written before the implementation and signed off first.

  • Relay (2): ssz_request_builder_routes_fulu unchanged;
    ssz_request_builder_refuses_gloas is the regression.
  • Builder (4): a Gloas request to /validate is refused; the same for
    /validate_merged, which had the identical hole; a Fulu request is still
    validated; and the refusal cannot demote a builder.

151 pass in helix-builder (was 147), 127 in helix-relay (was 125).

Reviewer checklist

  • CI (lint, unit-test) is green
  • Matches the linked issue/step
  • No unexplained scope creep or unrelated files touched

The SSZ dispatch short-circuited above the fork gate #517 added, so a
Gloas submission reaching an SSZ simulator was validated as Fulu.

Gate both dispatch kinds, and have the simulation role refuse a fork it
does not understand instead of discarding `decoder_params.fork_name`.

Answer 501, not 400. The relay maps a 400 body to a demotable error, and
this is helix's own limitation.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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