Skip to content

Add EIP: Builder Execution Requests - #11760

Merged
eth-bot merged 27 commits into
ethereum:masterfrom
wemeetagain:eip-builder-deposit
Jul 3, 2026
Merged

eth-bot merged 27 commits into
ethereum:masterfrom
wemeetagain:eip-builder-deposit

Conversation

@wemeetagain

@wemeetagain wemeetagain commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

A new EIP that gives EIP-7732 (ePBS) builders their own
execution-layer request contracts on the EIP-7685 request bus, rather than routing
builder onboarding and exit through the validator flows. Two predeploys:

Request type Contract Input (raw calldata) Record
0x03 builder deposit (also top-up) pubkey ++ withdrawal_credentials ++ amount ++ signature (184 B) the input, amount little-endian (184 B)
0x04 builder exit pubkey (48 B) source_address ++ pubkey (68 B)

Both contracts are line-level copies of the deployed EIP-7002/7251 system contracts
(written in geas; the ethereum/sys-asm source assembles byte-identically to the
mainnet code): same dispatch — no ABI, caller + calldatasize only — EIP-1559-style
fee, EXCESS_INHIBITOR, queue and storage layout, end-of-block SYSTEM_ADDRESS
drain, and per-request LOG0. The exit contract is the EIP-7002 contract minus the
amount field; the deposit contract adds only two value checks (amount >= 1 ETH in
gwei, value - fee >= amount * 1 gwei). Neither performs on-chain cryptography.
Addresses, request-type bytes, and runtime code are placeholders pending allocation
and audit.

Rationale

  • Decouples builders from validators. Dedicated request types let the consensus layer
    route by type instead of inspecting withdrawal-credential prefixes, keying the validator
    and builder registries independently — which also lets a single public key be both a
    validator and a builder (a restriction this EIP removes).
  • Bounds a consensus-side DoS. A builder deposit's proof-of-
    possession is verified by the consensus layer (as in EIP-7732). Delivering deposits
    through a request bus capped at MAX_REQUESTS_PER_BLOCK per block, plus the EIP-1559 fee
    on top of the 1-ETH stake, bounds the per-block verification work and the spam economics.
  • Cold-key exit. A builder's BLS key is hot (it signs bids), so exit is authorized by
    the builder's execution_address, mirroring EIP-7002's rationale for 0x01 credentials.
  • Minimal audit surface. New system contracts carry audit risk, so the deltas against
    the audited, deployed EIP-7002/7251 code are kept to request-layout constants plus a
    handful of comparison instructions — enumerated in each contract's header.

Draft EIP for a builder-specific deposit predeploy that verifies BLS
proof-of-possession signatures on chain via the EIP-2537 precompiles,
serving the EIP-7732 builder population. A separate top_up entrypoint
adds unverified stake to an already-registered builder.
Replace event-log delivery with the EIP-7685 request mechanism used by
EIP-7002 (withdrawals) and EIP-7251 (consolidations): two single-type
predeploys sharing a RequestQueue base, drained by a SYSTEM_ADDRESS
end-of-block system call and committed via the block requests_hash.

- BuilderDepositContract (request type 0x03): deposit() verifies the BLS
  proof-of-possession, then appends a record to its queue; no logs.
- BuilderTopUpContract (request type 0x04): unverified top_up() appends a
  record to its queue.
- No request fee: the staked value is the anti-spam gate.

BLS verification and the prior audit fixes (domain separation, sign-bit
binding, precompile gas caps) are unchanged. Dequeued records carry no
signature, since the consensus layer trusts the execution-layer check.
Tests rewritten for the queue / system-read model (14 passing). Adds
requires 7685; request-type bytes and predeploy addresses are placeholders.
…fixes

Request fee (like EIP-7002/7251): RequestQueue gains an excess/count fee
market with fake_exponential; deposit/top_up require
msg.value >= stake + fee. No EXCESS_INHIBITOR (predeploys install with
empty storage, so excess starts at the minimum fee).

Unsigned amount: the BLS proof-of-possession now commits only to the
2-field message (pubkey, withdrawal_credentials); amount_gwei is an
explicit, unsigned parameter. Signing the amount added no security (the
unverified top_up already adds unsigned stake) and would otherwise force a
signed value derived from a fee unknown at signing time. The distinct
2-field message also reinforces cross-context replay protection.

Round-2 audit fixes:
- Queue storage is now a head/tail ring over a mapping that resets both
  pointers to 0 when emptied (EIP-7002 dequeue behavior), bounding storage
  to peak in-flight depth instead of leaking a slot per request forever.
- fallback requires empty calldata, so only the system read-out / fee
  getter reach it.
- Spec: a 0x03 record for an already-registered pubkey MUST be treated as
  a top-up (credit stake, never change withdrawal credentials), making the
  replayable deposit signature harmless.
- Fixed stale entrypoint signatures in the contract header comment.

Tests: 20 passing (17 without EIP-2537), incl. fee dynamics, queue reset,
and fallback-calldata regressions. Vectors regenerated for the 2-field
signing message.
Add the SSZ container definitions BuilderDepositRequest (pubkey,
withdrawal_credentials, amount) and BuilderTopUpRequest (pubkey, amount)
to the spec, matching the EIP-7002/7251 style and tying the 88/56-byte
record serialization to what the contract appends; note the absence of a
signature/index field versus the EIP-6110 DepositRequest.

Reduce the "Consensus-layer processing of records" rules to normative
statements that reference the new objects by name; the replayability
rationale lives in Security Considerations.
Add BuilderWithdrawalContract (request type 0x05, EIP-7002-style) for builder partial withdrawals and full exits, and broaden the draft to the full builder lifecycle (renamed to "Builder Execution Requests").
Switch from fork-time installation to a presigned deployment transaction plus an EXCESS_INHIBITOR that blocks requests until the first end-of-block system call, matching EIP-7002/7251. Updates the spec, the RequestQueue reference contract, and the tests.
The builder deposit contract no longer verifies BLS; it carries the signature for the consensus layer to verify, bounded by the per-block cap. Top-up folds into the deposit request (0x03, register-or-credit) and the withdrawal/exit contract becomes exit-only (0x04), authorized by execution_address. Adds a normative "Changes to EIP-7732" section (remove the process_deposit_request and process_voluntary_exit builder branches; keep onboard_builders_from_pending_deposits for genesis). Updates the spec, contracts, and tests; deletes the BLS machinery and py_ecc fixtures.
…t precondition (review 2)

Resolves the second adversarial review of the redesigned EIP. Builder deposits reuse DOMAIN_DEPOSIT (document the benign cross-class signature interchange instead of asserting a non-existent domain separation); give the exact process_deposit_request inert-return for a 0x03-prefix deposit plus a post-fork deposit-routing transition window so in-flight pre-fork deposits are not stranded; align the exit predicate to gloas is_active_builder and document consumed-not-retried; correct the PoP message to the 3-field DepositMessage; name the EIP-7804 0x03 collision; add Spam/state-growth and Locked-funds security notes. Spec-only; contracts and tests unchanged.
…ition window (review 3)

Resolves the third adversarial review of the redesigned EIP. Require a builder first deposit to carry a 0x03-prefixed withdrawal_credentials (a consensus-layer check mirroring process_deposit_request), so a registered builder always has a well-formed execution_address and validator and builder deposits no longer cross-register; the cross-class Security note is rewritten accordingly and now records that DOMAIN_DEPOSIT is chain- and fork-agnostic. Drop the post-fork deposit-routing transition window in favour of a single deterministic cutover: the genesis snapshot onboards pending builder deposits, and from the fork onward every 0x03-credentialed validator-contract deposit is dropped (a late straggler is re-onboarded via the builder deposit contract). Document the exited-builder top-up (credited stake is non-reactivatable and sweeps to the execution_address) and the custodial-split exit standoff (a bidding operator can hold the pending balance non-zero and block the execution_address holder from exiting). Spec-only; contracts and tests unchanged.
@wemeetagain
wemeetagain requested a review from eth-bot as a code owner June 3, 2026 16:38
@github-actions github-actions Bot added c-new Creates a brand new proposal s-draft This EIP is a Draft t-core labels Jun 3, 2026
@eth-bot

eth-bot commented Jun 3, 2026

Copy link
Copy Markdown
Collaborator

✅ All reviewers have approved.

@eth-bot eth-bot added e-consensus Waiting on editor consensus e-review Waiting on editor to review labels Jun 3, 2026
@github-actions github-actions Bot added the w-ci Waiting on CI to pass label Jun 3, 2026
Comment thread EIPS/eip-8282.md
Comment thread EIPS/eip-draft_builder_requests.md Outdated
@github-actions github-actions Bot removed the w-ci Waiting on CI to pass label Jun 4, 2026
lodekeeper added a commit to lodekeeper/lodestar that referenced this pull request Jun 12, 2026
The gloas bid and envelope carry an `ExecutionRequests` extended with
`builder_deposits` (0x03) and `builder_exits` (0x04) per
ethereum/consensus-specs#5359. Using `ssz.electra.ExecutionRequests.hashTreeRoot`
in the gloas-only code paths produced a root over the electra-shaped
container — wrong even when both builder lists are empty, because the
gloas container has two additional zero-hash leaves.

Switch the four gloas-only call sites to `ssz.gloas.ExecutionRequests`:
* `produceBlockBody.ts` self-build bid construction
* `verifyExecutionPayloadEnvelope.ts` bid↔envelope cross-check
* `executionPayloadEnvelope.ts` gossip validation
* `upgradeStateToGloas.ts` genesis bid default-value root

Refs: ethereum/consensus-specs#5359, ethereum/EIPs#11760

🤖 Generated with AI assistance
@fjl

fjl commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

I think the assets should be removed here. We should work on the contract in the sys-asm repo and then update the EIP later when it is final. This is also what we did for previous contracts.

Comment thread EIPS/eip-8282.md Outdated
Comment thread EIPS/eip-8282.md Outdated

### Constants

All address and request-type values below are placeholders. The `0x03`/`0x04` request types MUST be unique across **all** active [EIP-7685](./eip-7685.md) request types, including in-flight proposals ([EIP-7804](./eip-7804.md), a Draft, also claims `0x03`); final allocation is coordinated in consensus-specs.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[...] a Draft [...]

Best not to mention the status of other proposals here. It's very likely that its status will change, making this sentence incorrect.

Comment thread EIPS/eip-8282.md Outdated
Comment thread EIPS/eip-8282.md

### Deployment

Each predeploy is deployed exactly as the [EIP-7002](./eip-7002.md) and [EIP-7251](./eip-7251.md) request contracts are: by a one-time presigned transaction from a single-use deployer account (the Nick's-method scheme), so that `BUILDER_DEPOSIT_CONTRACT_ADDRESS` and `BUILDER_EXIT_CONTRACT_ADDRESS` are the addresses cryptographically derived from those transactions. Each contract's init code sets its `excess` slot to `EXCESS_INHIBITOR`, so no request can be enqueued until the inhibitor is cleared (see [Request fee](#request-fee)). The concrete transactions — and therefore the final addresses — will be fixed once the runtime bytecode is audited and frozen (see [Reference Implementation](#reference-implementation)).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

(the Nick's-method scheme)

If there's somewhere we can link to that defines this in detail (preferably in another EIP/ERC), we should.

Comment thread EIPS/eip-8282.md Outdated
Comment thread EIPS/eip-8282.md Outdated
Comment thread EIPS/eip-8282.md
- **Deposit proof-of-possession at the consensus layer.** The consensus layer verifies the proof-of-possession over the `DepositMessage` `(pubkey, withdrawal_credentials, amount)` under `DOMAIN_BUILDER_DEPOSIT` on a builder's first registration, and ignores the signature for top-ups. The per-block cap bounds how many such verifications the consensus layer performs per block; see *Spam and state growth* below for the full anti-abuse picture.
- **Cross-class deposit signatures.** Builder deposits are signed under `DOMAIN_BUILDER_DEPOSIT`, a signing domain distinct from the validator deposit's `DOMAIN_DEPOSIT`. The separate domain prevents cross-contract replay between the two deposit classes: a *validator* deposit proof-of-possession cannot be resubmitted as a builder deposit, and a *builder* deposit proof-of-possession cannot be resubmitted to the validator deposit contract — each contract's consensus-layer handler verifies only its own domain, so the two classes cannot cross-register. The single exception is fork-transition onboarding: the initial builder set is seeded through the validator deposit contract *before* the fork, so those seed deposits are necessarily signed under `DOMAIN_DEPOSIT` and validated under it by `onboard_builders_from_pending_deposits`, with the `0x03` `BUILDER_WITHDRAWAL_PREFIX` on the credential distinguishing them for builder onboarding; after the fork the prefix is deprecated and steady-state builder deposits use `DOMAIN_BUILDER_DEPOSIT`. Like `DOMAIN_DEPOSIT`, the builder domain is chain- and fork-agnostic, so a builder's *own* public proof-of-possession remains replayable as a top-up (see *Replayable deposit records* below) — but only within the builder class, funding stake the original signer already authorized, and it can redirect nothing.
- **Exit authorization.** The exit contract records `msg.sender` as `source_address` and performs no further check. Because the request carries no signature, this is the sole authorization: the consensus layer MUST initiate an exit only when `source_address` equals the target builder's `execution_address`, or an arbitrary caller could exit a builder it does not control. A builder's only exit authorizer is therefore its `execution_address`; the voluntary-exit (BLS-key) path is removed for builders.
- **Custodial-split exit standoff.** A builder's exit precondition requires its pending balance to be zero (`get_pending_balance_to_withdraw_for_builder == 0`), every winning bid adds a pending payment, and the `execution_address` is the builder's sole exit authorizer (the BLS voluntary-exit path is removed). When the `execution_address` (the capital owner) and the BLS key (the bidding operator) are held by different parties — a custodial or staking-pool arrangement this design explicitly enables — the operator can keep the pending balance non-zero by continuing to win bids, so the capital owner cannot satisfy the exit precondition and the stake stays locked (a builder that never exits is never swept). The standoff is self-limiting, since the operator's bids must keep being included on-chain, but the protocol gives the `execution_address` holder no on-chain lever to halt bidding. Parties delegating builder operation SHOULD retain off-chain (contractual or operational) control over the operator's bidding, so a delegated builder can always be brought to a state in which it can exit.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Avoid creating requirements (defined with UPPERCASE keywords) outside of the Specification section. They're too easy to miss buried in this section. Instead, move the requirement itself to the Spec section, and discuss its security implications here.

Co-authored-by: Sam Wilson <57262657+SamWilsn@users.noreply.github.com>
SamWilsn
SamWilsn previously approved these changes Jun 30, 2026

@SamWilsn SamWilsn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please take care of the rest of these comments before moving into Review.

@eth-bot
eth-bot enabled auto-merge (squash) June 30, 2026 16:29

@eth-bot eth-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

All Reviewers Have Approved; Performing Automatic Merge...

@eth-bot eth-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

All Reviewers Have Approved; Performing Automatic Merge...

@github-actions

Copy link
Copy Markdown

The commit 2d27c03 (as a parent of 944f5f0) contains errors.
Please inspect the Run Summary for details.

Comment thread EIPS/eip-8282.md
eth-bot
eth-bot previously approved these changes Jul 2, 2026

@eth-bot eth-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

All Reviewers Have Approved; Performing Automatic Merge...

Co-authored-by: Jochem Brouwer <jochembrouwer96@gmail.com>
auto-merge was automatically disabled July 2, 2026 23:27

Head branch was pushed to by a user without write access

@wemeetagain
wemeetagain dismissed stale reviews from eth-bot and SamWilsn via 1336f2d July 2, 2026 23:27
Comment thread EIPS/eip-8282.md Outdated
@github-actions github-actions Bot removed the w-ci Waiting on CI to pass label Jul 2, 2026
@jochem-brouwer

Copy link
Copy Markdown
Member

@eth-bot rerun

@jochem-brouwer jochem-brouwer left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I am approving here to get this EIP merged, I have not done an editorial review, I have checked this extra commit 965f466 which looks fine to me. Since @SamWilsn has approved but the reviews were dismissed by a commit, will approve this here to push it through.

LGTM 😄 👍 Let's merge. @eth-bot do your thing 🎉

@eth-bot
eth-bot enabled auto-merge (squash) July 3, 2026 00:35

@eth-bot eth-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

All Reviewers Have Approved; Performing Automatic Merge...

@eth-bot
eth-bot merged commit de4c6f0 into ethereum:master Jul 3, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c-new Creates a brand new proposal e-consensus Waiting on editor consensus e-review Waiting on editor to review s-draft This EIP is a Draft t-core

Projects

None yet

Development

Successfully merging this pull request may close these issues.