Skip to content

Merge the ethrex builder stack into the Gloas stack - #562

Open
0w3n-d wants to merge 30 commits into
od/gloas-step6-real-bid-and-envelopefrom
od/gloas-builder-step0-integration
Open

Merge the ethrex builder stack into the Gloas stack#562
0w3n-d wants to merge 30 commits into
od/gloas-step6-real-bid-and-envelopefrom
od/gloas-builder-step0-integration

Conversation

@0w3n-d

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

Copy link
Copy Markdown
Collaborator

Issue: #561 (step 0 of 6)

What this PR does

Merges the ethrex builder stack (#560, which carries the simulator stack
#528-#544 beneath it) into the Gloas relay stack (#515). Both branch from
develop, and neither can be exercised on a Gloas testnet alone: the relay
stack has no builder or simulator that can produce or validate a Gloas block,
and the builder stack is entirely Fulu-shaped.

Everything after this in #561 stacks on this branch.

The one conflict

crates/types/src/hydration.rs. Both sides appended test functions at the same
point, and the diff landed mid-function on each side. Both are kept — all
four tests are present and run:

  • dehydrated_with_merging_data_decodes_under_gloas_fork (Gloas side)
  • dehydrated_bid_submission_decodes_under_gloas_fork (Gloas side)
  • dehydrated_with_adjustments_and_merging_data_ssz_round_trip (builder side)
  • dehydrated_with_adjustments_and_merging_data_split (builder side)

No production code conflicted.

What this PR deliberately does not do

No behaviour changes at all. Nothing here makes anything Gloas-ready — the
builder's three roles remain Fulu-shaped, and the two defects #561 records are
untouched:

Those are steps 1 and 2.

Tests

None added; a merge should not need them. The existing suites are the check,
and all pass on the merged tree: helix-types 35, helix-builder 147,
helix-relay 125. just fmt-check and the project clippy command are clean, and
helix-builder introduces no new lints beyond the pre-existing ones recorded
in #554.

Reviewer checklist

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

ninaiiad and others added 30 commits August 25, 2026 12:11
Co-authored-by: vladimir-ea <vladimir@gattaca.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
… simulator (#506)

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…ble failures (#508)

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
--merging.config activates merging, the new --sim.config activates
simulation, neither is a startup error. The relay signer loads only for
merging. The simulation role boots the node only; its servers come later.

Step 1 of #527.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…mmon

The disallow list's parsing and digest, and the Safe multiSend payment
recognition, carry no reth types. Move them so the ethrex simulator uses
the same code. The functions and their tests move verbatim.

Step 2 of #527.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
BlockValidator turns an ExecutionPayloadV3 into the block it describes,
checks the bid trace against that block, and finds the parent within the
validation window. Nothing executes yet.

The head comes from the node's watch channel rather than a store read per
call, which keeps prepare synchronous.

Step 3 of #527.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Runs validate_block_pre_execution, executes on the parent state, then
checks gas used, receipts root, requests hash and state root. The store
is only read: the submitted block is never persisted.

Step 4 of #527.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The recipient's whole-block balance delta decides first. When the
proposer also spends, the payment must be recognisable: a direct
transfer, or a PAYMENT_FORWARDER call where its runtime is deployed.
Merged blocks sum the base payment tx and the trailing distribution tx.

helix-common becomes a runtime dependency for the payment constants.

Ports the current reth behavior unchanged, including the multiSend gap
that #533 will close for both simulators at once.

Step 5 of #527.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Interaction means effect: a state change, or a transaction addressed to
the account. The coinbase and the proposer fee recipient are checked
directly, since neither has to change state.

Reading an account is not interaction. The reth simulator rejects such a
block, so the two disagree; see the test that records it.

Step 6 of #527.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The submission carries one bundle for the whole block, so the block's
blob versioned hashes must match its commitments in order. ethrex's
BlobsBundle::validate is per transaction and does not fit that shape, so
this checks the lengths and hashes and calls verify_cell_kzg_proof_batch
directly.

Blob gas accounting needs nothing: verify_blob_gas_usage already runs in
validate_block_pre_execution.

Step 8 of #527.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
/validate and /validate_merged decode the relay's SSZ requests, run the
validator on a blocking thread under a semaphore, and answer 200 or 400
with the reason. A dehydrated submission answers 424 so the relay retries
with full bytes. The disallow list refreshes from the configured endpoint.

main now builds the validator and spawns both, so the module no longer
needs allow(dead_code).

Drops rpc_addr: no JSON-RPC is served, and an unused config field is a
trap. The relay reaches this role through its simulator ssz_url.

Step 9 of #527.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
README covers both roles, how to run each, and where the simulation role
differs from crates/simulator: no inclusion lists, a narrower disallow
rule, SSZ only, and release builds only.

Step 10 of #527.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Turn `Roles` into a struct of optional configs. As an enum a third role
needs seven variants.

The building role takes its own two keys: `RELAY_KEY` is already read as
secp256k1 by the merging role and as BLS by `load_keypair`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The beacon node supplies the consensus fields and the relay supplies the
proposer. Neither alone is enough to build.

Take the fee recipient and gas limit from the duty. The event carries a
`suggested_fee_recipient`, but it is the local validator's.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Reserve the payout gas by lowering `remaining_gas` before the fill and
restoring it after. `fill_transactions` spends the whole budget.

Raise the default subsidy to 0.001 ETH. At 1 gwei the old default could
not cover the payout's own gas, so every idle slot was skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Take the builder domain from the beacon node's own spec and genesis. A
hardcoded genesis fork version makes the relay drop every bid, silently.

Check the blobs bundle by proof count, not by `version`. ethrex's
`AddAssign` does not propagate it, so an aggregate always reads 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sleep to an absolute deadline. The offsets share one origin, so sleeping
them end to end would land every attempt after the last.

Key the best bid by slot and parent. After a re-org the earlier bid sits
on a dead parent, so a lower value must still go out.

Drop `self_validate`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both stacks branch from develop and neither can be tested on a Gloas
testnet alone.

The only conflict is two test functions added at the same point in
`hydration.rs`. Both are kept.

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.

4 participants