From 38b476bf97b7b4d5b090e02ad03f7e265c0d7f29 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Tue, 7 Jul 2026 11:23:57 +0100 Subject: [PATCH 1/3] fix: use Gloas deposit request SSZ for engine API --- .../beacon-node/src/execution/engine/types.ts | 23 ++++++++++++++----- .../test/unit/execution/engine/types.test.ts | 19 +++++++++++++++ 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index 5d13fa235c58..3907045cb25c 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -510,13 +510,24 @@ function prefixRequests(requestsBytes: Uint8Array, requestType: ExecutionRequest return prefixedRequests; } -function serializeDepositRequests(depositRequests: electra.DepositRequests): DepositRequestsRpc { - const requestsBytes = ssz.electra.DepositRequests.serialize(depositRequests); +function serializeDepositRequests( + fork: ForkName, + depositRequests: electra.DepositRequests | gloas.DepositRequests +): DepositRequestsRpc { + const requestsBytes = + ForkSeq[fork] >= ForkSeq.gloas + ? ssz.gloas.DepositRequests.serialize(depositRequests) + : ssz.electra.DepositRequests.serialize(depositRequests); return bytesToData(prefixRequests(requestsBytes, DEPOSIT_REQUEST_TYPE)); } -function deserializeDepositRequests(serialized: DepositRequestsRpc): electra.DepositRequests { - return ssz.electra.DepositRequests.deserialize(dataToBytes(serialized, null)); +function deserializeDepositRequests( + fork: ForkName, + serialized: DepositRequestsRpc +): electra.DepositRequests | gloas.DepositRequests { + return ForkSeq[fork] >= ForkSeq.gloas + ? ssz.gloas.DepositRequests.deserialize(dataToBytes(serialized, null)) + : ssz.electra.DepositRequests.deserialize(dataToBytes(serialized, null)); } function serializeWithdrawalRequests(withdrawalRequests: electra.WithdrawalRequests): WithdrawalRequestsRpc { @@ -571,7 +582,7 @@ export function serializeExecutionRequests(fork: ForkName, executionRequests: Ex const result: ExecutionRequestsRpc = []; if (deposits.length !== 0) { - result.push(serializeDepositRequests(deposits)); + result.push(serializeDepositRequests(fork, deposits)); } if (withdrawals.length !== 0) { @@ -637,7 +648,7 @@ export function deserializeExecutionRequests(fork: ForkName, serialized: Executi switch (currentRequestType) { case DEPOSIT_REQUEST_TYPE: { - result.deposits = deserializeDepositRequests(requests); + result.deposits = deserializeDepositRequests(fork, requests); break; } case WITHDRAWAL_REQUEST_TYPE: { diff --git a/packages/beacon-node/test/unit/execution/engine/types.test.ts b/packages/beacon-node/test/unit/execution/engine/types.test.ts index f8a8a91b15f8..99e638feb538 100644 --- a/packages/beacon-node/test/unit/execution/engine/types.test.ts +++ b/packages/beacon-node/test/unit/execution/engine/types.test.ts @@ -5,6 +5,7 @@ import { CONSOLIDATION_REQUEST_TYPE, DEPOSIT_REQUEST_TYPE, ForkName, + MAX_DEPOSIT_REQUESTS_PER_PAYLOAD, WITHDRAWAL_REQUEST_TYPE, } from "@lodestar/params"; import {ExecutionRequests, gloas, ssz} from "@lodestar/types"; @@ -75,6 +76,24 @@ describe("execution / engine / types", () => { expect(serialized.length).toBe(0); }); + it("should serialize Gloas deposit requests beyond the Electra limit", () => { + const expectedLength = MAX_DEPOSIT_REQUESTS_PER_PAYLOAD + 1; + const executionRequests: gloas.ExecutionRequests = { + deposits: Array.from({length: expectedLength}, () => ssz.gloas.DepositRequest.defaultValue()), + withdrawals: [], + consolidations: [], + builderDeposits: [], + builderExits: [], + }; + + const serialized = serializeExecutionRequests(ForkName.gloas, executionRequests); + const deserialized = deserializeExecutionRequests(ForkName.gloas, serialized) as gloas.ExecutionRequests; + + expect(serialized.length).toBe(1); + expect(deserialized.deposits.length).toBe(expectedLength); + expect(serializeExecutionRequests(ForkName.gloas, deserialized)).toEqual(serialized); + }); + it("should serialize builder requests post-gloas", () => { const executionRequests: gloas.ExecutionRequests = { deposits: [], From 0d121c5bb8008dfb1df51af7f5ae18ad140364b6 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Tue, 7 Jul 2026 11:30:24 +0100 Subject: [PATCH 2/3] fix: remove Gloas deposit request count checks --- packages/beacon-node/src/chain/validation/block.ts | 3 --- .../src/chain/validation/executionPayloadEnvelope.ts | 4 +--- packages/params/src/presets/mainnet.ts | 2 +- packages/params/src/presets/minimal.ts | 2 +- .../src/block/processParentExecutionPayload.ts | 2 -- 5 files changed, 3 insertions(+), 10 deletions(-) diff --git a/packages/beacon-node/src/chain/validation/block.ts b/packages/beacon-node/src/chain/validation/block.ts index eda33e46e76f..6c1ebb9595b1 100644 --- a/packages/beacon-node/src/chain/validation/block.ts +++ b/packages/beacon-node/src/chain/validation/block.ts @@ -8,7 +8,6 @@ import { MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD, MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD, - MAX_DEPOSIT_REQUESTS_PER_PAYLOAD, MAX_PAYLOAD_ATTESTATIONS, MAX_PROPOSER_SLASHINGS, MAX_VOLUNTARY_EXITS, @@ -182,7 +181,6 @@ export async function validateGossipBlock( // [REJECT] The counts of `block.body.parent_execution_requests` are within // their respective limits -- i.e. validate that - // `len(block.body.parent_execution_requests.deposits) <= MAX_DEPOSIT_REQUESTS_PER_PAYLOAD`, // `len(block.body.parent_execution_requests.withdrawals) <= MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD`, // `len(block.body.parent_execution_requests.consolidations) <= MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD`, // `len(block.body.parent_execution_requests.builder_deposits) <= MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD`, @@ -200,7 +198,6 @@ export async function validateGossipBlock( const body = (block as gloas.BeaconBlock).body; const requests = body.parentExecutionRequests; const countLimits: [string, number, number][] = [ - ["parentExecutionRequests.deposits", requests.deposits.length, MAX_DEPOSIT_REQUESTS_PER_PAYLOAD], ["parentExecutionRequests.withdrawals", requests.withdrawals.length, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD], [ "parentExecutionRequests.consolidations", diff --git a/packages/beacon-node/src/chain/validation/executionPayloadEnvelope.ts b/packages/beacon-node/src/chain/validation/executionPayloadEnvelope.ts index 2eb94d6cb337..56d74f0c6aa3 100644 --- a/packages/beacon-node/src/chain/validation/executionPayloadEnvelope.ts +++ b/packages/beacon-node/src/chain/validation/executionPayloadEnvelope.ts @@ -3,7 +3,6 @@ import { MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD, MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD, - MAX_DEPOSIT_REQUESTS_PER_PAYLOAD, MAX_WITHDRAWALS_PER_PAYLOAD, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, } from "@lodestar/params"; @@ -123,12 +122,11 @@ async function validateExecutionPayloadEnvelope( }); } - // [REJECT] The counts of `execution_requests` are within their respective limits. + // [REJECT] The non-deposit counts of `execution_requests` are within their respective limits. // New in Gloas:EIP7688 — progressive lists are unbounded at the type level, so bounds // are enforced here in gossip validation. const {executionRequests} = envelope; const requestCountLimits: [string, number, number][] = [ - ["deposits", executionRequests.deposits.length, MAX_DEPOSIT_REQUESTS_PER_PAYLOAD], ["withdrawals", executionRequests.withdrawals.length, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD], ["consolidations", executionRequests.consolidations.length, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD], ["builderDeposits", executionRequests.builderDeposits.length, MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD], diff --git a/packages/params/src/presets/mainnet.ts b/packages/params/src/presets/mainnet.ts index ebaf9a880717..d761a6212366 100644 --- a/packages/params/src/presets/mainnet.ts +++ b/packages/params/src/presets/mainnet.ts @@ -156,5 +156,5 @@ export const mainnetPreset: BeaconPreset = { MAX_DATA_COLUMN_SIDECAR_SIZE: 8585272, MAX_PARTIAL_DATA_COLUMN_SIDECAR_SIZE: 8585741, MAX_SIGNED_EXECUTION_PAYLOAD_BID_SIZE: 196932, - MAX_SIGNED_BEACON_BLOCK_SIZE: 4027336, + MAX_SIGNED_BEACON_BLOCK_SIZE: 10134472, }; diff --git a/packages/params/src/presets/minimal.ts b/packages/params/src/presets/minimal.ts index 28faa66f2a4a..2f436ab377d8 100644 --- a/packages/params/src/presets/minimal.ts +++ b/packages/params/src/presets/minimal.ts @@ -157,5 +157,5 @@ export const minimalPreset: BeaconPreset = { MAX_DATA_COLUMN_SIDECAR_SIZE: 8585272, MAX_PARTIAL_DATA_COLUMN_SIDECAR_SIZE: 8585741, MAX_SIGNED_EXECUTION_PAYLOAD_BID_SIZE: 196932, - MAX_SIGNED_BEACON_BLOCK_SIZE: 1938012, + MAX_SIGNED_BEACON_BLOCK_SIZE: 8045148, }; diff --git a/packages/state-transition/src/block/processParentExecutionPayload.ts b/packages/state-transition/src/block/processParentExecutionPayload.ts index e863a4bd3f3b..dc00b09700fa 100644 --- a/packages/state-transition/src/block/processParentExecutionPayload.ts +++ b/packages/state-transition/src/block/processParentExecutionPayload.ts @@ -3,7 +3,6 @@ import { MAX_BUILDER_DEPOSIT_REQUESTS_PER_PAYLOAD, MAX_BUILDER_EXIT_REQUESTS_PER_PAYLOAD, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD, - MAX_DEPOSIT_REQUESTS_PER_PAYLOAD, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD, SLOTS_PER_EPOCH, SLOTS_PER_HISTORICAL_ROOT, @@ -128,7 +127,6 @@ function settleBuilderPayment(state: CachedBeaconStateGloas, paymentIndex: numbe } function assertExecutionRequestsWithinLimits(requests: gloas.ExecutionRequests): void { - assertMaxLength("deposits", requests.deposits.length, MAX_DEPOSIT_REQUESTS_PER_PAYLOAD); assertMaxLength("withdrawals", requests.withdrawals.length, MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD); assertMaxLength("consolidations", requests.consolidations.length, MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD); // New in GLOAS:EIP8282 From ec7a97002f7161cf89e5e8388335051497f718c2 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Tue, 7 Jul 2026 17:51:04 +0100 Subject: [PATCH 3/3] fix: remove Gloas signed beacon block size --- packages/beacon-node/src/network/gossip/topic.ts | 5 ++--- .../test/unit/network/gossip/topic.test.ts | 3 +-- packages/params/src/index.ts | 1 - packages/params/src/presets/mainnet.ts | 1 - packages/params/src/presets/minimal.ts | 1 - packages/params/src/types.ts | 2 -- packages/validator/src/util/params.ts | 1 - specrefs/.ethspecify.yml | 1 - specrefs/functions.yml | 5 ----- specrefs/presets.yml | 16 ---------------- 10 files changed, 3 insertions(+), 33 deletions(-) diff --git a/packages/beacon-node/src/network/gossip/topic.ts b/packages/beacon-node/src/network/gossip/topic.ts index 2e98b10d1221..ec1b05bd20a9 100644 --- a/packages/beacon-node/src/network/gossip/topic.ts +++ b/packages/beacon-node/src/network/gossip/topic.ts @@ -7,7 +7,6 @@ import { MAX_ATTESTER_SLASHING_SIZE, MAX_DATA_COLUMN_SIDECAR_SIZE, MAX_SIGNED_AGGREGATE_AND_PROOF_SIZE, - MAX_SIGNED_BEACON_BLOCK_SIZE, MAX_SIGNED_EXECUTION_PAYLOAD_BID_SIZE, SYNC_COMMITTEE_SUBNET_COUNT, isForkPostAltair, @@ -142,10 +141,10 @@ export function getGossipSSZType(topic: GossipTopic): CompositeTypeAny { */ export function getGossipSSZMaxSize(topic: GossipTopic, maxPayloadSize: number, sszType?: CompositeTypeAny): number { const {fork} = topic.boundary; - // Gloas progressive containers have broad theoretical SSZ max sizes; use the preset p2p bounds instead. + // Gloas progressive containers have broad theoretical SSZ max sizes; use preset p2p bounds where specified. switch (topic.type) { case GossipType.beacon_block: - return isForkPostGloas(fork) ? MAX_SIGNED_BEACON_BLOCK_SIZE : maxPayloadSize; + return maxPayloadSize; case GossipType.beacon_aggregate_and_proof: return isForkPostGloas(fork) ? MAX_SIGNED_AGGREGATE_AND_PROOF_SIZE : (sszType ?? getGossipSSZType(topic)).maxSize; case GossipType.attester_slashing: diff --git a/packages/beacon-node/test/unit/network/gossip/topic.test.ts b/packages/beacon-node/test/unit/network/gossip/topic.test.ts index 826b9c56e93c..ecebf2d40ab1 100644 --- a/packages/beacon-node/test/unit/network/gossip/topic.test.ts +++ b/packages/beacon-node/test/unit/network/gossip/topic.test.ts @@ -7,7 +7,6 @@ import { MAX_ATTESTER_SLASHING_SIZE, MAX_DATA_COLUMN_SIDECAR_SIZE, MAX_SIGNED_AGGREGATE_AND_PROOF_SIZE, - MAX_SIGNED_BEACON_BLOCK_SIZE, MAX_SIGNED_EXECUTION_PAYLOAD_BID_SIZE, ZERO_HASH, } from "@lodestar/params"; @@ -267,7 +266,7 @@ describe("network / gossip / topic", () => { config.MAX_PAYLOAD_SIZE ), }).toEqual({ - [GossipType.beacon_block]: MAX_SIGNED_BEACON_BLOCK_SIZE, + [GossipType.beacon_block]: config.MAX_PAYLOAD_SIZE, [GossipType.data_column_sidecar]: MAX_DATA_COLUMN_SIDECAR_SIZE, [GossipType.beacon_aggregate_and_proof]: MAX_SIGNED_AGGREGATE_AND_PROOF_SIZE, [GossipType.attester_slashing]: MAX_ATTESTER_SLASHING_SIZE, diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index 4388cb7473ed..d034f82948ba 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -125,7 +125,6 @@ export const { MAX_DATA_COLUMN_SIDECAR_SIZE, MAX_PARTIAL_DATA_COLUMN_SIDECAR_SIZE, MAX_SIGNED_EXECUTION_PAYLOAD_BID_SIZE, - MAX_SIGNED_BEACON_BLOCK_SIZE, } = activePreset; //////////// diff --git a/packages/params/src/presets/mainnet.ts b/packages/params/src/presets/mainnet.ts index d761a6212366..c1a325207167 100644 --- a/packages/params/src/presets/mainnet.ts +++ b/packages/params/src/presets/mainnet.ts @@ -156,5 +156,4 @@ export const mainnetPreset: BeaconPreset = { MAX_DATA_COLUMN_SIDECAR_SIZE: 8585272, MAX_PARTIAL_DATA_COLUMN_SIDECAR_SIZE: 8585741, MAX_SIGNED_EXECUTION_PAYLOAD_BID_SIZE: 196932, - MAX_SIGNED_BEACON_BLOCK_SIZE: 10134472, }; diff --git a/packages/params/src/presets/minimal.ts b/packages/params/src/presets/minimal.ts index 2f436ab377d8..0c7be8b39e6c 100644 --- a/packages/params/src/presets/minimal.ts +++ b/packages/params/src/presets/minimal.ts @@ -157,5 +157,4 @@ export const minimalPreset: BeaconPreset = { MAX_DATA_COLUMN_SIDECAR_SIZE: 8585272, MAX_PARTIAL_DATA_COLUMN_SIDECAR_SIZE: 8585741, MAX_SIGNED_EXECUTION_PAYLOAD_BID_SIZE: 196932, - MAX_SIGNED_BEACON_BLOCK_SIZE: 8045148, }; diff --git a/packages/params/src/types.ts b/packages/params/src/types.ts index 84bc91d92b8b..49ca04d27d2f 100644 --- a/packages/params/src/types.ts +++ b/packages/params/src/types.ts @@ -115,7 +115,6 @@ export type BeaconPreset = { MAX_DATA_COLUMN_SIDECAR_SIZE: number; MAX_PARTIAL_DATA_COLUMN_SIDECAR_SIZE: number; MAX_SIGNED_EXECUTION_PAYLOAD_BID_SIZE: number; - MAX_SIGNED_BEACON_BLOCK_SIZE: number; }; /** @@ -236,7 +235,6 @@ export const beaconPresetTypes: BeaconPresetTypes = { MAX_DATA_COLUMN_SIDECAR_SIZE: "number", MAX_PARTIAL_DATA_COLUMN_SIDECAR_SIZE: "number", MAX_SIGNED_EXECUTION_PAYLOAD_BID_SIZE: "number", - MAX_SIGNED_BEACON_BLOCK_SIZE: "number", }; type BeaconPresetTypes = { diff --git a/packages/validator/src/util/params.ts b/packages/validator/src/util/params.ts index 8cf54c31e4b6..258cf6624388 100644 --- a/packages/validator/src/util/params.ts +++ b/packages/validator/src/util/params.ts @@ -332,7 +332,6 @@ function getSpecCriticalParams(localConfig: ChainConfig): Record -- name: MAX_SIGNED_BEACON_BLOCK_SIZE#gloas - sources: - - file: packages/params/src/presets/mainnet.ts - search: "MAX_SIGNED_BEACON_BLOCK_SIZE:" - spec: | - - MAX_SIGNED_BEACON_BLOCK_SIZE: uint64 = 4027336 - - -- name: MAX_SIGNED_BEACON_BLOCK_SIZE_HEZE#heze - sources: [] - spec: | - - MAX_SIGNED_BEACON_BLOCK_SIZE_HEZE: uint64 = 4027338 - - - name: MAX_SIGNED_EXECUTION_PAYLOAD_BID_SIZE#gloas sources: - file: packages/params/src/presets/mainnet.ts