execution/engineapi: validate getPayload fork boundaries and blob bundle counts - #22985
Conversation
There was a problem hiding this comment.
Pull request overview
This PR tightens EngineServer.getPayload fork-version invariants so the selected Engine API payload schema cannot cross fork boundaries (now including Paris↔Shanghai), and extends blobs-bundle structural validation to cover Amsterdam (and later) payload versions.
Changes:
- Enforce Shanghai-era schema matching in
getPayload(reject Paris/Shanghai mismatches via timestamp↔version checks). - Apply blobs bundle length validation for Amsterdam+ versions by broadening the guard from
== Fuluto>= Fulu. - Add regression tests covering Paris/Shanghai mismatches and invalid Amsterdam blobs bundle structure.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
execution/engineapi/engine_server.go |
Adds Shanghai fork boundary enforcement in getPayload and ensures blobs-bundle validation runs for newer payload versions. |
execution/engineapi/engine_server_getpayload_test.go |
Adds regression tests for fork/schema mismatches and Amsterdam blobs-bundle structural validation; refactors server construction helper to accept custom configs. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
BlobsBundleFromTransactions always returns a non-nil bundle with initialized empty slices, so the nil branch was unreachable and the empty-bundle requirement of engine_getPayloadV5/V6 is already satisfied at construction.
|
Reviewed at The dead nil-fill removal is safe. The widened The new tests really guard the fix. I reverted both production hunks in a scratch worktree and re-ran: Three things worth addressing: 1. The Shanghai clause is deliberately asymmetric and nothing says so. Every other fork appears as a pair — 2. BlobsBundleV1 is still unvalidated. The PR title says "validate ... blob bundles", but the length check only runs for Osaka and later. Deneb/Electra ( 3. Missing the complement test. The risk introduced by a new rejection rule is over-rejection. That is covered for V2/Paris but not for V1/Paris. Nits, take or leave:
|
…overage Comment the deliberate absence of an exact-match check at Shanghai, derive parisShanghaiChainConfig from preCancunChainConfig, and add TestGetPayloadV2AcceptsShanghaiPayload so both sides of the boundary-spanning getPayloadV2 contract are pinned.
… versions Extend the bundle count check from Fulu-only to every getPayload version that returns a bundle: len(commitments) == len(blobs) == len(proofs) for BlobsBundleV1 (Deneb, Electra), and CELLS_PER_EXT_BLOB cell proofs per blob for BlobsBundleV2 (Fulu, Gloas).
Test-only: guards the new Shanghai rejection clause against over-rejection on the Paris side of the boundary.
|
Thanks for the thorough review — all three points are addressed: Point 1 — landed in 49d90d1 (crossed with your review in flight): the gate now carries a comment stating that Shanghai, unlike later forks, does not require an exact version match because Point 2 — a7dedba extends the count check to every version that returns a bundle: Point 3 — cf0ef24 adds On the nits: amsterdam.md says "This method is updated to return the new |
Summary
engine_getPayloadV1for Shanghai-and-later payloads while keepingengine_getPayloadV2valid on both sides of the Shanghai boundaryBlobsBundleV1fromengine_getPayloadV3/V4(Cancun/Prague) has equal commitment, blob, and proof countsBlobsBundleV2fromengine_getPayloadV5/V6(Osaka/Amsterdam) has equal commitment/blob counts andCELLS_PER_EXT_BLOBcell proofs per blobGetPayloadV4andGetPayloadV6comments to match the response structures defined by the specificationsWhy
Erigon payload IDs are monotonically allocated identifiers; they do not encode the Engine API version used to start the build.
getPayloadmust therefore validate the built payload's timestamp against the requested endpoint. V2 intentionally spans Paris and Shanghai, whereas V1 and V3–V6 must stay within their respective fork windows.Every response that carries a blob bundle must satisfy the count invariant of its bundle version.
BlobsBundleV1requires equal commitment, blob, and proof counts.BlobsBundleV2requires equal commitment/blob counts andCELLS_PER_EXT_BLOBproofs per blob.BlobsBundleFromTransactionsalways returns a non-nil bundle with initialized slices, including for an empty bundle.Testing
go test ./execution/engineapi/... -count=1make lint(repeated)make erigon integration