execution/protocol: implement EIP-8282 Builder Execution Requests#22093
Conversation
…/erigon into worktree-gd6-eip-2780
…devnet-6-fixtures
…/erigon into worktree-gd6-eip-2780
…into worktree-gd6-eip-8038
…into feat/eip-8282-builder-requests
…into worktree-gd6-eip-8038
…into worktree-gd6-eip-8282
## Summary Catches Caplin/Gloas up with the `consensus-specs` `v1.7.0-alpha.11` execution-request and builder-request shape, while keeping the broader EL syscall/contract/devnet work in erigontech#22093. - Adds Gloas builder deposit and builder exit request handling through CL state transition, block production, CL execution-request decoding, and SSZREST getPayload encoding. - Aligns builder deposit signature domain/version handling and execution payload bid validation with alpha11 semantics. - Keeps alpha11 exited-builder top-up behavior: top-ups reset `withdrawable_epoch` for exited builders, matching the current repository spectest fixtures. - Rejects spec-invalid builder deposit transitions for balance overflow and full/unavailable builder registry instead of silently no-oping. - Uses forkchoice `get_shuffling_dependent_root` semantics for execution payload bid proposer-preference matching, avoids redundant full-state reads before bid deduplication, and keeps pending bids queued while parent state is temporarily unavailable. - Fixes Beacon API Gloas edge cases: payload-attestation SSZ request sizing is based on `PTC_SIZE`, PTC duties POST no longer has a synthetic item cap beyond the existing body bound, and queued execution payload bids return gossip `IGNORE` while waiting for dependencies/preferences. - Preserves Electra/Fulu `ExecutionRequests` SSZ/JSON/hash shape while using the Gloas request shape at Gloas-specific boundaries, including JSON `null` list handling and zero-value `ExecutionRequests` fallback behavior. - Deep-copies `ExecutionRequests.Clone()` contents, including builder request lists, to avoid mutable-list aliasing. - Aggregates payload attestations through one shared helper for API and block production, including duplicate PTC positions, out-of-PTC messages, deterministic selection, and malformed aggregate-signature groups. - Keeps only minimal shared EIP-8282 execution request type constants on the EL protocol side; broader EL syscall/contract/devnet handling remains in erigontech#22093. Refs erigontech#22008. ## Spec note The repository fixture source is currently pinned to `consensus-specs` `v1.7.0-alpha.11` in `test-fixtures.json`. A later consensus-specs master change adds the swept-only top-up predicate for exited builders (`withdrawable_epoch != FAR_FUTURE_EPOCH && balance == 0`); this PR intentionally keeps the alpha11 fixture behavior so `make -C cl/spectest gloas` stays green. ## Validation - `GOCACHE=/private/tmp/erigon-gloas-go-cache go test ./cl/beacon/handler -run 'TestPostPayloadAttestations|TestPostPtcDuties|TestAggregatePayloadAttestation' -count=1` - `GOCACHE=/private/tmp/erigon-gloas-go-cache go test ./cl/phase1/network/services -run 'TestExecutionPayloadBidService' -count=1` - `GOCACHE=/private/tmp/erigon-gloas-go-cache CGO_CFLAGS=-D__BLST_PORTABLE__ go test ./cl/transition/impl/eth2 -run 'Test.*(Attestation|Builder|Gloas|Payment)' -count=1` - `GOCACHE=/private/tmp/erigon-gloas-go-cache GOLANGCI_LINT_CACHE=/private/tmp/golangci-gloas-cache-22091-reviewfix make lint` `go test ./cl/beacon/handler ./cl/phase1/network/services -count=1` was also attempted inside the sandbox; `cl/phase1/network/services` passed, while `cl/beacon/handler` hit the sandbox's `httptest` port bind restriction in `TestGetBlobsFromFrozenSnapshots`, unrelated to this PR. ## Review `adversarial-code-review` was run with the Erigon CL / Gloas specialization and subagents until convergence. Findings addressed during the latest convergence loop: - Payload-attestation POST SSZ cap now uses `PTC_SIZE`, not `MAX_PAYLOAD_ATTESTATIONS`. - PTC duties POST no longer rejects valid large validator-index lists solely due to a synthetic item cap. - Execution payload bids queued for missing dependencies/preferences now return `ErrIgnore`, and pending bids are retained while parent state is temporarily unavailable. - Builder pending payment weight updates now accumulate locally and clone once before write-back. - Block production now delegates payload-attestation aggregation to the shared helper used by the API path. - PR scope now explicitly targets alpha11 instead of claiming current consensus-specs master semantics. Final subagent follow-up on `c9fbcf4c8a` reported no remaining Critical/High/Medium actionable findings for spec/regression/pre-fork compatibility or data-race/performance/error-boundary/corner-case safety.
…/erigon into worktree-gd6-eip-2780
There was a problem hiding this comment.
Pull request overview
Adds execution-layer support for EIP-8282 “Builder Execution Requests” (builder deposit / builder exit) under the Amsterdam fork, including new request types, system-contract predeploy wiring for tests/dev chains, and Merge rule updates to dequeue and hash these requests.
Changes:
- Add EIP-8282 request type constants (0x03/0x04) and extend known request types.
- Dequeue builder deposit/exit requests in Merge finalization when Amsterdam is active; introduce EIP-8282 system contract bytecode/constants and basic tests.
- Update dev genesis allocs and multiple test harnesses to predeploy the Amsterdam system contracts.
Reviewed changes
Copilot reviewed 14 out of 15 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/eest-spec-shards.yml | Adjust EEST shard failure thresholds. |
| execution/types/eip7685_requests.go | Add builder deposit/exit request type constants; extend known types list. |
| execution/tests/blockgen/chain_makers.go | Add Amsterdam predeploy helper for builder contracts in test chains. |
| execution/protocol/rules/merge/merge.go | Dequeue builder deposit/exit requests during Finalize under Amsterdam and include in requests hash. |
| execution/protocol/params/protocol.go | Define default builder deposit/exit predeploy addresses. |
| execution/protocol/misc/eip8282.go | Add builder deposit/exit contract bytecode and dequeue helpers. |
| execution/protocol/misc/eip8282_test.go | Add tests for system-contract registration and dequeue empty-code guardrails. |
| execution/execmodule/execmoduletester/exec_module_tester.go | Ensure Amsterdam system contracts are deployed at genesis when Amsterdam is scheduled. |
| execution/engineapi/sszrest_wire.go | Update SSZ REST encoding path for execution requests (currently drops EIP-8282 types). |
| execution/engineapi/engineapitester/engine_api_tester.go | Include builder contracts in engine-api tester genesis alloc. |
| execution/chain/spec/allocs/hoodi.json | Formatting-only change at EOF. |
| execution/chain/spec/allocs/dev.json | Add builder deposit/exit predeploy accounts (code + storage) to dev alloc. |
| execution/chain/chain_config.go | Add chain-config fields + SystemContracts() entries and accessors for builder contract addresses. |
| cl/cltypes/execution_requests.go | Add TODO note for extending CL ExecutionRequests to include builder_* lists. |
| .github/workflows/test-hive-eest.yml | Adjust hive-eest max failure threshold. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…into worktree-gd6-eip-8038
yperbasis
left a comment
There was a problem hiding this comment.
Verified against the devnet-6 pin (EELS d0338f56, fixtures tests-glamsterdam-devnet@v6.1.1) and the canonical devnet-6 genesis (ethpandaops/glamsterdam-devnets network configs): both predeploy addresses and both embedded bytecodes are byte-identical to the pin (incl. nonce 1 and the slot-0 inhibitor in dev.json), and the checked-syscall semantics plus 0x00→0x04 request ordering match pinned EELS process_general_purpose_requests. The res != nil (vs len > 0) corner is safe — FlatRequests.Hash() skips zero-length data. Notes:
- Spec drift heads-up: EIP-8282 on EIPs master now pins different addresses (
0x0000bFF4…0D8282/0x000064D6…0E8282) — the reference bytecode was revised after the devnet-6 pin, changing the Nick's-method addresses. Nothing to change here, but devnet-7 will need new bytecode + addresses inparams,misc,dev.jsonand the testers; worth a tracking note. Same text-ahead-of-pin pattern as EIP-2780/8038. - Rebase hazard: the
sszrest_wire.gosilent-ignore of 0x03/0x04 and thecl/cltypesTODO are stale-base shims — main already has the 5-list Gloas container (#22091) and replacedexecutionRequestsFromListwithcltypes.DecodeExecutionRequestsList. Both hunks must be dropped when the stack rebases; please leave a note so the silent drop can't survive conflict resolution. This also supersedes Copilot's "return an error until cltypes is extended" — cltypes is already extended on main, and erroring on this branch would break every Gloas getPayload carrying builder requests. - Copilot's engine-api tester comment is right in substance: the canonical genesis and this PR's own
dev.jsonset the slot-0 inhibitor on both contracts, but the tester sets it only on the deposit entry — give the exit entry the same slot-0 value. (Impact is fee/acceptance before the first syscall, not dequeue semantics.) - Copilot's
InitAmsterdamPreDeployscomment (ignoredUpdateAccountData/UpdateAccountCodeerrors, no inhibitor/nonce) is true but inherited verbatim fromInitPraguePreDeploys— fix both helpers together or defer both; don't patch just one. - Optional: a positive-path unit test (enqueue via calldata against the embedded bytecode → syscall → assert the 184/68-byte record and type prefix) would pin the bytecode's behavior rather than just its presence; EEST covers it end-to-end.
Trivia: stray blank line in merge.go Initialize.
thanks, addressed in 2cc2121
|
…into worktree-gd6-eip-8282
continuation of #21844
merge after #22060
for #22008
EIP-8282
0x0000884d2AA32eAa155F59A2f24eFa73D90082820x000014574A74c805590AFF9499fc7A690f008282#22008
https://notes.ethereum.org/@ethpandaops/glamsterdam-devnet-6