11import { ChainForkConfig } from "@lodestar/config" ;
2- import { ForkName , isForkPostDeneb , isForkPostFulu } from "@lodestar/params" ;
3- import { Epoch , RootHex , Slot , phase0 } from "@lodestar/types" ;
2+ import { ForkName , isForkPostDeneb , isForkPostFulu , isForkPostGloas } from "@lodestar/params" ;
3+ import { Epoch , RootHex , Slot , gloas , phase0 } from "@lodestar/types" ;
44import { LodestarError } from "@lodestar/utils" ;
55import { isBlockInputColumns } from "../../chain/blocks/blockInput/blockInput.js" ;
66import { IBlockInput } from "../../chain/blocks/blockInput/types.js" ;
@@ -46,19 +46,21 @@ export type Attempt = {
4646export type AwaitingDownloadState = {
4747 status : BatchStatus . AwaitingDownload ;
4848 blocks : IBlockInput [ ] ;
49+ payloadEnvelopes : Map < Slot , gloas . SignedExecutionPayloadEnvelope > | null ;
4950} ;
5051
5152export type DownloadSuccessState = {
5253 status : BatchStatus . AwaitingProcessing ;
5354 blocks : IBlockInput [ ] ;
55+ payloadEnvelopes : Map < Slot , gloas . SignedExecutionPayloadEnvelope > | null ;
5456} ;
5557
5658export type BatchState =
5759 | AwaitingDownloadState
58- | { status : BatchStatus . Downloading ; peer : PeerIdStr ; blocks : IBlockInput [ ] }
60+ | { status : BatchStatus . Downloading ; peer : PeerIdStr ; blocks : IBlockInput [ ] ; payloadEnvelopes : Map < Slot , gloas . SignedExecutionPayloadEnvelope > | null }
5961 | DownloadSuccessState
60- | { status : BatchStatus . Processing ; blocks : IBlockInput [ ] ; attempt : Attempt }
61- | { status : BatchStatus . AwaitingValidation ; blocks : IBlockInput [ ] ; attempt : Attempt } ;
62+ | { status : BatchStatus . Processing ; blocks : IBlockInput [ ] ; payloadEnvelopes : Map < Slot , gloas . SignedExecutionPayloadEnvelope > | null ; attempt : Attempt }
63+ | { status : BatchStatus . AwaitingValidation ; blocks : IBlockInput [ ] ; payloadEnvelopes : Map < Slot , gloas . SignedExecutionPayloadEnvelope > | null ; attempt : Attempt } ;
6264
6365export type BatchMetadata = {
6466 startEpoch : Epoch ;
@@ -85,7 +87,7 @@ export class Batch {
8587 /** Block, blob and column requests that are used to determine the best peer and are used in downloadByRange */
8688 requests : DownloadByRangeRequests ;
8789 /** State of the batch. */
88- state : BatchState = { status : BatchStatus . AwaitingDownload , blocks : [ ] } ;
90+ state : BatchState = { status : BatchStatus . AwaitingDownload , blocks : [ ] , payloadEnvelopes : null } ;
8991 /** Peers that provided good data */
9092 goodPeers : PeerIdStr [ ] = [ ] ;
9193 /** The `Attempts` that have been made and failed to send us this batch. */
@@ -129,6 +131,10 @@ export class Batch {
129131 count : this . count ,
130132 step : 1 ,
131133 } ;
134+ const envelopesRequest : gloas . ExecutionPayloadEnvelopesByRangeRequest | undefined = isForkPostGloas ( this . forkName )
135+ ? { startSlot : this . startSlot , count : this . count }
136+ : undefined ;
137+
132138 if ( isForkPostFulu ( this . forkName ) && withinValidRequestWindow ) {
133139 return {
134140 blocksRequest,
@@ -137,6 +143,7 @@ export class Batch {
137143 count : this . count ,
138144 columns : this . custodyConfig . sampledColumns ,
139145 } ,
146+ envelopesRequest,
140147 } ;
141148 }
142149 if ( isForkPostDeneb ( this . forkName ) && withinValidRequestWindow ) {
@@ -146,10 +153,12 @@ export class Batch {
146153 startSlot : this . startSlot ,
147154 count : this . count ,
148155 } ,
156+ envelopesRequest,
149157 } ;
150158 }
151159 return {
152160 blocksRequest,
161+ envelopesRequest,
153162 } ;
154163 }
155164
@@ -186,6 +195,18 @@ export class Batch {
186195 }
187196 }
188197
198+ // Track envelope start slot for post-Gloas forks
199+ let envelopeStartSlot = this . startSlot ;
200+ if ( isForkPostGloas ( this . forkName ) ) {
201+ for ( const blockInput of blocks ) {
202+ const blockSlot = blockInput . slot ;
203+ // Envelopes track separately - advance start slot for contiguous downloaded envelopes
204+ if ( envelopeStartSlot === blockSlot ) {
205+ envelopeStartSlot = blockSlot + 1 ;
206+ }
207+ }
208+ }
209+
189210 // if the blockStartSlot or dataStartSlot is after the desired endSlot then no request will be made for the batch
190211 // because it is complete
191212 const endSlot = this . startSlot + this . count - 1 ;
@@ -216,6 +237,13 @@ export class Batch {
216237 // dataSlot will still have a value but do not create a request for preDeneb forks
217238 }
218239
240+ if ( isForkPostGloas ( this . forkName ) && envelopeStartSlot <= endSlot ) {
241+ requests . envelopesRequest = {
242+ startSlot : envelopeStartSlot ,
243+ count : endSlot - envelopeStartSlot + 1 ,
244+ } ;
245+ }
246+
219247 return requests ;
220248 }
221249
@@ -263,6 +291,10 @@ export class Batch {
263291 return this . state . blocks ;
264292 }
265293
294+ getPayloadEnvelopes ( ) : Map < Slot , gloas . SignedExecutionPayloadEnvelope > | null {
295+ return this . state . payloadEnvelopes ;
296+ }
297+
266298 /**
267299 * AwaitingDownload -> Downloading
268300 */
@@ -271,13 +303,13 @@ export class Batch {
271303 throw new BatchError ( this . wrongStatusErrorType ( BatchStatus . AwaitingDownload ) ) ;
272304 }
273305
274- this . state = { status : BatchStatus . Downloading , peer, blocks : this . state . blocks } ;
306+ this . state = { status : BatchStatus . Downloading , peer, blocks : this . state . blocks , payloadEnvelopes : this . state . payloadEnvelopes } ;
275307 }
276308
277309 /**
278310 * Downloading -> AwaitingProcessing
279311 */
280- downloadingSuccess ( peer : PeerIdStr , blocks : IBlockInput [ ] ) : DownloadSuccessState {
312+ downloadingSuccess ( peer : PeerIdStr , blocks : IBlockInput [ ] , payloadEnvelopes : Map < Slot , gloas . SignedExecutionPayloadEnvelope > | null ) : DownloadSuccessState {
281313 if ( this . state . status !== BatchStatus . Downloading ) {
282314 throw new BatchError ( this . wrongStatusErrorType ( BatchStatus . Downloading ) ) ;
283315 }
@@ -305,11 +337,13 @@ export class Batch {
305337 status : this . state . status ,
306338 } ) ;
307339 }
340+ const newPayloadEnvelopes = payloadEnvelopes ?? this . state . payloadEnvelopes ;
341+
308342 if ( allComplete ) {
309- this . state = { status : BatchStatus . AwaitingProcessing , blocks} ;
343+ this . state = { status : BatchStatus . AwaitingProcessing , blocks, payloadEnvelopes : newPayloadEnvelopes } ;
310344 } else {
311345 this . requests = this . getRequests ( blocks ) ;
312- this . state = { status : BatchStatus . AwaitingDownload , blocks} ;
346+ this . state = { status : BatchStatus . AwaitingDownload , blocks, payloadEnvelopes : newPayloadEnvelopes } ;
313347 }
314348
315349 return this . state as DownloadSuccessState ;
@@ -328,25 +362,26 @@ export class Batch {
328362 throw new BatchError ( this . errorType ( { code : BatchErrorCode . MAX_DOWNLOAD_ATTEMPTS } ) ) ;
329363 }
330364
331- this . state = { status : BatchStatus . AwaitingDownload , blocks : this . state . blocks } ;
365+ this . state = { status : BatchStatus . AwaitingDownload , blocks : this . state . blocks , payloadEnvelopes : this . state . payloadEnvelopes } ;
332366 }
333367
334368 /**
335369 * AwaitingProcessing -> Processing
336370 */
337- startProcessing ( ) : IBlockInput [ ] {
371+ startProcessing ( ) : { blocks : IBlockInput [ ] ; payloadEnvelopes : Map < Slot , gloas . SignedExecutionPayloadEnvelope > | null } {
338372 if ( this . state . status !== BatchStatus . AwaitingProcessing ) {
339373 throw new BatchError ( this . wrongStatusErrorType ( BatchStatus . AwaitingProcessing ) ) ;
340374 }
341375
342376 const blocks = this . state . blocks ;
377+ const payloadEnvelopes = this . state . payloadEnvelopes ;
343378 const hash = hashBlocks ( blocks , this . config ) ; // tracks blocks to report peer on processing error
344379 // Reset goodPeers in case another download attempt needs to be made. When Attempt is successful or not the peers
345380 // that the data came from will be handled by the Attempt that goes for processing
346381 const peers = this . goodPeers ;
347382 this . goodPeers = [ ] ;
348- this . state = { status : BatchStatus . Processing , blocks, attempt : { peers, hash} } ;
349- return blocks ;
383+ this . state = { status : BatchStatus . Processing , blocks, payloadEnvelopes , attempt : { peers, hash} } ;
384+ return { blocks, payloadEnvelopes } ;
350385 }
351386
352387 /**
@@ -357,7 +392,7 @@ export class Batch {
357392 throw new BatchError ( this . wrongStatusErrorType ( BatchStatus . Processing ) ) ;
358393 }
359394
360- this . state = { status : BatchStatus . AwaitingValidation , blocks : this . state . blocks , attempt : this . state . attempt } ;
395+ this . state = { status : BatchStatus . AwaitingValidation , blocks : this . state . blocks , payloadEnvelopes : this . state . payloadEnvelopes , attempt : this . state . attempt } ;
361396 }
362397
363398 /**
@@ -408,7 +443,7 @@ export class Batch {
408443
409444 // remove any downloaded blocks and re-attempt
410445 // TODO(fulu): need to remove the bad blocks from the SeenBlockInputCache
411- this . state = { status : BatchStatus . AwaitingDownload , blocks : [ ] } ;
446+ this . state = { status : BatchStatus . AwaitingDownload , blocks : [ ] , payloadEnvelopes : null } ;
412447 }
413448
414449 private onProcessingError ( attempt : Attempt ) : void {
@@ -419,7 +454,7 @@ export class Batch {
419454
420455 // remove any downloaded blocks and re-attempt
421456 // TODO(fulu): need to remove the bad blocks from the SeenBlockInputCache
422- this . state = { status : BatchStatus . AwaitingDownload , blocks : [ ] } ;
457+ this . state = { status : BatchStatus . AwaitingDownload , blocks : [ ] , payloadEnvelopes : null } ;
423458 }
424459
425460 /** Helper to construct typed BatchError. Stack traces are correct as the error is thrown above */
0 commit comments