@lodestar/beacon-node 1.42.0-dev.5f2fffc2ce → 1.42.0-dev.7552832620

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 (142) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +35 -16
  3. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  4. package/lib/chain/blocks/blockInput/types.d.ts +3 -3
  5. package/lib/chain/blocks/blockInput/types.d.ts.map +1 -1
  6. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  7. package/lib/chain/blocks/importBlock.js +18 -2
  8. package/lib/chain/blocks/importBlock.js.map +1 -1
  9. package/lib/chain/blocks/importExecutionPayload.d.ts +48 -0
  10. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -0
  11. package/lib/chain/blocks/importExecutionPayload.js +159 -0
  12. package/lib/chain/blocks/importExecutionPayload.js.map +1 -0
  13. package/lib/chain/blocks/payloadEnvelopeInput/index.d.ts +3 -0
  14. package/lib/chain/blocks/payloadEnvelopeInput/index.d.ts.map +1 -0
  15. package/lib/chain/blocks/payloadEnvelopeInput/index.js +3 -0
  16. package/lib/chain/blocks/payloadEnvelopeInput/index.js.map +1 -0
  17. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +80 -0
  18. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -0
  19. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +248 -0
  20. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -0
  21. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +29 -0
  22. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -0
  23. package/lib/chain/blocks/payloadEnvelopeInput/types.js +11 -0
  24. package/lib/chain/blocks/payloadEnvelopeInput/types.js.map +1 -0
  25. package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts +15 -0
  26. package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts.map +1 -0
  27. package/lib/chain/blocks/payloadEnvelopeProcessor.js +46 -0
  28. package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -0
  29. package/lib/chain/blocks/types.d.ts +7 -0
  30. package/lib/chain/blocks/types.d.ts.map +1 -1
  31. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.d.ts +12 -0
  32. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.d.ts.map +1 -0
  33. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js +40 -0
  34. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js.map +1 -0
  35. package/lib/chain/chain.d.ts +7 -2
  36. package/lib/chain/chain.d.ts.map +1 -1
  37. package/lib/chain/chain.js +28 -3
  38. package/lib/chain/chain.js.map +1 -1
  39. package/lib/chain/errors/executionPayloadEnvelope.d.ts +12 -2
  40. package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -1
  41. package/lib/chain/errors/executionPayloadEnvelope.js +3 -1
  42. package/lib/chain/errors/executionPayloadEnvelope.js.map +1 -1
  43. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  44. package/lib/chain/forkChoice/index.js +0 -10
  45. package/lib/chain/forkChoice/index.js.map +1 -1
  46. package/lib/chain/interface.d.ts +6 -3
  47. package/lib/chain/interface.d.ts.map +1 -1
  48. package/lib/chain/opPools/utils.js +1 -1
  49. package/lib/chain/opPools/utils.js.map +1 -1
  50. package/lib/chain/produceBlock/computeNewStateRoot.d.ts.map +1 -1
  51. package/lib/chain/produceBlock/computeNewStateRoot.js +6 -1
  52. package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
  53. package/lib/chain/produceBlock/produceBlockBody.js +1 -1
  54. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  55. package/lib/chain/regen/interface.d.ts +2 -0
  56. package/lib/chain/regen/interface.d.ts.map +1 -1
  57. package/lib/chain/regen/interface.js +2 -0
  58. package/lib/chain/regen/interface.js.map +1 -1
  59. package/lib/chain/seenCache/index.d.ts +1 -1
  60. package/lib/chain/seenCache/index.d.ts.map +1 -1
  61. package/lib/chain/seenCache/index.js +1 -1
  62. package/lib/chain/seenCache/index.js.map +1 -1
  63. package/lib/chain/seenCache/seenGossipBlockInput.js +2 -2
  64. package/lib/chain/seenCache/seenGossipBlockInput.js.map +1 -1
  65. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +38 -0
  66. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -0
  67. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +76 -0
  68. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -0
  69. package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -1
  70. package/lib/chain/validation/executionPayloadEnvelope.js +30 -19
  71. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  72. package/lib/chain/validation/lightClientFinalityUpdate.js +1 -1
  73. package/lib/chain/validation/lightClientFinalityUpdate.js.map +1 -1
  74. package/lib/chain/validation/lightClientOptimisticUpdate.js +1 -1
  75. package/lib/chain/validation/lightClientOptimisticUpdate.js.map +1 -1
  76. package/lib/chain/validatorMonitor.d.ts +2 -1
  77. package/lib/chain/validatorMonitor.d.ts.map +1 -1
  78. package/lib/chain/validatorMonitor.js +4 -1
  79. package/lib/chain/validatorMonitor.js.map +1 -1
  80. package/lib/execution/engine/interface.d.ts +2 -2
  81. package/lib/metrics/metrics/lodestar.d.ts +28 -0
  82. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  83. package/lib/metrics/metrics/lodestar.js +74 -0
  84. package/lib/metrics/metrics/lodestar.js.map +1 -1
  85. package/lib/network/network.js +2 -2
  86. package/lib/network/network.js.map +1 -1
  87. package/lib/network/processor/extractSlotRootFns.d.ts.map +1 -1
  88. package/lib/network/processor/extractSlotRootFns.js +14 -4
  89. package/lib/network/processor/extractSlotRootFns.js.map +1 -1
  90. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  91. package/lib/network/processor/gossipHandlers.js +31 -3
  92. package/lib/network/processor/gossipHandlers.js.map +1 -1
  93. package/lib/network/reqresp/ReqRespBeaconNode.d.ts +1 -1
  94. package/lib/network/reqresp/ReqRespBeaconNode.js +1 -1
  95. package/lib/sync/backfill/backfill.d.ts +1 -1
  96. package/lib/sync/backfill/backfill.js +1 -1
  97. package/lib/sync/constants.d.ts +1 -1
  98. package/lib/sync/constants.js +1 -1
  99. package/lib/util/sszBytes.d.ts +4 -1
  100. package/lib/util/sszBytes.d.ts.map +1 -1
  101. package/lib/util/sszBytes.js +69 -12
  102. package/lib/util/sszBytes.js.map +1 -1
  103. package/package.json +15 -15
  104. package/src/api/impl/beacon/blocks/index.ts +36 -17
  105. package/src/chain/blocks/blockInput/types.ts +3 -3
  106. package/src/chain/blocks/importBlock.ts +36 -2
  107. package/src/chain/blocks/importExecutionPayload.ts +241 -0
  108. package/src/chain/blocks/payloadEnvelopeInput/index.ts +2 -0
  109. package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +336 -0
  110. package/src/chain/blocks/payloadEnvelopeInput/types.ts +33 -0
  111. package/src/chain/blocks/payloadEnvelopeProcessor.ts +61 -0
  112. package/src/chain/blocks/types.ts +8 -0
  113. package/src/chain/blocks/writePayloadEnvelopeInputToDb.ts +55 -0
  114. package/src/chain/chain.ts +37 -3
  115. package/src/chain/errors/executionPayloadEnvelope.ts +6 -2
  116. package/src/chain/forkChoice/index.ts +0 -10
  117. package/src/chain/interface.ts +6 -3
  118. package/src/chain/opPools/utils.ts +1 -1
  119. package/src/chain/produceBlock/computeNewStateRoot.ts +6 -1
  120. package/src/chain/produceBlock/produceBlockBody.ts +1 -1
  121. package/src/chain/regen/interface.ts +2 -0
  122. package/src/chain/seenCache/index.ts +1 -1
  123. package/src/chain/seenCache/seenGossipBlockInput.ts +2 -2
  124. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +106 -0
  125. package/src/chain/validation/executionPayloadEnvelope.ts +38 -25
  126. package/src/chain/validation/lightClientFinalityUpdate.ts +1 -1
  127. package/src/chain/validation/lightClientOptimisticUpdate.ts +1 -1
  128. package/src/chain/validatorMonitor.ts +11 -1
  129. package/src/execution/engine/interface.ts +2 -2
  130. package/src/metrics/metrics/lodestar.ts +77 -0
  131. package/src/network/network.ts +2 -2
  132. package/src/network/processor/extractSlotRootFns.ts +18 -5
  133. package/src/network/processor/gossipHandlers.ts +37 -1
  134. package/src/network/reqresp/ReqRespBeaconNode.ts +1 -1
  135. package/src/sync/backfill/backfill.ts +1 -1
  136. package/src/sync/constants.ts +1 -1
  137. package/src/util/sszBytes.ts +90 -10
  138. package/lib/chain/seenCache/seenExecutionPayloadEnvelope.d.ts +0 -15
  139. package/lib/chain/seenCache/seenExecutionPayloadEnvelope.d.ts.map +0 -1
  140. package/lib/chain/seenCache/seenExecutionPayloadEnvelope.js +0 -28
  141. package/lib/chain/seenCache/seenExecutionPayloadEnvelope.js.map +0 -1
  142. package/src/chain/seenCache/seenExecutionPayloadEnvelope.ts +0 -34
@@ -0,0 +1,55 @@
1
+ import {BeaconChain} from "../chain.js";
2
+ import {PayloadEnvelopeInput} from "../seenCache/seenPayloadEnvelopeInput.js";
3
+ import {writeDataColumnsToDb} from "./writeBlockInputToDb.js";
4
+
5
+ /**
6
+ * Persists payload envelope data to DB. This operation must be eventually completed if a payload is imported.
7
+ *
8
+ * TODO GLOAS: Persist envelope metadata (stateRoot, executionRequests, builderIndex, etc.) without the full
9
+ * execution payload body — only keep the blockHash reference. The EL already stores the payload.
10
+ * See https://github.com/ChainSafe/lodestar/issues/5671
11
+ */
12
+ export async function writePayloadEnvelopeInputToDb(
13
+ this: BeaconChain,
14
+ payloadInput: PayloadEnvelopeInput
15
+ ): Promise<void> {
16
+ const envelope = payloadInput.getPayloadEnvelope();
17
+ const blockRootHex = payloadInput.blockRootHex;
18
+
19
+ const envelopeBytes = this.serializedCache.get(envelope);
20
+ const envelopePromise = envelopeBytes
21
+ ? this.db.executionPayloadEnvelope.putBinary(this.db.executionPayloadEnvelope.getId(envelope), envelopeBytes)
22
+ : this.db.executionPayloadEnvelope.add(envelope);
23
+
24
+ // Write envelope and data columns in parallel (reuses shared column writing logic)
25
+ await Promise.all([envelopePromise, writeDataColumnsToDb.call(this, payloadInput)]);
26
+ this.logger.debug("Persisted payload envelope to db", {
27
+ slot: payloadInput.slot,
28
+ root: blockRootHex,
29
+ });
30
+ }
31
+
32
+ export async function persistPayloadEnvelopeInput(
33
+ this: BeaconChain,
34
+ payloadInput: PayloadEnvelopeInput
35
+ ): Promise<void> {
36
+ await writePayloadEnvelopeInputToDb
37
+ .call(this, payloadInput)
38
+ .catch((e) => {
39
+ this.logger.error(
40
+ "Error persisting payload envelope in hot db",
41
+ {
42
+ slot: payloadInput.slot,
43
+ root: payloadInput.blockRootHex,
44
+ },
45
+ e
46
+ );
47
+ })
48
+ .finally(() => {
49
+ this.seenPayloadEnvelopeInputCache.prune(payloadInput.blockRootHex);
50
+ this.logger.debug("Pruned payload envelope input", {
51
+ slot: payloadInput.slot,
52
+ root: payloadInput.blockRootHex,
53
+ });
54
+ });
55
+ }
@@ -84,7 +84,10 @@ import {CheckpointBalancesCache} from "./balancesCache.js";
84
84
  import {BeaconProposerCache} from "./beaconProposerCache.js";
85
85
  import {IBlockInput, isBlockInputBlobs, isBlockInputColumns} from "./blocks/blockInput/index.js";
86
86
  import {BlockProcessor, ImportBlockOpts} from "./blocks/index.js";
87
+ import {PayloadEnvelopeProcessor} from "./blocks/payloadEnvelopeProcessor.js";
88
+ import {ImportPayloadOpts} from "./blocks/types.js";
87
89
  import {persistBlockInput} from "./blocks/writeBlockInputToDb.js";
90
+ import {persistPayloadEnvelopeInput} from "./blocks/writePayloadEnvelopeInputToDb.js";
88
91
  import {BlsMultiThreadWorkerPool, BlsSingleThreadVerifier, IBlsVerifier} from "./bls/index.js";
89
92
  import {ColumnReconstructionTracker} from "./ColumnReconstructionTracker.js";
90
93
  import {ChainEvent, ChainEventEmitter} from "./emitter.js";
@@ -109,13 +112,14 @@ import {BlockAttributes, produceBlockBody, produceCommonBlockBody} from "./produ
109
112
  import {QueuedStateRegenerator, RegenCaller} from "./regen/index.js";
110
113
  import {ReprocessController} from "./reprocess.js";
111
114
  import {
115
+ PayloadEnvelopeInput,
112
116
  SeenAggregators,
113
117
  SeenAttesters,
114
118
  SeenBlockProposers,
115
119
  SeenContributionAndProof,
116
120
  SeenExecutionPayloadBids,
117
- SeenExecutionPayloadEnvelopes,
118
121
  SeenPayloadAttesters,
122
+ SeenPayloadEnvelopeInput,
119
123
  SeenSyncCommitteeMessages,
120
124
  } from "./seenCache/index.js";
121
125
  import {SeenAggregatedAttestations} from "./seenCache/seenAggregateAndProof.js";
@@ -148,6 +152,13 @@ const DEFAULT_MAX_CACHED_PRODUCED_RESULTS = 4;
148
152
  */
149
153
  const DEFAULT_MAX_PENDING_UNFINALIZED_BLOCK_WRITES = 16;
150
154
 
155
+ /**
156
+ * The maximum number of pending unfinalized payload envelope writes to the database before backpressure is applied.
157
+ * Payload envelope write queue entries hold references to payload inputs (including columns),
158
+ * keeping them in memory. Keep moderate to avoid OOM during sync.
159
+ */
160
+ const DEFAULT_MAX_PENDING_UNFINALIZED_PAYLOAD_ENVELOPE_WRITES = 16;
161
+
151
162
  export class BeaconChain implements IBeaconChain {
152
163
  readonly genesisTime: UintNum64;
153
164
  readonly genesisValidatorsRoot: Root;
@@ -172,6 +183,7 @@ export class BeaconChain implements IBeaconChain {
172
183
  readonly reprocessController: ReprocessController;
173
184
  readonly archiveStore: ArchiveStore;
174
185
  readonly unfinalizedBlockWrites: JobItemQueue<[IBlockInput], void>;
186
+ readonly unfinalizedPayloadEnvelopeWrites: JobItemQueue<[PayloadEnvelopeInput], void>;
175
187
 
176
188
  // Ops pool
177
189
  readonly attestationPool: AttestationPool;
@@ -187,13 +199,13 @@ export class BeaconChain implements IBeaconChain {
187
199
  readonly seenAggregators = new SeenAggregators();
188
200
  readonly seenPayloadAttesters = new SeenPayloadAttesters();
189
201
  readonly seenAggregatedAttestations: SeenAggregatedAttestations;
190
- readonly seenExecutionPayloadEnvelopes = new SeenExecutionPayloadEnvelopes();
191
202
  readonly seenExecutionPayloadBids = new SeenExecutionPayloadBids();
192
203
  readonly seenBlockProposers = new SeenBlockProposers();
193
204
  readonly seenSyncCommitteeMessages = new SeenSyncCommitteeMessages();
194
205
  readonly seenContributionAndProof: SeenContributionAndProof;
195
206
  readonly seenAttestationDatas: SeenAttestationDatas;
196
207
  readonly seenBlockInputCache: SeenBlockInput;
208
+ readonly seenPayloadEnvelopeInputCache: SeenPayloadEnvelopeInput;
197
209
  // Seen cache for liveness checks
198
210
  readonly seenBlockAttesters = new SeenBlockAttesters();
199
211
 
@@ -221,6 +233,7 @@ export class BeaconChain implements IBeaconChain {
221
233
  readonly opts: IChainOptions;
222
234
 
223
235
  protected readonly blockProcessor: BlockProcessor;
236
+ protected readonly payloadEnvelopeProcessor: PayloadEnvelopeProcessor;
224
237
  protected readonly db: IBeaconDb;
225
238
  // this is only available if nHistoricalStates is enabled
226
239
  private readonly cpStateDatastore?: CPStateDatastore;
@@ -334,6 +347,13 @@ export class BeaconChain implements IBeaconChain {
334
347
  metrics,
335
348
  logger,
336
349
  });
350
+ this.seenPayloadEnvelopeInputCache = new SeenPayloadEnvelopeInput({
351
+ chainEvents: emitter,
352
+ signal,
353
+ serializedCache: this.serializedCache,
354
+ metrics,
355
+ logger,
356
+ });
337
357
 
338
358
  this._earliestAvailableSlot = anchorState.slot;
339
359
 
@@ -411,6 +431,7 @@ export class BeaconChain implements IBeaconChain {
411
431
  this.reprocessController = new ReprocessController(this.metrics);
412
432
 
413
433
  this.blockProcessor = new BlockProcessor(this, metrics, opts, signal);
434
+ this.payloadEnvelopeProcessor = new PayloadEnvelopeProcessor(this, metrics, signal);
414
435
 
415
436
  this.forkChoice = forkChoice;
416
437
  this.clock = clock;
@@ -447,6 +468,15 @@ export class BeaconChain implements IBeaconChain {
447
468
  metrics?.unfinalizedBlockWritesQueue
448
469
  );
449
470
 
471
+ this.unfinalizedPayloadEnvelopeWrites = new JobItemQueue(
472
+ persistPayloadEnvelopeInput.bind(this),
473
+ {
474
+ maxLength: DEFAULT_MAX_PENDING_UNFINALIZED_PAYLOAD_ENVELOPE_WRITES,
475
+ signal,
476
+ },
477
+ metrics?.unfinalizedPayloadEnvelopeWritesQueue
478
+ );
479
+
450
480
  // always run PrepareNextSlotScheduler except for fork_choice spec tests
451
481
  if (!opts?.disablePrepareNextSlot) {
452
482
  new PrepareNextSlotScheduler(this, this.config, metrics, this.logger, signal);
@@ -477,6 +507,7 @@ export class BeaconChain implements IBeaconChain {
477
507
  // we can abort any ongoing unfinalized block writes.
478
508
  // TODO: persist fork choice to disk and allow unfinalized block writes to complete.
479
509
  this.unfinalizedBlockWrites.dropAllJobs();
510
+ this.unfinalizedPayloadEnvelopeWrites.dropAllJobs();
480
511
 
481
512
  this.abortController.abort();
482
513
  }
@@ -1010,6 +1041,10 @@ export class BeaconChain implements IBeaconChain {
1010
1041
  return this.blockProcessor.processBlocksJob(blocks, opts);
1011
1042
  }
1012
1043
 
1044
+ async processExecutionPayload(payloadInput: PayloadEnvelopeInput, opts?: ImportPayloadOpts): Promise<void> {
1045
+ return this.payloadEnvelopeProcessor.processPayloadEnvelopeJob(payloadInput, opts);
1046
+ }
1047
+
1013
1048
  getStatus(): Status {
1014
1049
  const head = this.forkChoice.getHead();
1015
1050
  const finalizedCheckpoint = this.forkChoice.getFinalizedCheckpoint();
@@ -1402,7 +1437,6 @@ export class BeaconChain implements IBeaconChain {
1402
1437
  this.logger.verbose("Fork choice finalized", {epoch: cp.epoch, root: cp.rootHex});
1403
1438
  const finalizedSlot = computeStartSlotAtEpoch(cp.epoch);
1404
1439
  this.seenBlockProposers.prune(finalizedSlot);
1405
- this.seenExecutionPayloadEnvelopes.prune(finalizedSlot);
1406
1440
 
1407
1441
  // Update validator custody to account for effective balance changes
1408
1442
  await this.updateValidatorsCustodyRequirement(cp);
@@ -4,17 +4,21 @@ import {GossipActionError} from "./gossipValidation.js";
4
4
  export enum ExecutionPayloadEnvelopeErrorCode {
5
5
  BELONG_TO_FINALIZED_BLOCK = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_BELONG_TO_FINALIZED_BLOCK",
6
6
  BLOCK_ROOT_UNKNOWN = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_BLOCK_ROOT_UNKNOWN",
7
+ PARENT_UNKNOWN = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_PARENT_UNKNOWN",
8
+ UNKNOWN_BLOCK_STATE = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_UNKNOWN_BLOCK_STATE",
7
9
  ENVELOPE_ALREADY_KNOWN = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_ALREADY_KNOWN",
8
10
  INVALID_BLOCK = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_INVALID_BLOCK",
9
11
  SLOT_MISMATCH = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_SLOT_MISMATCH",
10
12
  BUILDER_INDEX_MISMATCH = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_BUILDER_INDEX_MISMATCH",
11
13
  BLOCK_HASH_MISMATCH = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_BLOCK_HASH_MISMATCH",
12
14
  INVALID_SIGNATURE = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_INVALID_SIGNATURE",
13
- CACHE_FAIL = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_CACHE_FAIL",
15
+ PAYLOAD_ENVELOPE_INPUT_MISSING = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_PAYLOAD_ENVELOPE_INPUT_MISSING",
14
16
  }
15
17
  export type ExecutionPayloadEnvelopeErrorType =
16
18
  | {code: ExecutionPayloadEnvelopeErrorCode.BELONG_TO_FINALIZED_BLOCK; envelopeSlot: Slot; finalizedSlot: Slot}
17
19
  | {code: ExecutionPayloadEnvelopeErrorCode.BLOCK_ROOT_UNKNOWN; blockRoot: RootHex}
20
+ | {code: ExecutionPayloadEnvelopeErrorCode.PARENT_UNKNOWN; parentRoot: RootHex; slot: Slot}
21
+ | {code: ExecutionPayloadEnvelopeErrorCode.UNKNOWN_BLOCK_STATE; blockRoot: RootHex; slot: Slot}
18
22
  | {
19
23
  code: ExecutionPayloadEnvelopeErrorCode.ENVELOPE_ALREADY_KNOWN;
20
24
  blockRoot: RootHex;
@@ -33,6 +37,6 @@ export type ExecutionPayloadEnvelopeErrorType =
33
37
  bidBlockHash: RootHex | null;
34
38
  }
35
39
  | {code: ExecutionPayloadEnvelopeErrorCode.INVALID_SIGNATURE}
36
- | {code: ExecutionPayloadEnvelopeErrorCode.CACHE_FAIL; blockRoot: RootHex};
40
+ | {code: ExecutionPayloadEnvelopeErrorCode.PAYLOAD_ENVELOPE_INPUT_MISSING; blockRoot: RootHex};
37
41
 
38
42
  export class ExecutionPayloadEnvelopeError extends GossipActionError<ExecutionPayloadEnvelopeErrorType> {}
@@ -158,10 +158,6 @@ export function initializeForkChoiceFromFinalizedState(
158
158
 
159
159
  dataAvailabilityStatus: DataAvailabilityStatus.PreData,
160
160
  payloadStatus: isForkPostGloas ? PayloadStatus.PENDING : PayloadStatus.FULL, // TODO GLOAS: Post-gloas how do we know if the checkpoint payload is FULL or EMPTY?
161
- builderIndex: isForkPostGloas ? (state as CachedBeaconStateGloas).latestExecutionPayloadBid.builderIndex : null,
162
- blockHashFromBid: isForkPostGloas
163
- ? toRootHex((state as CachedBeaconStateGloas).latestExecutionPayloadBid.blockHash)
164
- : null,
165
161
  parentBlockHash: isForkPostGloas ? toRootHex((state as CachedBeaconStateGloas).latestBlockHash) : null,
166
162
  },
167
163
  currentSlot
@@ -255,12 +251,6 @@ export function initializeForkChoiceFromUnfinalizedState(
255
251
 
256
252
  dataAvailabilityStatus: DataAvailabilityStatus.PreData,
257
253
  payloadStatus: isForkPostGloas ? PayloadStatus.PENDING : PayloadStatus.FULL, // TODO GLOAS: Post-gloas how do we know if the checkpoint payload is FULL or EMPTY?
258
- builderIndex: isForkPostGloas
259
- ? (unfinalizedState as CachedBeaconStateGloas).latestExecutionPayloadBid.builderIndex
260
- : null,
261
- blockHashFromBid: isForkPostGloas
262
- ? toRootHex((unfinalizedState as CachedBeaconStateGloas).latestExecutionPayloadBid.blockHash)
263
- : null,
264
254
  parentBlockHash: isForkPostGloas ? toRootHex((unfinalizedState as CachedBeaconStateGloas).latestBlockHash) : null,
265
255
  };
266
256
 
@@ -32,7 +32,7 @@ import {IArchiveStore} from "./archiveStore/interface.js";
32
32
  import {CheckpointBalancesCache} from "./balancesCache.js";
33
33
  import {BeaconProposerCache, ProposerPreparationData} from "./beaconProposerCache.js";
34
34
  import {IBlockInput} from "./blocks/blockInput/index.js";
35
- import {ImportBlockOpts} from "./blocks/types.js";
35
+ import {ImportBlockOpts, ImportPayloadOpts} from "./blocks/types.js";
36
36
  import {IBlsVerifier} from "./bls/index.js";
37
37
  import {ColumnReconstructionTracker} from "./ColumnReconstructionTracker.js";
38
38
  import {ChainEventEmitter} from "./emitter.js";
@@ -58,7 +58,6 @@ import {
58
58
  SeenBlockProposers,
59
59
  SeenContributionAndProof,
60
60
  SeenExecutionPayloadBids,
61
- SeenExecutionPayloadEnvelopes,
62
61
  SeenPayloadAttesters,
63
62
  SeenSyncCommitteeMessages,
64
63
  } from "./seenCache/index.js";
@@ -66,6 +65,7 @@ import {SeenAggregatedAttestations} from "./seenCache/seenAggregateAndProof.js";
66
65
  import {SeenAttestationDatas} from "./seenCache/seenAttestationData.js";
67
66
  import {SeenBlockAttesters} from "./seenCache/seenBlockAttesters.js";
68
67
  import {SeenBlockInput} from "./seenCache/seenGossipBlockInput.js";
68
+ import {PayloadEnvelopeInput, SeenPayloadEnvelopeInput} from "./seenCache/seenPayloadEnvelopeInput.js";
69
69
  import {ShufflingCache} from "./shufflingCache.js";
70
70
  import {ValidatorMonitor} from "./validatorMonitor.js";
71
71
 
@@ -128,13 +128,13 @@ export interface IBeaconChain {
128
128
  readonly seenAggregators: SeenAggregators;
129
129
  readonly seenPayloadAttesters: SeenPayloadAttesters;
130
130
  readonly seenAggregatedAttestations: SeenAggregatedAttestations;
131
- readonly seenExecutionPayloadEnvelopes: SeenExecutionPayloadEnvelopes;
132
131
  readonly seenExecutionPayloadBids: SeenExecutionPayloadBids;
133
132
  readonly seenBlockProposers: SeenBlockProposers;
134
133
  readonly seenSyncCommitteeMessages: SeenSyncCommitteeMessages;
135
134
  readonly seenContributionAndProof: SeenContributionAndProof;
136
135
  readonly seenAttestationDatas: SeenAttestationDatas;
137
136
  readonly seenBlockInputCache: SeenBlockInput;
137
+ readonly seenPayloadEnvelopeInputCache: SeenPayloadEnvelopeInput;
138
138
  // Seen cache for liveness checks
139
139
  readonly seenBlockAttesters: SeenBlockAttesters;
140
140
 
@@ -242,6 +242,9 @@ export interface IBeaconChain {
242
242
  /** Process a chain of blocks until complete */
243
243
  processChainSegment(blocks: IBlockInput[], opts?: ImportBlockOpts): Promise<void>;
244
244
 
245
+ /** Process execution payload envelope: verify, import to fork choice, and persist to DB */
246
+ processExecutionPayload(payloadInput: PayloadEnvelopeInput, opts?: ImportPayloadOpts): Promise<void>;
247
+
245
248
  getStatus(): Status;
246
249
 
247
250
  recomputeForkChoiceHead(caller: ForkchoiceCaller): ProtoBlock;
@@ -41,7 +41,7 @@ export function isValidBlsToExecutionChangeForBlockInclusion(
41
41
  state: CachedBeaconStateAllForks,
42
42
  signedBLSToExecutionChange: capella.SignedBLSToExecutionChange
43
43
  ): boolean {
44
- // For each condition from https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/beacon-chain.md#new-process_bls_to_execution_change
44
+ // For each condition from https://github.com/ethereum/consensus-specs/blob/v1.6.1/specs/capella/beacon-chain.md#new-process_bls_to_execution_change
45
45
  //
46
46
  // 1. assert address_change.validator_index < len(state.validators):
47
47
  // If valid before will always be valid in the future, no need to check
@@ -73,7 +73,12 @@ export function computeEnvelopeStateRoot(
73
73
  };
74
74
 
75
75
  const processEnvelopeTimer = metrics?.blockPayload.executionPayloadEnvelopeProcessingTime.startTimer();
76
- const postEnvelopeState = processExecutionPayloadEnvelope(postBlockState, signedEnvelope, false, {
76
+ const postEnvelopeState = processExecutionPayloadEnvelope(postBlockState, signedEnvelope, {
77
+ // Signature is zero-ed (G2_POINT_AT_INFINITY), skip verification
78
+ verifySignature: false,
79
+ // State root is being computed here, the envelope doesn't have it yet
80
+ verifyStateRoot: false,
81
+ // Preserve cache in source state, since the resulting state is not added to the state cache
77
82
  dontTransferCache: true,
78
83
  });
79
84
  processEnvelopeTimer?.();
@@ -441,7 +441,7 @@ export async function produceBlockBody<T extends BlockType>(
441
441
  parentBlockRoot: toRootHex(parentBlockRoot),
442
442
  feeRecipient,
443
443
  });
444
- // https://github.com/ethereum/consensus-specs/blob/dev/specs/deneb/validator.md#constructing-the-beaconblockbody
444
+ // https://github.com/ethereum/consensus-specs/blob/v1.6.1/specs/deneb/validator.md#constructing-the-beaconblockbody
445
445
  const prepareRes = await prepareExecutionPayload(
446
446
  this,
447
447
  this.logger,
@@ -9,8 +9,10 @@ export enum RegenCaller {
9
9
  processBlock = "processBlock",
10
10
  produceBlock = "produceBlock",
11
11
  validateGossipBlock = "validateGossipBlock",
12
+ validateGossipPayloadEnvelope = "validateGossipPayloadEnvelope",
12
13
  validateGossipBlob = "validateGossipBlob",
13
14
  validateGossipDataColumn = "validateGossipDataColumn",
15
+ validateGossipExecutionPayloadEnvelope = "validateGossipExecutionPayloadEnvelope",
14
16
  precomputeEpoch = "precomputeEpoch",
15
17
  predictProposerHead = "predictProposerHead",
16
18
  produceAttestationData = "produceAttestationData",
@@ -3,5 +3,5 @@ export {SeenBlockProposers} from "./seenBlockProposers.js";
3
3
  export {SeenSyncCommitteeMessages} from "./seenCommittee.js";
4
4
  export {SeenContributionAndProof} from "./seenCommitteeContribution.js";
5
5
  export {SeenExecutionPayloadBids} from "./seenExecutionPayloadBids.js";
6
- export {SeenExecutionPayloadEnvelopes} from "./seenExecutionPayloadEnvelope.js";
7
6
  export {SeenBlockInput} from "./seenGossipBlockInput.js";
7
+ export {PayloadEnvelopeInput, SeenPayloadEnvelopeInput} from "./seenPayloadEnvelopeInput.js";
@@ -180,7 +180,7 @@ export class SeenBlockInput {
180
180
  blockInput = this.blockInputs.get(parentRootHex ?? "");
181
181
  parentRootHex = blockInput?.parentRootHex;
182
182
  }
183
- this.logger?.debug(`BlockInputCache.prune deleted ${deletedCount} cached BlockInputs`);
183
+ this.logger?.debug("BlockInputCache.prune deleted cached BlockInputs", {deletedCount});
184
184
  this.pruneToMaxSize();
185
185
  }
186
186
 
@@ -193,7 +193,7 @@ export class SeenBlockInput {
193
193
  this.evictBlockInput(blockInput);
194
194
  }
195
195
  }
196
- this.logger?.debug(`BlockInputCache.onFinalized deleted ${deletedCount} cached BlockInputs`);
196
+ this.logger?.debug("BlockInputCache.onFinalized deleted cached BlockInputs", {deletedCount});
197
197
  this.pruneToMaxSize();
198
198
  };
199
199
 
@@ -0,0 +1,106 @@
1
+ import {CheckpointWithHex} from "@lodestar/fork-choice";
2
+ import {computeStartSlotAtEpoch} from "@lodestar/state-transition";
3
+ import {RootHex} from "@lodestar/types";
4
+ import {Logger} from "@lodestar/utils";
5
+ import {Metrics} from "../../metrics/metrics.js";
6
+ import {SerializedCache} from "../../util/serializedCache.js";
7
+ import {CreateFromBlockProps, PayloadEnvelopeInput} from "../blocks/payloadEnvelopeInput/index.js";
8
+ import {ChainEvent, ChainEventEmitter} from "../emitter.js";
9
+
10
+ export type {PayloadEnvelopeInputState} from "../blocks/payloadEnvelopeInput/index.js";
11
+ export {PayloadEnvelopeInput} from "../blocks/payloadEnvelopeInput/index.js";
12
+
13
+ export type SeenPayloadEnvelopeInputModules = {
14
+ chainEvents: ChainEventEmitter;
15
+ signal: AbortSignal;
16
+ serializedCache: SerializedCache;
17
+ metrics: Metrics | null;
18
+ logger?: Logger;
19
+ };
20
+
21
+ /**
22
+ * Cache for tracking PayloadEnvelopeInput instances, keyed by beacon block root.
23
+ *
24
+ * Created during block import when a block is processed.
25
+ * Pruned on finalization and after payload is written to DB.
26
+ */
27
+ export class SeenPayloadEnvelopeInput {
28
+ private readonly chainEvents: ChainEventEmitter;
29
+ private readonly signal: AbortSignal;
30
+ private readonly serializedCache: SerializedCache;
31
+ private readonly metrics: Metrics | null;
32
+ private readonly logger?: Logger;
33
+ private payloadInputs = new Map<RootHex, PayloadEnvelopeInput>();
34
+
35
+ constructor({chainEvents, signal, serializedCache, metrics, logger}: SeenPayloadEnvelopeInputModules) {
36
+ this.chainEvents = chainEvents;
37
+ this.signal = signal;
38
+ this.serializedCache = serializedCache;
39
+ this.metrics = metrics;
40
+ this.logger = logger;
41
+
42
+ if (metrics) {
43
+ metrics.seenCache.payloadEnvelopeInput.count.addCollect(() => {
44
+ metrics.seenCache.payloadEnvelopeInput.count.set(this.payloadInputs.size);
45
+ metrics.seenCache.payloadEnvelopeInput.serializedObjectRefs.set(
46
+ Array.from(this.payloadInputs.values()).reduce(
47
+ (count, payloadInput) => count + payloadInput.getSerializedCacheKeys().length,
48
+ 0
49
+ )
50
+ );
51
+ });
52
+ }
53
+
54
+ this.chainEvents.on(ChainEvent.forkChoiceFinalized, this.onFinalized);
55
+ this.signal.addEventListener("abort", () => {
56
+ this.chainEvents.off(ChainEvent.forkChoiceFinalized, this.onFinalized);
57
+ });
58
+ }
59
+
60
+ private onFinalized = (checkpoint: CheckpointWithHex): void => {
61
+ // Prune all entries with slot < finalized slot
62
+ const finalizedSlot = computeStartSlotAtEpoch(checkpoint.epoch);
63
+ let deletedCount = 0;
64
+ for (const [, input] of this.payloadInputs) {
65
+ if (input.slot < finalizedSlot) {
66
+ this.evictPayloadInput(input);
67
+ deletedCount++;
68
+ }
69
+ }
70
+ this.logger?.debug("SeenPayloadEnvelopeInput.onFinalized deleted cached entries", {deletedCount});
71
+ };
72
+
73
+ add(props: CreateFromBlockProps): PayloadEnvelopeInput {
74
+ if (this.payloadInputs.has(props.blockRootHex)) {
75
+ throw new Error(`PayloadEnvelopeInput already exists for block ${props.blockRootHex}`);
76
+ }
77
+ const input = PayloadEnvelopeInput.createFromBlock(props);
78
+ this.payloadInputs.set(props.blockRootHex, input);
79
+ this.metrics?.seenCache.payloadEnvelopeInput.created.inc();
80
+ return input;
81
+ }
82
+
83
+ get(blockRootHex: RootHex): PayloadEnvelopeInput | undefined {
84
+ return this.payloadInputs.get(blockRootHex);
85
+ }
86
+
87
+ has(blockRootHex: RootHex): boolean {
88
+ return this.payloadInputs.has(blockRootHex);
89
+ }
90
+
91
+ prune(blockRootHex: RootHex): void {
92
+ const payloadInput = this.payloadInputs.get(blockRootHex);
93
+ if (payloadInput) {
94
+ this.evictPayloadInput(payloadInput);
95
+ }
96
+ }
97
+
98
+ size(): number {
99
+ return this.payloadInputs.size;
100
+ }
101
+
102
+ private evictPayloadInput(payloadInput: PayloadEnvelopeInput): void {
103
+ this.serializedCache.delete(payloadInput.getSerializedCacheKeys());
104
+ this.payloadInputs.delete(payloadInput.blockRootHex);
105
+ }
106
+ }
@@ -1,14 +1,15 @@
1
- import {PublicKey} from "@chainsafe/blst";
1
+ import {PayloadStatus} from "@lodestar/fork-choice";
2
2
  import {
3
+ BeaconStateView,
3
4
  CachedBeaconStateGloas,
4
5
  computeStartSlotAtEpoch,
5
- createSingleSignatureSetFromComponents,
6
- getExecutionPayloadEnvelopeSigningRoot,
6
+ getExecutionPayloadEnvelopeSignatureSet,
7
7
  } from "@lodestar/state-transition";
8
8
  import {gloas} from "@lodestar/types";
9
9
  import {toRootHex} from "@lodestar/utils";
10
10
  import {ExecutionPayloadEnvelopeError, ExecutionPayloadEnvelopeErrorCode, GossipAction} from "../errors/index.js";
11
11
  import {IBeaconChain} from "../index.js";
12
+ import {RegenCaller} from "../regen/index.js";
12
13
 
13
14
  export async function validateApiExecutionPayloadEnvelope(
14
15
  chain: IBeaconChain,
@@ -47,7 +48,9 @@ async function validateExecutionPayloadEnvelope(
47
48
 
48
49
  // [IGNORE] The node has not seen another valid
49
50
  // `SignedExecutionPayloadEnvelope` for this block root from this builder.
50
- if (chain.seenExecutionPayloadEnvelopes.isKnown(blockRootHex)) {
51
+ const envelopeBlock = chain.forkChoice.getBlockHex(blockRootHex, PayloadStatus.FULL);
52
+ const payloadInput = chain.seenPayloadEnvelopeInputCache.get(blockRootHex);
53
+ if (envelopeBlock || payloadInput?.hasPayloadEnvelope()) {
51
54
  throw new ExecutionPayloadEnvelopeError(GossipAction.IGNORE, {
52
55
  code: ExecutionPayloadEnvelopeErrorCode.ENVELOPE_ALREADY_KNOWN,
53
56
  blockRoot: blockRootHex,
@@ -55,6 +58,14 @@ async function validateExecutionPayloadEnvelope(
55
58
  });
56
59
  }
57
60
 
61
+ if (!payloadInput) {
62
+ // PayloadEnvelopeInput should have been created during block import
63
+ throw new ExecutionPayloadEnvelopeError(GossipAction.IGNORE, {
64
+ code: ExecutionPayloadEnvelopeErrorCode.PAYLOAD_ENVELOPE_INPUT_MISSING,
65
+ blockRoot: blockRootHex,
66
+ });
67
+ }
68
+
58
69
  // [IGNORE] The envelope is from a slot greater than or equal to the latest finalized slot -- i.e. validate that `envelope.slot >= compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)`
59
70
  const finalizedCheckpoint = chain.forkChoice.getFinalizedCheckpoint();
60
71
  const finalizedSlot = computeStartSlotAtEpoch(finalizedCheckpoint.epoch);
@@ -79,45 +90,47 @@ async function validateExecutionPayloadEnvelope(
79
90
  });
80
91
  }
81
92
 
82
- if (block.builderIndex == null || block.blockHashFromBid == null) {
83
- // This indicates this block is a pre-gloas block which is wrong
84
- throw new ExecutionPayloadEnvelopeError(GossipAction.IGNORE, {
85
- code: ExecutionPayloadEnvelopeErrorCode.CACHE_FAIL,
86
- blockRoot: blockRootHex,
87
- });
88
- }
89
-
90
93
  // [REJECT] `envelope.builder_index == bid.builder_index`
91
- if (envelope.builderIndex !== block.builderIndex) {
94
+ if (envelope.builderIndex !== payloadInput.getBuilderIndex()) {
92
95
  throw new ExecutionPayloadEnvelopeError(GossipAction.REJECT, {
93
96
  code: ExecutionPayloadEnvelopeErrorCode.BUILDER_INDEX_MISMATCH,
94
97
  envelopeBuilderIndex: envelope.builderIndex,
95
- bidBuilderIndex: block.builderIndex,
98
+ bidBuilderIndex: payloadInput.getBuilderIndex(),
96
99
  });
97
100
  }
98
101
 
99
102
  // [REJECT] `payload.block_hash == bid.block_hash`
100
- if (toRootHex(payload.blockHash) !== block.blockHashFromBid) {
103
+ if (toRootHex(payload.blockHash) !== payloadInput.getBlockHashHex()) {
101
104
  throw new ExecutionPayloadEnvelopeError(GossipAction.REJECT, {
102
105
  code: ExecutionPayloadEnvelopeErrorCode.BLOCK_HASH_MISMATCH,
103
106
  envelopeBlockHash: toRootHex(payload.blockHash),
104
- bidBlockHash: block.blockHashFromBid,
107
+ bidBlockHash: payloadInput.getBlockHashHex(),
105
108
  });
106
109
  }
107
110
 
108
- // [REJECT] `signed_execution_payload_envelope.signature` is valid with respect to the builder's public key.
109
- const state = chain.getHeadState() as CachedBeaconStateGloas;
110
- const signatureSet = createSingleSignatureSetFromComponents(
111
- PublicKey.fromBytes(state.builders.getReadonly(envelope.builderIndex).pubkey),
112
- getExecutionPayloadEnvelopeSigningRoot(chain.config, envelope),
113
- executionPayloadEnvelope.signature
111
+ // Get the post block state which is the pre-payload state to verify the builder's signature.
112
+ const blockState = await chain.regen
113
+ .getState(block.stateRoot, RegenCaller.validateGossipPayloadEnvelope)
114
+ .catch(() => {
115
+ throw new ExecutionPayloadEnvelopeError(GossipAction.IGNORE, {
116
+ code: ExecutionPayloadEnvelopeErrorCode.UNKNOWN_BLOCK_STATE,
117
+ blockRoot: blockRootHex,
118
+ slot: envelope.slot,
119
+ });
120
+ });
121
+
122
+ const state = blockState as CachedBeaconStateGloas;
123
+ const signatureSet = getExecutionPayloadEnvelopeSignatureSet(
124
+ chain.config,
125
+ chain.pubkeyCache,
126
+ new BeaconStateView(state),
127
+ executionPayloadEnvelope,
128
+ payloadInput.proposerIndex
114
129
  );
115
130
 
116
- if (!(await chain.bls.verifySignatureSets([signatureSet]))) {
131
+ if (!(await chain.bls.verifySignatureSets([signatureSet], {verifyOnMainThread: true}))) {
117
132
  throw new ExecutionPayloadEnvelopeError(GossipAction.REJECT, {
118
133
  code: ExecutionPayloadEnvelopeErrorCode.INVALID_SIGNATURE,
119
134
  });
120
135
  }
121
-
122
- chain.seenExecutionPayloadEnvelopes.add(blockRootHex, envelope.slot);
123
136
  }
@@ -6,7 +6,7 @@ import {LightClientError, LightClientErrorCode} from "../errors/lightClientError
6
6
  import {IBeaconChain} from "../interface.js";
7
7
  import {updateReceivedTooEarly} from "./lightClientOptimisticUpdate.js";
8
8
 
9
- // https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/p2p-interface.md#light_client_finality_update
9
+ // https://github.com/ethereum/consensus-specs/blob/v1.6.1/specs/altair/light-client/p2p-interface.md#light_client_finality_update
10
10
  export function validateLightClientFinalityUpdate(
11
11
  config: ChainForkConfig,
12
12
  chain: IBeaconChain,
@@ -6,7 +6,7 @@ import {GossipAction} from "../errors/index.js";
6
6
  import {LightClientError, LightClientErrorCode} from "../errors/lightClientError.js";
7
7
  import {IBeaconChain} from "../interface.js";
8
8
 
9
- // https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/light-client/p2p-interface.md#light_client_optimistic_update
9
+ // https://github.com/ethereum/consensus-specs/blob/v1.6.1/specs/altair/light-client/p2p-interface.md#light_client_optimistic_update
10
10
  export function validateLightClientOptimisticUpdate(
11
11
  config: ChainForkConfig,
12
12
  chain: IBeaconChain,
@@ -23,6 +23,7 @@ import {
23
23
  ValidatorIndex,
24
24
  altair,
25
25
  deneb,
26
+ gloas,
26
27
  } from "@lodestar/types";
27
28
  import {LogData, LogHandler, LogLevel, Logger, MapDef, MapDefMax, prettyPrintIndices, toRootHex} from "@lodestar/utils";
28
29
  import {GENESIS_SLOT} from "../constants/constants.js";
@@ -61,6 +62,11 @@ export type ValidatorMonitor = {
61
62
  ): void;
62
63
  registerBeaconBlock(src: OpSource, delaySec: Seconds, block: BeaconBlock): void;
63
64
  registerBlobSidecar(src: OpSource, seenTimestampSec: Seconds, blob: deneb.BlobSidecar): void;
65
+ registerExecutionPayloadEnvelope(
66
+ src: OpSource,
67
+ delaySec: Seconds,
68
+ envelope: gloas.SignedExecutionPayloadEnvelope
69
+ ): void;
64
70
  registerImportedBlock(block: BeaconBlock, data: {proposerBalanceDelta: number}): void;
65
71
  onPoolSubmitUnaggregatedAttestation(
66
72
  seenTimestampSec: number,
@@ -450,6 +456,10 @@ export function createValidatorMonitor(
450
456
  //TODO: freetheblobs
451
457
  },
452
458
 
459
+ registerExecutionPayloadEnvelope(_src, _delaySec, _envelope) {
460
+ // TODO GLOAS: implement execution payload envelope monitoring
461
+ },
462
+
453
463
  registerImportedBlock(block, {proposerBalanceDelta}) {
454
464
  const validator = validators.get(block.proposerIndex);
455
465
  if (validator) {
@@ -889,7 +899,7 @@ function renderAttestationSummary(
889
899
  summary: AttestationSummary | undefined,
890
900
  flags: ParticipationFlags
891
901
  ): string {
892
- // Reference https://github.com/ethereum/consensus-specs/blob/dev/specs/altair/beacon-chain.md#get_attestation_participation_flag_indices
902
+ // Reference https://github.com/ethereum/consensus-specs/blob/v1.6.1/specs/altair/beacon-chain.md#get_attestation_participation_flag_indices
893
903
  //
894
904
  // is_matching_source = data.source == justified_checkpoint
895
905
  // is_matching_target = is_matching_source and data.target.root == get_block_root(state, data.target.epoch)