@lodestar/beacon-node 1.43.0-dev.ca1fc40294 → 1.43.0-dev.dfb984e779

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +3 -2
  3. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  4. package/lib/api/impl/lodestar/index.js +1 -1
  5. package/lib/api/impl/lodestar/index.js.map +1 -1
  6. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  7. package/lib/chain/blocks/importBlock.js +6 -3
  8. package/lib/chain/blocks/importBlock.js.map +1 -1
  9. package/lib/chain/blocks/importExecutionPayload.d.ts +26 -14
  10. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  11. package/lib/chain/blocks/importExecutionPayload.js +73 -77
  12. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  13. package/lib/chain/blocks/index.d.ts +5 -3
  14. package/lib/chain/blocks/index.d.ts.map +1 -1
  15. package/lib/chain/blocks/index.js +28 -10
  16. package/lib/chain/blocks/index.js.map +1 -1
  17. package/lib/chain/blocks/payloadEnvelopeProcessor.js +2 -2
  18. package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
  19. package/lib/chain/blocks/types.d.ts +14 -20
  20. package/lib/chain/blocks/types.d.ts.map +1 -1
  21. package/lib/chain/blocks/utils/chainSegment.d.ts +23 -2
  22. package/lib/chain/blocks/utils/chainSegment.d.ts.map +1 -1
  23. package/lib/chain/blocks/utils/chainSegment.js +81 -12
  24. package/lib/chain/blocks/utils/chainSegment.js.map +1 -1
  25. package/lib/chain/blocks/verifyBlock.d.ts +3 -2
  26. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  27. package/lib/chain/blocks/verifyBlock.js +30 -5
  28. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  29. package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts.map +1 -1
  30. package/lib/chain/blocks/verifyBlocksSanityChecks.js +15 -4
  31. package/lib/chain/blocks/verifyBlocksSanityChecks.js.map +1 -1
  32. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts +24 -0
  33. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -0
  34. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +76 -0
  35. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -0
  36. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.d.ts +1 -1
  37. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.d.ts.map +1 -1
  38. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js +2 -11
  39. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js.map +1 -1
  40. package/lib/chain/chain.d.ts +3 -2
  41. package/lib/chain/chain.d.ts.map +1 -1
  42. package/lib/chain/chain.js +14 -3
  43. package/lib/chain/chain.js.map +1 -1
  44. package/lib/chain/errors/blockError.d.ts +8 -1
  45. package/lib/chain/errors/blockError.d.ts.map +1 -1
  46. package/lib/chain/errors/blockError.js +2 -0
  47. package/lib/chain/errors/blockError.js.map +1 -1
  48. package/lib/chain/errors/executionPayloadBid.d.ts +5 -0
  49. package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
  50. package/lib/chain/errors/executionPayloadBid.js +1 -0
  51. package/lib/chain/errors/executionPayloadBid.js.map +1 -1
  52. package/lib/chain/errors/executionPayloadEnvelope.d.ts +5 -0
  53. package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -1
  54. package/lib/chain/errors/executionPayloadEnvelope.js +1 -0
  55. package/lib/chain/errors/executionPayloadEnvelope.js.map +1 -1
  56. package/lib/chain/forkChoice/index.js +2 -2
  57. package/lib/chain/forkChoice/index.js.map +1 -1
  58. package/lib/chain/interface.d.ts +3 -2
  59. package/lib/chain/interface.d.ts.map +1 -1
  60. package/lib/chain/interface.js.map +1 -1
  61. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  62. package/lib/chain/prepareNextSlot.js +30 -10
  63. package/lib/chain/prepareNextSlot.js.map +1 -1
  64. package/lib/chain/produceBlock/produceBlockBody.d.ts +3 -2
  65. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  66. package/lib/chain/produceBlock/produceBlockBody.js +34 -13
  67. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  68. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +11 -4
  69. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  70. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +20 -18
  71. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  72. package/lib/chain/validation/block.d.ts.map +1 -1
  73. package/lib/chain/validation/block.js +1 -0
  74. package/lib/chain/validation/block.js.map +1 -1
  75. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  76. package/lib/chain/validation/executionPayloadBid.js +13 -1
  77. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  78. package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -1
  79. package/lib/chain/validation/executionPayloadEnvelope.js +11 -1
  80. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  81. package/lib/metrics/metrics/lodestar.d.ts +1 -0
  82. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  83. package/lib/metrics/metrics/lodestar.js +4 -0
  84. package/lib/metrics/metrics/lodestar.js.map +1 -1
  85. package/lib/network/processor/gossipHandlers.js +4 -6
  86. package/lib/network/processor/gossipHandlers.js.map +1 -1
  87. package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
  88. package/lib/network/reqresp/handlers/beaconBlocksByRange.js +14 -6
  89. package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
  90. package/lib/network/reqresp/handlers/blobSidecarsByRange.d.ts.map +1 -1
  91. package/lib/network/reqresp/handlers/blobSidecarsByRange.js +11 -5
  92. package/lib/network/reqresp/handlers/blobSidecarsByRange.js.map +1 -1
  93. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
  94. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +17 -5
  95. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
  96. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts.map +1 -1
  97. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js +7 -4
  98. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
  99. package/lib/node/notifier.js +7 -1
  100. package/lib/node/notifier.js.map +1 -1
  101. package/lib/sync/range/batch.d.ts +12 -2
  102. package/lib/sync/range/batch.d.ts.map +1 -1
  103. package/lib/sync/range/batch.js +56 -30
  104. package/lib/sync/range/batch.js.map +1 -1
  105. package/lib/sync/range/chain.d.ts +6 -2
  106. package/lib/sync/range/chain.d.ts.map +1 -1
  107. package/lib/sync/range/chain.js +4 -3
  108. package/lib/sync/range/chain.js.map +1 -1
  109. package/lib/sync/range/range.d.ts.map +1 -1
  110. package/lib/sync/range/range.js +17 -6
  111. package/lib/sync/range/range.js.map +1 -1
  112. package/lib/sync/types.d.ts +34 -0
  113. package/lib/sync/types.d.ts.map +1 -1
  114. package/lib/sync/types.js +34 -0
  115. package/lib/sync/types.js.map +1 -1
  116. package/lib/sync/unknownBlock.d.ts +24 -1
  117. package/lib/sync/unknownBlock.d.ts.map +1 -1
  118. package/lib/sync/unknownBlock.js +649 -53
  119. package/lib/sync/unknownBlock.js.map +1 -1
  120. package/lib/sync/utils/downloadByRange.d.ts +46 -10
  121. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  122. package/lib/sync/utils/downloadByRange.js +147 -24
  123. package/lib/sync/utils/downloadByRange.js.map +1 -1
  124. package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
  125. package/lib/sync/utils/downloadByRoot.js +6 -2
  126. package/lib/sync/utils/downloadByRoot.js.map +1 -1
  127. package/lib/sync/utils/pendingBlocksTree.d.ts +0 -1
  128. package/lib/sync/utils/pendingBlocksTree.d.ts.map +1 -1
  129. package/lib/sync/utils/pendingBlocksTree.js +0 -9
  130. package/lib/sync/utils/pendingBlocksTree.js.map +1 -1
  131. package/package.json +16 -15
  132. package/src/api/impl/beacon/blocks/index.ts +5 -2
  133. package/src/api/impl/lodestar/index.ts +1 -1
  134. package/src/chain/blocks/importBlock.ts +4 -2
  135. package/src/chain/blocks/importExecutionPayload.ts +92 -97
  136. package/src/chain/blocks/index.ts +44 -13
  137. package/src/chain/blocks/payloadEnvelopeProcessor.ts +2 -2
  138. package/src/chain/blocks/types.ts +14 -25
  139. package/src/chain/blocks/utils/chainSegment.ts +106 -17
  140. package/src/chain/blocks/verifyBlock.ts +35 -6
  141. package/src/chain/blocks/verifyBlocksSanityChecks.ts +16 -7
  142. package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +129 -0
  143. package/src/chain/blocks/writePayloadEnvelopeInputToDb.ts +9 -18
  144. package/src/chain/chain.ts +23 -3
  145. package/src/chain/errors/blockError.ts +4 -1
  146. package/src/chain/errors/executionPayloadBid.ts +6 -0
  147. package/src/chain/errors/executionPayloadEnvelope.ts +6 -0
  148. package/src/chain/forkChoice/index.ts +2 -2
  149. package/src/chain/interface.ts +7 -1
  150. package/src/chain/prepareNextSlot.ts +42 -12
  151. package/src/chain/produceBlock/produceBlockBody.ts +37 -11
  152. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +22 -20
  153. package/src/chain/validation/block.ts +1 -0
  154. package/src/chain/validation/executionPayloadBid.ts +14 -0
  155. package/src/chain/validation/executionPayloadEnvelope.ts +12 -2
  156. package/src/metrics/metrics/lodestar.ts +4 -0
  157. package/src/network/processor/gossipHandlers.ts +6 -6
  158. package/src/network/reqresp/handlers/beaconBlocksByRange.ts +14 -6
  159. package/src/network/reqresp/handlers/blobSidecarsByRange.ts +11 -5
  160. package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +17 -5
  161. package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +7 -4
  162. package/src/node/notifier.ts +8 -1
  163. package/src/sync/range/batch.ts +90 -35
  164. package/src/sync/range/chain.ts +13 -5
  165. package/src/sync/range/range.ts +18 -6
  166. package/src/sync/types.ts +72 -0
  167. package/src/sync/unknownBlock.ts +810 -57
  168. package/src/sync/utils/downloadByRange.ts +256 -39
  169. package/src/sync/utils/downloadByRoot.ts +12 -2
  170. package/src/sync/utils/pendingBlocksTree.ts +0 -15
@@ -1,10 +1,11 @@
1
1
  import {ChainForkConfig} from "@lodestar/config";
2
- import {ForkName, isForkPostDeneb, isForkPostFulu} from "@lodestar/params";
2
+ import {ForkName, isForkPostDeneb, isForkPostFulu, isForkPostGloas} from "@lodestar/params";
3
3
  import {Epoch, RootHex, Slot, phase0} from "@lodestar/types";
4
4
  import {LodestarError} from "@lodestar/utils";
5
5
  import {isBlockInputColumns} from "../../chain/blocks/blockInput/blockInput.js";
6
6
  import {IBlockInput} from "../../chain/blocks/blockInput/types.js";
7
7
  import {isDaOutOfRange} from "../../chain/blocks/blockInput/utils.js";
8
+ import {PayloadEnvelopeInput} from "../../chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js";
8
9
  import {BlockError, BlockErrorCode} from "../../chain/errors/index.js";
9
10
  import {PeerSyncMeta} from "../../network/peers/peersData.js";
10
11
  import {IClock} from "../../util/clock.js";
@@ -46,19 +47,36 @@ export type Attempt = {
46
47
  export type AwaitingDownloadState = {
47
48
  status: BatchStatus.AwaitingDownload;
48
49
  blocks: IBlockInput[];
50
+ payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null;
49
51
  };
50
52
 
51
53
  export type DownloadSuccessState = {
52
54
  status: BatchStatus.AwaitingProcessing;
53
55
  blocks: IBlockInput[];
56
+ payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null;
54
57
  };
55
58
 
56
59
  export type BatchState =
57
60
  | AwaitingDownloadState
58
- | {status: BatchStatus.Downloading; peer: PeerIdStr; blocks: IBlockInput[]}
61
+ | {
62
+ status: BatchStatus.Downloading;
63
+ peer: PeerIdStr;
64
+ blocks: IBlockInput[];
65
+ payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null;
66
+ }
59
67
  | DownloadSuccessState
60
- | {status: BatchStatus.Processing; blocks: IBlockInput[]; attempt: Attempt}
61
- | {status: BatchStatus.AwaitingValidation; blocks: IBlockInput[]; attempt: Attempt};
68
+ | {
69
+ status: BatchStatus.Processing;
70
+ blocks: IBlockInput[];
71
+ payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null;
72
+ attempt: Attempt;
73
+ }
74
+ | {
75
+ status: BatchStatus.AwaitingValidation;
76
+ blocks: IBlockInput[];
77
+ payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null;
78
+ attempt: Attempt;
79
+ };
62
80
 
63
81
  export type BatchMetadata = {
64
82
  startEpoch: Epoch;
@@ -85,7 +103,7 @@ export class Batch {
85
103
  /** Block, blob and column requests that are used to determine the best peer and are used in downloadByRange */
86
104
  requests: DownloadByRangeRequests;
87
105
  /** State of the batch. */
88
- state: BatchState = {status: BatchStatus.AwaitingDownload, blocks: []};
106
+ state: BatchState = {status: BatchStatus.AwaitingDownload, blocks: [], payloadEnvelopes: null};
89
107
  /** Peers that provided good data */
90
108
  goodPeers: PeerIdStr[] = [];
91
109
  /** The `Attempts` that have been made and failed to send us this batch. */
@@ -129,35 +147,33 @@ export class Batch {
129
147
  count: this.count,
130
148
  step: 1,
131
149
  };
132
- if (isForkPostFulu(this.forkName) && withinValidRequestWindow) {
133
- return {
134
- blocksRequest,
135
- columnsRequest: {
136
- startSlot: this.startSlot,
137
- count: this.count,
138
- columns: this.custodyConfig.sampledColumns,
139
- },
140
- };
150
+ const requests: DownloadByRangeRequests = {blocksRequest};
151
+
152
+ // Post-Gloas envelopes are required for block processing, independent of DA retention window.
153
+ if (isForkPostGloas(this.forkName)) {
154
+ requests.envelopesRequest = {startSlot: this.startSlot, count: this.count};
141
155
  }
142
- if (isForkPostDeneb(this.forkName) && withinValidRequestWindow) {
143
- return {
144
- blocksRequest,
145
- blobsRequest: {
146
- startSlot: this.startSlot,
147
- count: this.count,
148
- },
156
+
157
+ if (isForkPostFulu(this.forkName) && withinValidRequestWindow) {
158
+ requests.columnsRequest = {
159
+ startSlot: this.startSlot,
160
+ count: this.count,
161
+ columns: this.custodyConfig.sampledColumns,
149
162
  };
163
+ } else if (isForkPostDeneb(this.forkName) && withinValidRequestWindow) {
164
+ requests.blobsRequest = {startSlot: this.startSlot, count: this.count};
150
165
  }
151
- return {
152
- blocksRequest,
153
- };
166
+
167
+ return requests;
154
168
  }
155
169
 
156
170
  // subsequent request where part of the epoch has already been downloaded. Need to figure out what is the beginning
157
171
  // of the range where download needs to resume
158
172
  let blockStartSlot = this.startSlot;
159
173
  let dataStartSlot = this.startSlot;
174
+ let envelopeStartSlot = this.startSlot;
160
175
  const neededColumns = new Set<number>();
176
+ const envelopesBySlot = this.state.payloadEnvelopes ?? new Map<Slot, PayloadEnvelopeInput>();
161
177
 
162
178
  // ensure blocks are in slot-wise order
163
179
  for (const blockInput of blocks) {
@@ -175,6 +191,13 @@ export class Batch {
175
191
  if (blockInput.hasBlock() && blockStartSlot === blockSlot) {
176
192
  blockStartSlot = blockSlot + 1;
177
193
  }
194
+ if (
195
+ blockInput.hasBlock() &&
196
+ envelopeStartSlot === blockSlot &&
197
+ envelopesBySlot.get(blockSlot)?.hasPayloadEnvelope()
198
+ ) {
199
+ envelopeStartSlot = blockSlot + 1;
200
+ }
178
201
  if (!blockInput.hasAllData()) {
179
202
  if (isBlockInputColumns(blockInput)) {
180
203
  for (const index of blockInput.getMissingSampledColumnMeta().missing) {
@@ -216,6 +239,13 @@ export class Batch {
216
239
  // dataSlot will still have a value but do not create a request for preDeneb forks
217
240
  }
218
241
 
242
+ if (isForkPostGloas(this.forkName) && envelopeStartSlot <= endSlot) {
243
+ requests.envelopesRequest = {
244
+ startSlot: envelopeStartSlot,
245
+ count: endSlot - envelopeStartSlot + 1,
246
+ };
247
+ }
248
+
219
249
  return requests;
220
250
  }
221
251
 
@@ -263,6 +293,10 @@ export class Batch {
263
293
  return this.state.blocks;
264
294
  }
265
295
 
296
+ getPayloadEnvelopes(): Map<Slot, PayloadEnvelopeInput> | null {
297
+ return this.state.payloadEnvelopes;
298
+ }
299
+
266
300
  /**
267
301
  * AwaitingDownload -> Downloading
268
302
  */
@@ -271,13 +305,22 @@ export class Batch {
271
305
  throw new BatchError(this.wrongStatusErrorType(BatchStatus.AwaitingDownload));
272
306
  }
273
307
 
274
- this.state = {status: BatchStatus.Downloading, peer, blocks: this.state.blocks};
308
+ this.state = {
309
+ status: BatchStatus.Downloading,
310
+ peer,
311
+ blocks: this.state.blocks,
312
+ payloadEnvelopes: this.state.payloadEnvelopes,
313
+ };
275
314
  }
276
315
 
277
316
  /**
278
317
  * Downloading -> AwaitingProcessing
279
318
  */
280
- downloadingSuccess(peer: PeerIdStr, blocks: IBlockInput[]): DownloadSuccessState {
319
+ downloadingSuccess(
320
+ peer: PeerIdStr,
321
+ blocks: IBlockInput[],
322
+ payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null
323
+ ): DownloadSuccessState {
281
324
  if (this.state.status !== BatchStatus.Downloading) {
282
325
  throw new BatchError(this.wrongStatusErrorType(BatchStatus.Downloading));
283
326
  }
@@ -305,11 +348,13 @@ export class Batch {
305
348
  status: this.state.status,
306
349
  });
307
350
  }
351
+ const newPayloadEnvelopes = payloadEnvelopes ?? this.state.payloadEnvelopes;
352
+
308
353
  if (allComplete) {
309
- this.state = {status: BatchStatus.AwaitingProcessing, blocks};
354
+ this.state = {status: BatchStatus.AwaitingProcessing, blocks, payloadEnvelopes: newPayloadEnvelopes};
310
355
  } else {
311
356
  this.requests = this.getRequests(blocks);
312
- this.state = {status: BatchStatus.AwaitingDownload, blocks};
357
+ this.state = {status: BatchStatus.AwaitingDownload, blocks, payloadEnvelopes: newPayloadEnvelopes};
313
358
  }
314
359
 
315
360
  return this.state as DownloadSuccessState;
@@ -328,25 +373,30 @@ export class Batch {
328
373
  throw new BatchError(this.errorType({code: BatchErrorCode.MAX_DOWNLOAD_ATTEMPTS}));
329
374
  }
330
375
 
331
- this.state = {status: BatchStatus.AwaitingDownload, blocks: this.state.blocks};
376
+ this.state = {
377
+ status: BatchStatus.AwaitingDownload,
378
+ blocks: this.state.blocks,
379
+ payloadEnvelopes: this.state.payloadEnvelopes,
380
+ };
332
381
  }
333
382
 
334
383
  /**
335
384
  * AwaitingProcessing -> Processing
336
385
  */
337
- startProcessing(): IBlockInput[] {
386
+ startProcessing(): {blocks: IBlockInput[]; payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null} {
338
387
  if (this.state.status !== BatchStatus.AwaitingProcessing) {
339
388
  throw new BatchError(this.wrongStatusErrorType(BatchStatus.AwaitingProcessing));
340
389
  }
341
390
 
342
391
  const blocks = this.state.blocks;
392
+ const payloadEnvelopes = this.state.payloadEnvelopes;
343
393
  const hash = hashBlocks(blocks, this.config); // tracks blocks to report peer on processing error
344
394
  // Reset goodPeers in case another download attempt needs to be made. When Attempt is successful or not the peers
345
395
  // that the data came from will be handled by the Attempt that goes for processing
346
396
  const peers = this.goodPeers;
347
397
  this.goodPeers = [];
348
- this.state = {status: BatchStatus.Processing, blocks, attempt: {peers, hash}};
349
- return blocks;
398
+ this.state = {status: BatchStatus.Processing, blocks, payloadEnvelopes, attempt: {peers, hash}};
399
+ return {blocks, payloadEnvelopes};
350
400
  }
351
401
 
352
402
  /**
@@ -357,7 +407,12 @@ export class Batch {
357
407
  throw new BatchError(this.wrongStatusErrorType(BatchStatus.Processing));
358
408
  }
359
409
 
360
- this.state = {status: BatchStatus.AwaitingValidation, blocks: this.state.blocks, attempt: this.state.attempt};
410
+ this.state = {
411
+ status: BatchStatus.AwaitingValidation,
412
+ blocks: this.state.blocks,
413
+ payloadEnvelopes: this.state.payloadEnvelopes,
414
+ attempt: this.state.attempt,
415
+ };
361
416
  }
362
417
 
363
418
  /**
@@ -408,7 +463,7 @@ export class Batch {
408
463
 
409
464
  // remove any downloaded blocks and re-attempt
410
465
  // TODO(fulu): need to remove the bad blocks from the SeenBlockInputCache
411
- this.state = {status: BatchStatus.AwaitingDownload, blocks: []};
466
+ this.state = {status: BatchStatus.AwaitingDownload, blocks: [], payloadEnvelopes: null};
412
467
  }
413
468
 
414
469
  private onProcessingError(attempt: Attempt): void {
@@ -419,7 +474,7 @@ export class Batch {
419
474
 
420
475
  // remove any downloaded blocks and re-attempt
421
476
  // TODO(fulu): need to remove the bad blocks from the SeenBlockInputCache
422
- this.state = {status: BatchStatus.AwaitingDownload, blocks: []};
477
+ this.state = {status: BatchStatus.AwaitingDownload, blocks: [], payloadEnvelopes: null};
423
478
  }
424
479
 
425
480
  /** Helper to construct typed BatchError. Stack traces are correct as the error is thrown above */
@@ -4,6 +4,7 @@ import {ErrorAborted, LodestarError, Logger, toRootHex} from "@lodestar/utils";
4
4
  import {isBlockInputBlobs, isBlockInputColumns} from "../../chain/blocks/blockInput/blockInput.js";
5
5
  import {BlockInputErrorCode} from "../../chain/blocks/blockInput/errors.js";
6
6
  import {IBlockInput} from "../../chain/blocks/blockInput/types.js";
7
+ import {PayloadEnvelopeInput} from "../../chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js";
7
8
  import {BlobSidecarErrorCode} from "../../chain/errors/blobSidecarError.js";
8
9
  import {DataColumnSidecarErrorCode} from "../../chain/errors/dataColumnSidecarError.js";
9
10
  import {Metrics} from "../../metrics/metrics.js";
@@ -44,13 +45,19 @@ export type SyncChainFns = {
44
45
  * Must return if ALL blocks are processed successfully
45
46
  * If SOME blocks are processed must throw BlockProcessorError()
46
47
  */
47
- processChainSegment: (blocks: IBlockInput[], syncType: RangeSyncType) => Promise<void>;
48
+ processChainSegment: (
49
+ blocks: IBlockInput[],
50
+ payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null,
51
+ syncType: RangeSyncType
52
+ ) => Promise<void>;
48
53
  /** Must download blocks, and validate their range */
49
54
  downloadByRange: (
50
55
  peer: PeerSyncMeta,
51
56
  batch: Batch,
52
57
  syncType: RangeSyncType
53
- ) => Promise<WarnResult<IBlockInput[], DownloadByRangeError>>;
58
+ ) => Promise<
59
+ WarnResult<{blocks: IBlockInput[]; payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null}, DownloadByRangeError>
60
+ >;
54
61
  /** Report peer for negative actions. Decouples from the full network instance */
55
62
  reportPeer: (peer: PeerIdStr, action: PeerAction, actionName: string) => void;
56
63
  /** Gets current peer custodyColumns and earliestAvailableSlot */
@@ -516,7 +523,8 @@ export class SyncChain {
516
523
  });
517
524
  this.metrics?.syncRange.downloadByRange.success.inc();
518
525
  const {warnings, result} = res.result;
519
- const downloadSuccessOutput = batch.downloadingSuccess(peer.peerId, result);
526
+ const {blocks: downloadedBlocks, payloadEnvelopes} = result;
527
+ const downloadSuccessOutput = batch.downloadingSuccess(peer.peerId, downloadedBlocks, payloadEnvelopes);
520
528
  const logMeta: Record<string, number> = {
521
529
  blockCount: downloadSuccessOutput.blocks.length,
522
530
  };
@@ -578,10 +586,10 @@ export class SyncChain {
578
586
  * Sends `batch` to the processor. Note: batch may be empty
579
587
  */
580
588
  private async processBatch(batch: Batch): Promise<void> {
581
- const blocks = batch.startProcessing();
589
+ const {blocks, payloadEnvelopes} = batch.startProcessing();
582
590
 
583
591
  // wrapError ensures to never call both batch success() and batch error()
584
- const res = await wrapError(this.processChainSegment(blocks, this.syncType));
592
+ const res = await wrapError(this.processChainSegment(blocks, payloadEnvelopes, this.syncType));
585
593
 
586
594
  if (!res.err) {
587
595
  batch.processingSuccess();
@@ -172,7 +172,7 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
172
172
  }
173
173
 
174
174
  /** Convenience method for `SyncChain` */
175
- private processChainSegment: SyncChainFns["processChainSegment"] = async (blocks, syncType) => {
175
+ private processChainSegment: SyncChainFns["processChainSegment"] = async (blocks, payloadEnvelopes, syncType) => {
176
176
  // Not trusted, verify signatures
177
177
  const flags: ImportBlockOpts = {
178
178
  // Only skip importing attestations for finalized sync. For head sync attestation are valuable.
@@ -192,9 +192,15 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
192
192
 
193
193
  if (this.opts?.disableProcessAsChainSegment) {
194
194
  // Should only be used for debugging or testing
195
- for (const block of blocks) await this.chain.processBlock(block, flags);
195
+ for (const block of blocks) {
196
+ await this.chain.processBlock(block, flags);
197
+ const payloadEnvelope = payloadEnvelopes?.get(block.slot);
198
+ if (payloadEnvelope) {
199
+ await this.chain.processExecutionPayload(payloadEnvelope);
200
+ }
201
+ }
196
202
  } else {
197
- await this.chain.processChainSegment(blocks, flags);
203
+ await this.chain.processChainSegment(blocks, payloadEnvelopes, flags);
198
204
  }
199
205
  };
200
206
 
@@ -209,13 +215,19 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
209
215
  peerDasMetrics: this.chain.metrics?.peerDas,
210
216
  ...batch.getRequestsForPeer(peer),
211
217
  });
212
- const cached = cacheByRangeResponses({
218
+ const {responses, payloadEnvelopes: downloadedPayloadEnvelopes} = result;
219
+ const {blocks, payloadEnvelopes} = cacheByRangeResponses({
213
220
  cache: this.chain.seenBlockInputCache,
221
+ seenPayloadEnvelopeInputCache: this.chain.seenPayloadEnvelopeInputCache,
214
222
  peerIdStr: peer.peerId,
215
- responses: result,
223
+ responses,
216
224
  batchBlocks,
225
+ downloadedPayloadEnvelopes,
226
+ existingPayloadEnvelopes: batch.getPayloadEnvelopes(),
227
+ custodyConfig: this.chain.custodyConfig,
228
+ seenTimestampSec: Date.now() / 1000,
217
229
  });
218
- return {result: cached, warnings};
230
+ return {result: {blocks, payloadEnvelopes}, warnings};
219
231
  };
220
232
 
221
233
  private pruneBlockInputs: SyncChainFns["pruneBlockInputs"] = (blocks: IBlockInput[]) => {
package/src/sync/types.ts CHANGED
@@ -1,5 +1,8 @@
1
1
  import {RootHex, Slot} from "@lodestar/types";
2
+ import {SignedExecutionPayloadEnvelope} from "@lodestar/types/gloas";
3
+ import {toRootHex} from "@lodestar/utils";
2
4
  import {IBlockInput} from "../chain/blocks/blockInput/index.js";
5
+ import {PayloadEnvelopeInput} from "../chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js";
3
6
 
4
7
  export enum PendingBlockType {
5
8
  /**
@@ -26,6 +29,14 @@ export enum PendingBlockInputStatus {
26
29
  processing = "processing",
27
30
  }
28
31
 
32
+ export enum PendingPayloadInputStatus {
33
+ pending = "pending",
34
+ fetching = "fetching",
35
+ waitingForBlock = "waiting_for_block",
36
+ downloaded = "downloaded",
37
+ processing = "processing",
38
+ }
39
+
29
40
  export type PendingBlockInput = {
30
41
  status: PendingBlockInputStatus;
31
42
  blockInput: IBlockInput;
@@ -44,10 +55,47 @@ export type PendingRootHex = {
44
55
 
45
56
  export type BlockInputSyncCacheItem = PendingBlockInput | PendingRootHex;
46
57
 
58
+ export type PendingPayloadInput = {
59
+ status:
60
+ | PendingPayloadInputStatus.pending
61
+ | PendingPayloadInputStatus.fetching
62
+ | PendingPayloadInputStatus.downloaded
63
+ | PendingPayloadInputStatus.processing;
64
+ payloadInput: PayloadEnvelopeInput;
65
+ timeAddedSec: number;
66
+ timeSyncedSec?: number;
67
+ peerIdStrings: Set<string>;
68
+ };
69
+
70
+ export type PendingPayloadRootHex = {
71
+ status: PendingPayloadInputStatus.pending | PendingPayloadInputStatus.fetching;
72
+ rootHex: RootHex;
73
+ timeAddedSec: number;
74
+ timeSyncedSec?: number;
75
+ peerIdStrings: Set<string>;
76
+ };
77
+
78
+ export type PendingPayloadEnvelope = {
79
+ status: PendingPayloadInputStatus.waitingForBlock;
80
+ envelope: SignedExecutionPayloadEnvelope;
81
+ timeAddedSec: number;
82
+ peerIdStrings: Set<string>;
83
+ };
84
+
85
+ export type PayloadSyncCacheItem = PendingPayloadInput | PendingPayloadRootHex | PendingPayloadEnvelope;
86
+
47
87
  export function isPendingBlockInput(pending: BlockInputSyncCacheItem): pending is PendingBlockInput {
48
88
  return "blockInput" in pending;
49
89
  }
50
90
 
91
+ export function isPendingPayloadInput(pending: PayloadSyncCacheItem): pending is PendingPayloadInput {
92
+ return "payloadInput" in pending;
93
+ }
94
+
95
+ export function isPendingPayloadEnvelope(pending: PayloadSyncCacheItem): pending is PendingPayloadEnvelope {
96
+ return "envelope" in pending;
97
+ }
98
+
51
99
  export function getBlockInputSyncCacheItemRootHex(block: BlockInputSyncCacheItem): RootHex {
52
100
  return isPendingBlockInput(block) ? block.blockInput.blockRootHex : block.rootHex;
53
101
  }
@@ -55,3 +103,27 @@ export function getBlockInputSyncCacheItemRootHex(block: BlockInputSyncCacheItem
55
103
  export function getBlockInputSyncCacheItemSlot(block: BlockInputSyncCacheItem): Slot | string {
56
104
  return isPendingBlockInput(block) ? block.blockInput.slot : "unknown";
57
105
  }
106
+
107
+ export function getPayloadSyncCacheItemRootHex(payload: PayloadSyncCacheItem): RootHex {
108
+ if (isPendingPayloadInput(payload)) {
109
+ return payload.payloadInput.blockRootHex;
110
+ }
111
+
112
+ if (isPendingPayloadEnvelope(payload)) {
113
+ return toRootHex(payload.envelope.message.beaconBlockRoot);
114
+ }
115
+
116
+ return payload.rootHex;
117
+ }
118
+
119
+ export function getPayloadSyncCacheItemSlot(payload: PayloadSyncCacheItem): Slot | string {
120
+ if (isPendingPayloadInput(payload)) {
121
+ return payload.payloadInput.slot;
122
+ }
123
+
124
+ if (isPendingPayloadEnvelope(payload)) {
125
+ return payload.envelope.message.payload.slotNumber;
126
+ }
127
+
128
+ return "unknown";
129
+ }