@lodestar/beacon-node 1.51.0-dev.50ed45c251 → 1.51.0-dev.5619357e93

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 (177) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +17 -27
  3. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  4. package/lib/api/impl/beacon/pool/index.d.ts.map +1 -1
  5. package/lib/api/impl/beacon/pool/index.js +5 -2
  6. package/lib/api/impl/beacon/pool/index.js.map +1 -1
  7. package/lib/api/impl/beacon/state/utils.d.ts +1 -1
  8. package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
  9. package/lib/chain/GetBlobsTracker.d.ts.map +1 -1
  10. package/lib/chain/GetBlobsTracker.js +4 -2
  11. package/lib/chain/GetBlobsTracker.js.map +1 -1
  12. package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
  13. package/lib/chain/archiveStore/archiveStore.js +1 -0
  14. package/lib/chain/archiveStore/archiveStore.js.map +1 -1
  15. package/lib/chain/blocks/importExecutionPayload.d.ts +4 -1
  16. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  17. package/lib/chain/blocks/importExecutionPayload.js +6 -1
  18. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  19. package/lib/chain/blocks/payloadEnvelopeProcessor.js +2 -2
  20. package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
  21. package/lib/chain/blocks/verifyBlocksDataAvailability.d.ts.map +1 -1
  22. package/lib/chain/blocks/verifyBlocksDataAvailability.js +8 -1
  23. package/lib/chain/blocks/verifyBlocksDataAvailability.js.map +1 -1
  24. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts.map +1 -1
  25. package/lib/chain/blocks/verifyPayloadsDataAvailability.js +8 -1
  26. package/lib/chain/blocks/verifyPayloadsDataAvailability.js.map +1 -1
  27. package/lib/chain/bls/multithread/index.js +5 -5
  28. package/lib/chain/bls/multithread/index.js.map +1 -1
  29. package/lib/chain/bls/multithread/types.d.ts +1 -1
  30. package/lib/chain/bls/multithread/types.d.ts.map +1 -1
  31. package/lib/chain/bls/multithread/worker.js +1 -1
  32. package/lib/chain/bls/multithread/worker.js.map +1 -1
  33. package/lib/chain/bls/singleThread.js +1 -1
  34. package/lib/chain/bls/singleThread.js.map +1 -1
  35. package/lib/chain/bls/utils.js +1 -1
  36. package/lib/chain/bls/utils.js.map +1 -1
  37. package/lib/chain/chain.d.ts +1 -1
  38. package/lib/chain/chain.d.ts.map +1 -1
  39. package/lib/chain/chain.js.map +1 -1
  40. package/lib/chain/errors/blockError.d.ts +1 -1
  41. package/lib/chain/errors/blockError.d.ts.map +1 -1
  42. package/lib/chain/errors/blockError.js +1 -1
  43. package/lib/chain/errors/blockError.js.map +1 -1
  44. package/lib/chain/interface.d.ts +2 -3
  45. package/lib/chain/interface.d.ts.map +1 -1
  46. package/lib/chain/interface.js.map +1 -1
  47. package/lib/chain/opPools/aggregatedAttestationPool.d.ts.map +1 -1
  48. package/lib/chain/opPools/aggregatedAttestationPool.js +23 -10
  49. package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
  50. package/lib/chain/opPools/attestationPool.d.ts +1 -1
  51. package/lib/chain/opPools/attestationPool.d.ts.map +1 -1
  52. package/lib/chain/opPools/attestationPool.js +15 -4
  53. package/lib/chain/opPools/attestationPool.js.map +1 -1
  54. package/lib/chain/opPools/payloadAttestationPool.d.ts.map +1 -1
  55. package/lib/chain/opPools/payloadAttestationPool.js +17 -7
  56. package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
  57. package/lib/chain/opPools/syncCommitteeMessagePool.d.ts.map +1 -1
  58. package/lib/chain/opPools/syncCommitteeMessagePool.js +9 -3
  59. package/lib/chain/opPools/syncCommitteeMessagePool.js.map +1 -1
  60. package/lib/chain/opPools/syncContributionAndProofPool.d.ts.map +1 -1
  61. package/lib/chain/opPools/syncContributionAndProofPool.js +11 -3
  62. package/lib/chain/opPools/syncContributionAndProofPool.js.map +1 -1
  63. package/lib/chain/opPools/utils.d.ts +1 -1
  64. package/lib/chain/opPools/utils.d.ts.map +1 -1
  65. package/lib/chain/opPools/utils.js +1 -1
  66. package/lib/chain/opPools/utils.js.map +1 -1
  67. package/lib/chain/options.d.ts +0 -1
  68. package/lib/chain/options.d.ts.map +1 -1
  69. package/lib/chain/options.js +0 -1
  70. package/lib/chain/options.js.map +1 -1
  71. package/lib/execution/engine/index.d.ts +1 -1
  72. package/lib/execution/engine/index.d.ts.map +1 -1
  73. package/lib/execution/engine/index.js +1 -1
  74. package/lib/execution/engine/index.js.map +1 -1
  75. package/lib/execution/engine/interface.d.ts +1 -1
  76. package/lib/execution/engine/interface.d.ts.map +1 -1
  77. package/lib/execution/engine/interface.js.map +1 -1
  78. package/lib/execution/engine/types.d.ts.map +1 -1
  79. package/lib/execution/engine/types.js +2 -2
  80. package/lib/execution/engine/types.js.map +1 -1
  81. package/lib/metrics/metrics/lodestar.d.ts +3 -0
  82. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  83. package/lib/metrics/metrics/lodestar.js +5 -0
  84. package/lib/metrics/metrics/lodestar.js.map +1 -1
  85. package/lib/monitoring/service.js +1 -1
  86. package/lib/monitoring/service.js.map +1 -1
  87. package/lib/network/core/networkCore.d.ts +2 -0
  88. package/lib/network/core/networkCore.d.ts.map +1 -1
  89. package/lib/network/core/networkCore.js +3 -0
  90. package/lib/network/core/networkCore.js.map +1 -1
  91. package/lib/network/core/networkCoreWorker.js +1 -0
  92. package/lib/network/core/networkCoreWorker.js.map +1 -1
  93. package/lib/network/core/networkCoreWorkerHandler.d.ts +2 -0
  94. package/lib/network/core/networkCoreWorkerHandler.d.ts.map +1 -1
  95. package/lib/network/core/networkCoreWorkerHandler.js +3 -0
  96. package/lib/network/core/networkCoreWorkerHandler.js.map +1 -1
  97. package/lib/network/core/types.d.ts +2 -0
  98. package/lib/network/core/types.d.ts.map +1 -1
  99. package/lib/network/interface.d.ts +2 -0
  100. package/lib/network/interface.d.ts.map +1 -1
  101. package/lib/network/network.d.ts +2 -0
  102. package/lib/network/network.d.ts.map +1 -1
  103. package/lib/network/network.js +6 -1
  104. package/lib/network/network.js.map +1 -1
  105. package/lib/network/peers/peerManager.d.ts +2 -1
  106. package/lib/network/peers/peerManager.d.ts.map +1 -1
  107. package/lib/network/peers/peerManager.js.map +1 -1
  108. package/lib/network/peers/utils/assertPeerRelevance.d.ts +9 -1
  109. package/lib/network/peers/utils/assertPeerRelevance.d.ts.map +1 -1
  110. package/lib/network/peers/utils/assertPeerRelevance.js +32 -21
  111. package/lib/network/peers/utils/assertPeerRelevance.js.map +1 -1
  112. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  113. package/lib/network/processor/gossipHandlers.js +6 -5
  114. package/lib/network/processor/gossipHandlers.js.map +1 -1
  115. package/lib/node/nodejs.d.ts +1 -1
  116. package/lib/node/nodejs.d.ts.map +1 -1
  117. package/lib/node/nodejs.js +1 -1
  118. package/lib/node/nodejs.js.map +1 -1
  119. package/lib/node/options.d.ts +1 -1
  120. package/lib/node/options.d.ts.map +1 -1
  121. package/lib/node/options.js +1 -1
  122. package/lib/node/options.js.map +1 -1
  123. package/lib/sync/interface.d.ts.map +1 -1
  124. package/lib/sync/interface.js.map +1 -1
  125. package/lib/sync/sync.d.ts +7 -0
  126. package/lib/sync/sync.d.ts.map +1 -1
  127. package/lib/sync/sync.js +61 -3
  128. package/lib/sync/sync.js.map +1 -1
  129. package/lib/util/queue/itemQueue.js +1 -1
  130. package/lib/util/queue/itemQueue.js.map +1 -1
  131. package/lib/util/sszBytes.js +2 -2
  132. package/lib/util/sszBytes.js.map +1 -1
  133. package/package.json +16 -16
  134. package/src/api/impl/beacon/blocks/index.ts +35 -45
  135. package/src/api/impl/beacon/pool/index.ts +5 -1
  136. package/src/api/impl/beacon/state/utils.ts +1 -1
  137. package/src/chain/GetBlobsTracker.ts +4 -2
  138. package/src/chain/archiveStore/archiveStore.ts +1 -0
  139. package/src/chain/blocks/importExecutionPayload.ts +11 -1
  140. package/src/chain/blocks/payloadEnvelopeProcessor.ts +2 -2
  141. package/src/chain/blocks/verifyBlocksDataAvailability.ts +10 -1
  142. package/src/chain/blocks/verifyPayloadsDataAvailability.ts +10 -1
  143. package/src/chain/bls/multithread/index.ts +5 -5
  144. package/src/chain/bls/multithread/types.ts +1 -1
  145. package/src/chain/bls/multithread/worker.ts +1 -5
  146. package/src/chain/bls/singleThread.ts +1 -1
  147. package/src/chain/bls/utils.ts +1 -1
  148. package/src/chain/chain.ts +1 -1
  149. package/src/chain/errors/blockError.ts +1 -1
  150. package/src/chain/interface.ts +2 -3
  151. package/src/chain/opPools/aggregatedAttestationPool.ts +25 -9
  152. package/src/chain/opPools/attestationPool.ts +16 -4
  153. package/src/chain/opPools/payloadAttestationPool.ts +18 -7
  154. package/src/chain/opPools/syncCommitteeMessagePool.ts +10 -3
  155. package/src/chain/opPools/syncContributionAndProofPool.ts +13 -3
  156. package/src/chain/opPools/utils.ts +1 -1
  157. package/src/chain/options.ts +0 -2
  158. package/src/execution/engine/index.ts +1 -1
  159. package/src/execution/engine/interface.ts +1 -1
  160. package/src/execution/engine/types.ts +3 -1
  161. package/src/metrics/metrics/lodestar.ts +5 -0
  162. package/src/monitoring/service.ts +1 -1
  163. package/src/network/core/networkCore.ts +5 -0
  164. package/src/network/core/networkCoreWorker.ts +1 -0
  165. package/src/network/core/networkCoreWorkerHandler.ts +4 -0
  166. package/src/network/core/types.ts +2 -0
  167. package/src/network/interface.ts +2 -0
  168. package/src/network/network.ts +8 -1
  169. package/src/network/peers/peerManager.ts +1 -1
  170. package/src/network/peers/utils/assertPeerRelevance.ts +39 -23
  171. package/src/network/processor/gossipHandlers.ts +6 -5
  172. package/src/node/nodejs.ts +6 -6
  173. package/src/node/options.ts +4 -5
  174. package/src/sync/interface.ts +1 -0
  175. package/src/sync/sync.ts +65 -4
  176. package/src/util/queue/itemQueue.ts +1 -1
  177. package/src/util/sszBytes.ts +2 -2
@@ -316,18 +316,8 @@ export function getBeaconBlockApi(
316
316
  break;
317
317
  }
318
318
 
319
- case routes.beacon.BroadcastValidation.none: {
320
- chain.logger.debug("Skipping broadcast validation", valLogMeta);
321
- break;
322
- }
323
-
324
319
  default: {
325
- // error or log warning we do not support this validation
326
- const message = `Broadcast validation of ${broadcastValidation} type not implemented yet`;
327
- if (chain.opts.broadcastValidationStrictness === "error") {
328
- throw Error(message);
329
- }
330
- chain.logger.warn(message, valLogMeta);
320
+ throw new ApiError(400, `Invalid broadcast validation level ${broadcastValidation}`);
331
321
  }
332
322
  }
333
323
 
@@ -397,26 +387,24 @@ export function getBeaconBlockApi(
397
387
  ...blobSidecars.map((blobSidecar) => () => network.publishBlobSidecar(blobSidecar)),
398
388
  () =>
399
389
  // there is no rush to persist block since we published it to gossip anyway
400
- chain
401
- .processBlock(blockForImport, opts)
402
- .catch((e) => {
403
- if (e instanceof BlockError) {
404
- switch (e.type.code) {
405
- case BlockErrorCode.ALREADY_KNOWN:
406
- // Block was imported while publishing, e.g. received via gossip
407
- chain.logger.debug("Ignoring already-known block during publishing", valLogMeta);
408
- return;
409
- case BlockErrorCode.PARENT_BLOCK_UNKNOWN:
410
- case BlockErrorCode.PARENT_PAYLOAD_UNKNOWN:
411
- chain.emitter.emit(ChainEvent.blockUnknownParent, {
412
- blockInput: blockForImport,
413
- peer: IDENTITY_PEER_ID,
414
- source: BlockInputSource.api,
415
- });
416
- }
390
+ chain.processBlock(blockForImport, opts).catch((e) => {
391
+ if (e instanceof BlockError) {
392
+ switch (e.type.code) {
393
+ case BlockErrorCode.ALREADY_KNOWN:
394
+ // Block was imported while publishing, e.g. received via gossip
395
+ chain.logger.debug("Ignoring already-known block during publishing", valLogMeta);
396
+ return;
397
+ case BlockErrorCode.PARENT_BLOCK_UNKNOWN:
398
+ case BlockErrorCode.PARENT_PAYLOAD_UNKNOWN:
399
+ chain.emitter.emit(ChainEvent.blockUnknownParent, {
400
+ blockInput: blockForImport,
401
+ peer: IDENTITY_PEER_ID,
402
+ source: BlockInputSource.api,
403
+ });
417
404
  }
418
- throw e;
419
- }),
405
+ }
406
+ throw e;
407
+ }),
420
408
  ];
421
409
  const sentPeersArr = await promiseAllMaybeAsync<{sentPeers: number; alreadyPublished: boolean} | number | void>(
422
410
  publishPromises
@@ -804,11 +792,6 @@ export function getBeaconBlockApi(
804
792
  };
805
793
  try {
806
794
  switch (broadcastValidation) {
807
- case routes.beacon.BroadcastValidation.none: {
808
- chain.logger.debug("Skipping broadcast validation of execution payload envelope", valLogMeta);
809
- break;
810
- }
811
-
812
795
  case routes.beacon.BroadcastValidation.gossip: {
813
796
  await validateApiExecutionPayloadEnvelope(chain, signedExecutionPayloadEnvelope);
814
797
  break;
@@ -847,11 +830,7 @@ export function getBeaconBlockApi(
847
830
  }
848
831
 
849
832
  default: {
850
- const message = `Broadcast validation of ${broadcastValidation} type not implemented yet`;
851
- if (chain.opts.broadcastValidationStrictness === "error") {
852
- throw Error(message);
853
- }
854
- chain.logger.warn(message, valLogMeta);
833
+ throw new ApiError(400, `Invalid broadcast validation level ${broadcastValidation}`);
855
834
  }
856
835
  }
857
836
  } catch (error) {
@@ -1003,9 +982,13 @@ export function getBeaconBlockApi(
1003
982
  () => network.publishSignedExecutionPayloadEnvelope(signedExecutionPayloadEnvelope),
1004
983
  // Publish all data column sidecars
1005
984
  ...dataColumnSidecars.map((dataColumnSidecar) => () => network.publishDataColumnSidecar(dataColumnSidecar)),
1006
- // Import execution payload. Signature is verified during broadcast validation, an already
1007
- // known envelope was verified by its original source and `none` deliberately skips validation
1008
- () => chain.processExecutionPayload(payloadInput, {validSignature: true}),
985
+ // Import execution payload
986
+ () =>
987
+ chain.processExecutionPayload(payloadInput, {
988
+ // Signature is verified during broadcast validation only for the submitted envelope,
989
+ // an envelope cached by another source is verified at import
990
+ validSignature: payloadInput.getPayloadEnvelope() === signedExecutionPayloadEnvelope,
991
+ }),
1009
992
  ];
1010
993
 
1011
994
  const publishPromise = promiseAllMaybeAsync<{sentPeers: number; alreadyPublished: boolean} | number | void>(
@@ -1109,7 +1092,7 @@ export function getBeaconBlockApi(
1109
1092
  },
1110
1093
 
1111
1094
  async getSignedExecutionPayloadEnvelope({blockId}, context) {
1112
- const {block, executionOptimistic, finalized} = await getBlockResponse(chain, blockId);
1095
+ const {block, finalized} = await getBlockResponse(chain, blockId);
1113
1096
  const slot = block.message.slot;
1114
1097
  const fork = config.getForkName(slot);
1115
1098
 
@@ -1123,6 +1106,13 @@ export function getBeaconBlockApi(
1123
1106
  const blockRoot = config.getForkTypes(slot).BeaconBlock.hashTreeRoot(block.message);
1124
1107
  const blockRootHex = toRootHex(blockRoot);
1125
1108
 
1109
+ // The block's own flag is the status of the payload it builds on, the envelope's is that of its
1110
+ // FULL variant. An unfinalized block without one has not imported its envelope yet.
1111
+ const payload = finalized ? null : chain.forkChoice.getBlockHex(blockRootHex, PayloadStatus.FULL);
1112
+ if (!finalized && payload === null) {
1113
+ throw new ApiError(404, `Execution payload envelope not found for slot=${slot}, blockRoot=${blockRootHex}`);
1114
+ }
1115
+
1126
1116
  let data: Uint8Array | gloas.SignedExecutionPayloadEnvelope | null;
1127
1117
  try {
1128
1118
  data = context?.returnBytes
@@ -1147,7 +1137,7 @@ export function getBeaconBlockApi(
1147
1137
 
1148
1138
  return {
1149
1139
  data,
1150
- meta: {executionOptimistic, finalized, version: fork},
1140
+ meta: {executionOptimistic: payload !== null && isOptimisticBlock(payload), finalized, version: fork},
1151
1141
  };
1152
1142
  },
1153
1143
 
@@ -17,6 +17,7 @@ import {
17
17
  PayloadAttestationError,
18
18
  PayloadAttestationErrorCode,
19
19
  SyncCommitteeError,
20
+ SyncCommitteeErrorCode,
20
21
  } from "../../../../chain/errors/index.js";
21
22
  import {validateApiAttesterSlashing} from "../../../../chain/validation/attesterSlashing.js";
22
23
  import {validateApiBlsToExecutionChange} from "../../../../chain/validation/blsToExecutionChange.js";
@@ -340,7 +341,10 @@ export function getBeaconPoolApi({
340
341
  const synCommittee = state.getIndexedSyncCommittee(signature.slot);
341
342
  const indexesInCommittee = synCommittee.validatorIndexMap.get(signature.validatorIndex);
342
343
  if (indexesInCommittee === undefined || indexesInCommittee.length === 0) {
343
- return; // Not a sync committee member
344
+ throw new SyncCommitteeError(GossipAction.REJECT, {
345
+ code: SyncCommitteeErrorCode.VALIDATOR_NOT_IN_SYNC_COMMITTEE,
346
+ validatorIndex: signature.validatorIndex,
347
+ });
344
348
  }
345
349
 
346
350
  // Verify signature only, all other data is very likely to be correct, since the `signature` object is created by this node.
@@ -1,6 +1,6 @@
1
- import {type PubkeyCache} from "@chainsafe/lodestar-z/pubkeys";
2
1
  import {routes} from "@lodestar/api";
3
2
  import {CheckpointWithHex, IForkChoice} from "@lodestar/fork-choice";
3
+ import {type PubkeyCache} from "@lodestar/native/pubkeys";
4
4
  import {GENESIS_SLOT} from "@lodestar/params";
5
5
  import {IBeaconStateView, IBeaconStateViewGloas} from "@lodestar/state-transition";
6
6
  import {
@@ -158,8 +158,10 @@ export class GetBlobsTracker {
158
158
 
159
159
  private retryPendingTrigger(input: IBlockInput | PayloadEnvelopeInput, requestFailed: boolean): void {
160
160
  // Triggers dropped while the request was in flight re-enter once it failed, the attempt that was just
161
- // recorded makes this arm the trailing retry instead of sending another request right away
162
- if (this.pendingTriggers.delete(input.blockRootHex) && requestFailed) {
161
+ // recorded makes this arm the trailing retry instead of sending another request right away.
162
+ // Post-gloas only the bid triggers a request, so every failed attempt re-enters to arm its own retry
163
+ const hadPendingTrigger = this.pendingTriggers.delete(input.blockRootHex);
164
+ if (requestFailed && (hadPendingTrigger || input instanceof PayloadEnvelopeInput)) {
163
165
  this.triggerGetBlobs(input);
164
166
  }
165
167
  }
@@ -197,6 +197,7 @@ export class ArchiveStore {
197
197
  //
198
198
  // `jobQueue.push()` can throw synchronously (queue aborted / full) or reject asynchronously;
199
199
  // awaiting it inside the deferred callback funnels both failure modes into the one catch.
200
+ // biome-ignore lint/nursery/noMisusedPromises: the callback catches all errors itself
200
201
  callInNextEventLoop(async () => {
201
202
  try {
202
203
  await this.jobQueue.push(finalized);
@@ -37,6 +37,7 @@ export enum PayloadErrorCode {
37
37
  MISS_BLOCK_STATE = "PAYLOAD_ERROR_MISS_BLOCK_STATE",
38
38
  ENVELOPE_VERIFICATION_ERROR = "PAYLOAD_ERROR_ENVELOPE_VERIFICATION_ERROR",
39
39
  INVALID_SIGNATURE = "PAYLOAD_ERROR_INVALID_SIGNATURE",
40
+ DATA_UNAVAILABLE = "PAYLOAD_ERROR_DATA_UNAVAILABLE",
40
41
  }
41
42
 
42
43
  export type PayloadErrorType =
@@ -64,6 +65,9 @@ export type PayloadErrorType =
64
65
  }
65
66
  | {
66
67
  code: PayloadErrorCode.INVALID_SIGNATURE;
68
+ }
69
+ | {
70
+ code: PayloadErrorCode.DATA_UNAVAILABLE;
67
71
  };
68
72
 
69
73
  export class PayloadError extends Error {
@@ -329,7 +333,13 @@ export async function importExecutionPayload(
329
333
 
330
334
  // 7. Queue notifyForkchoiceUpdate to engine api
331
335
  const head = this.forkChoice.getHead();
332
- if (!this.opts.disableImportExecutionFcU && blockRootHex === head.blockRoot) {
336
+ if (
337
+ !this.opts.disableImportExecutionFcU &&
338
+ blockRootHex === head.blockRoot &&
339
+ // Skip a payload that does not satisfy the inclusion list constraints, fork choice keeps the EMPTY
340
+ // variant as head and the next prepare fcU keeps the engine on the parent payload
341
+ this.forkChoice.isPayloadInclusionListSatisfied(blockRootHex)
342
+ ) {
333
343
  const safeBlockHash = getSafeExecutionBlockHash(this.forkChoice, this.logger);
334
344
  const finalizedBlockHash = getFinalizedExecutionBlockHash(this.forkChoice);
335
345
  this.executionEngine.notifyForkchoiceUpdate(fork, blockHashHex, safeBlockHash, finalizedBlockHash).catch((e) => {
@@ -35,7 +35,7 @@ export class PayloadEnvelopeProcessor {
35
35
 
36
36
  async processPayloadEnvelopeJob(payloadInput: PayloadEnvelopeInput, opts: ImportPayloadOpts = {}): Promise<void> {
37
37
  const existing = this.imports.get(payloadInput);
38
- if (existing) {
38
+ if (existing !== undefined) {
39
39
  return existing;
40
40
  }
41
41
 
@@ -43,7 +43,7 @@ export class PayloadEnvelopeProcessor {
43
43
 
44
44
  // Re-check after await, as another call may have queued this payload.
45
45
  const queued = this.imports.get(payloadInput);
46
- if (queued) {
46
+ if (queued !== undefined) {
47
47
  return queued;
48
48
  }
49
49
 
@@ -1,4 +1,6 @@
1
1
  import {DataAvailabilityStatus} from "@lodestar/state-transition";
2
+ import {TimeoutError} from "@lodestar/utils";
3
+ import {BlockError, BlockErrorCode} from "../errors/index.js";
2
4
  import {DAData, DAType, IBlockInput} from "./blockInput/index.js";
3
5
 
4
6
  // we can now wait for full 12 seconds because unavailable block sync will try pulling
@@ -22,7 +24,14 @@ export async function verifyBlocksDataAvailability(
22
24
  for (const blockInput of blocks) {
23
25
  // block verification is triggered on a verified gossip block so we only need to wait for all data
24
26
  if (!blockInput.hasAllData()) {
25
- promises.push(blockInput.waitForAllData(BLOB_AVAILABILITY_TIMEOUT, signal));
27
+ promises.push(
28
+ blockInput.waitForAllData(BLOB_AVAILABILITY_TIMEOUT, signal).catch((e) => {
29
+ if (e instanceof TimeoutError) {
30
+ throw new BlockError(blockInput.getBlock(), {code: BlockErrorCode.DATA_UNAVAILABLE});
31
+ }
32
+ throw e;
33
+ })
34
+ );
26
35
  }
27
36
  }
28
37
  await Promise.all(promises);
@@ -1,7 +1,9 @@
1
1
  import {ChainForkConfig} from "@lodestar/config";
2
2
  import {DataAvailabilityStatus} from "@lodestar/state-transition";
3
3
  import {gloas} from "@lodestar/types";
4
+ import {TimeoutError} from "@lodestar/utils";
4
5
  import {PayloadEnvelopeInput} from "../seenCache/seenPayloadEnvelopeInput.js";
6
+ import {PayloadError, PayloadErrorCode} from "./importExecutionPayload.js";
5
7
 
6
8
  /**
7
9
  * Verifies that all payload envelope inputs have their data columns available.
@@ -23,7 +25,14 @@ export async function verifyPayloadsDataAvailability(
23
25
  // Sync and reconstruction keep pulling the data columns from the network while we wait. The wait is
24
26
  // capped at one slot because the payload queue is serial: a longer wait lets consecutive unavailable
25
27
  // payloads push every later payload import further behind with each slot.
26
- promises.push(payloadInput.waitForAllData(config.getSlotDurationMs(payloadInput.forkName), signal));
28
+ promises.push(
29
+ payloadInput.waitForAllData(config.getSlotDurationMs(payloadInput.forkName), signal).catch((e) => {
30
+ if (e instanceof TimeoutError) {
31
+ throw new PayloadError(payloadInput, {code: PayloadErrorCode.DATA_UNAVAILABLE});
32
+ }
33
+ throw e;
34
+ })
35
+ );
27
36
  }
28
37
  }
29
38
  await Promise.all(promises);
@@ -342,7 +342,7 @@ export class BlsMultiThreadWorkerPool implements IBlsVerifier {
342
342
  } else {
343
343
  this.jobs.push(job);
344
344
  }
345
- callInNextEventLoop(this.runJob);
345
+ callInNextEventLoop(() => void this.runJob());
346
346
  }
347
347
  }
348
348
 
@@ -377,7 +377,7 @@ export class BlsMultiThreadWorkerPool implements IBlsVerifier {
377
377
  let completedJobsCount = 0;
378
378
 
379
379
  if (this.jobs.length > 0) {
380
- callInNextEventLoop(this.runJob);
380
+ callInNextEventLoop(() => void this.runJob());
381
381
  }
382
382
 
383
383
  try {
@@ -423,7 +423,7 @@ export class BlsMultiThreadWorkerPool implements IBlsVerifier {
423
423
  if (workReqs.length === 0) {
424
424
  worker.status = {code: WorkerStatusCode.idle, workerApi};
425
425
  this.workersBusy--;
426
- callInNextEventLoop(this.runJob);
426
+ callInNextEventLoop(() => void this.runJob());
427
427
  return;
428
428
  }
429
429
 
@@ -499,7 +499,7 @@ export class BlsMultiThreadWorkerPool implements IBlsVerifier {
499
499
  this.workersBusy--;
500
500
 
501
501
  // Potentially run a new job
502
- callInNextEventLoop(this.runJob);
502
+ callInNextEventLoop(() => void this.runJob());
503
503
  };
504
504
 
505
505
  /**
@@ -542,7 +542,7 @@ export class BlsMultiThreadWorkerPool implements IBlsVerifier {
542
542
  this.jobs.unshift(job);
543
543
  }
544
544
  this.bufferedJobs = null;
545
- callInNextEventLoop(this.runJob);
545
+ callInNextEventLoop(() => void this.runJob());
546
546
  }
547
547
  };
548
548
 
@@ -1,4 +1,4 @@
1
- import {type BlsSignatureSet} from "@chainsafe/lodestar-z/bls-verifier";
1
+ import {type BlsSignatureSet} from "@lodestar/native/bls-verifier";
2
2
  import {SameMessageSignatureSet, VerifySignatureOpts} from "../interface.js";
3
3
 
4
4
  export type WorkerData = {
@@ -1,10 +1,6 @@
1
1
  import worker from "node:worker_threads";
2
- import {
3
- type BlsSignatureSet,
4
- verifySignatureSets,
5
- verifySignatureSetsSameMessage,
6
- } from "@chainsafe/lodestar-z/bls-verifier";
7
2
  import {expose} from "@chainsafe/threads/worker";
3
+ import {type BlsSignatureSet, verifySignatureSets, verifySignatureSetsSameMessage} from "@lodestar/native/bls-verifier";
8
4
  import {
9
5
  BlsWorkReq,
10
6
  BlsWorkResult,
@@ -1,4 +1,4 @@
1
- import {verifySignatureSetsSameMessage} from "@chainsafe/lodestar-z/bls-verifier";
1
+ import {verifySignatureSetsSameMessage} from "@lodestar/native/bls-verifier";
2
2
  import {ISignatureSet} from "@lodestar/state-transition";
3
3
  import {Metrics} from "../../metrics/index.js";
4
4
  import {IBlsVerifier, SameMessageSignatureSet} from "./interface.js";
@@ -2,7 +2,7 @@ import {
2
2
  BLS_VERIFIER_MAX_BATCH_SIZE,
3
3
  BLS_VERIFIER_MAX_SAME_MESSAGE_BATCH_SIZE,
4
4
  verifySignatureSets,
5
- } from "@chainsafe/lodestar-z/bls-verifier";
5
+ } from "@lodestar/native/bls-verifier";
6
6
  import {ISignatureSet, SignatureSetType, toBlsSignatureSet} from "@lodestar/state-transition";
7
7
  import {SameMessageSignatureSet} from "./interface.js";
8
8
 
@@ -1,6 +1,5 @@
1
1
  import path from "node:path";
2
2
  import {PrivateKey} from "@libp2p/interface";
3
- import {type PubkeyCache} from "@chainsafe/lodestar-z/pubkeys";
4
3
  import {Type} from "@chainsafe/ssz";
5
4
  import {routes} from "@lodestar/api";
6
5
  import {BeaconConfig} from "@lodestar/config";
@@ -14,6 +13,7 @@ import {
14
13
  UpdateHeadOpt,
15
14
  } from "@lodestar/fork-choice";
16
15
  import {LoggerNode} from "@lodestar/logger/node";
16
+ import {type PubkeyCache} from "@lodestar/native/pubkeys";
17
17
  import {
18
18
  EFFECTIVE_BALANCE_INCREMENT,
19
19
  type ForkPostFulu,
@@ -72,7 +72,7 @@ export enum BlockErrorCode {
72
72
  * whoever served the block MAY be downscored. Mirrors PayloadErrorCode.EXECUTION_ENGINE_INVALID.
73
73
  */
74
74
  EXECUTION_ENGINE_INVALID = "BLOCK_ERROR_EXECUTION_INVALID",
75
- /** The blobs are unavailable */
75
+ /** The blob or column data did not arrive within the availability wait */
76
76
  DATA_UNAVAILABLE = "BLOCK_ERROR_DATA_UNAVAILABLE",
77
77
  /** Block contains too many kzg commitments */
78
78
  TOO_MANY_KZG_COMMITMENTS = "BLOCK_ERROR_TOO_MANY_KZG_COMMITMENTS",
@@ -1,7 +1,7 @@
1
- import {type PubkeyCache} from "@chainsafe/lodestar-z/pubkeys";
2
1
  import {Type} from "@chainsafe/ssz";
3
2
  import {BeaconConfig} from "@lodestar/config";
4
3
  import {CheckpointWithHex, IForkChoice, ProtoBlock} from "@lodestar/fork-choice";
4
+ import {type PubkeyCache} from "@lodestar/native/pubkeys";
5
5
  import {EpochShuffling, IBeaconStateView} from "@lodestar/state-transition";
6
6
  import {
7
7
  BeaconBlock,
@@ -77,8 +77,7 @@ import {PayloadEnvelopeInput, SeenPayloadEnvelopeInput} from "./seenCache/seenPa
77
77
  import {ShufflingCache} from "./shufflingCache.js";
78
78
  import {ValidatorMonitor} from "./validatorMonitor.js";
79
79
 
80
- export {BlockType, type AssembledBlockType};
81
- export {type ProposerPreparationData};
80
+ export {type AssembledBlockType, BlockType, type ProposerPreparationData};
82
81
  export type BlockHash = RootHex;
83
82
 
84
83
  export type StateGetOpts = {
@@ -1,7 +1,7 @@
1
- import {Signature, aggregateSignatures} from "@chainsafe/lodestar-z/blst";
2
1
  import {BitArray} from "@chainsafe/ssz";
3
2
  import {BeaconConfig} from "@lodestar/config";
4
3
  import {IForkChoice} from "@lodestar/fork-choice";
4
+ import {Signature, aggregateSignatures} from "@lodestar/native/blst";
5
5
  import {
6
6
  ForkName,
7
7
  ForkSeq,
@@ -20,6 +20,7 @@ import {
20
20
  } from "@lodestar/params";
21
21
  import {
22
22
  EffectiveBalanceIncrements,
23
+ G2_POINT_AT_INFINITY,
23
24
  IBeaconStateView,
24
25
  RootCache,
25
26
  computeEpochAtSlot,
@@ -30,7 +31,7 @@ import {
30
31
  isStatePostGloas,
31
32
  } from "@lodestar/state-transition";
32
33
  import {Attestation, Epoch, RootHex, Slot, electra, isElectraAttestation, phase0, ssz} from "@lodestar/types";
33
- import {Logger, MapDef, assert, toRootHex} from "@lodestar/utils";
34
+ import {Logger, MapDef, assert, byteArrayEquals, toRootHex} from "@lodestar/utils";
34
35
  import {Metrics} from "../../metrics/metrics.js";
35
36
  import {IntersectResult, intersectUint8Arrays} from "../../util/bitArray.js";
36
37
  import {getShufflingDependentRoot} from "../../util/dependentRoot.js";
@@ -409,20 +410,34 @@ export class AggregatedAttestationPool {
409
410
 
410
411
  const sortedConsolidationsByScore = Array.from(consolidations.entries())
411
412
  .sort((a, b) => b[1] - a[1])
412
- .map(([consolidation, _]) => consolidation)
413
- .slice(0, MAX_ATTESTATIONS_ELECTRA);
413
+ .map(([consolidation, _]) => consolidation);
414
414
 
415
415
  // on chain aggregation is expensive, only do it after all
416
416
  const packedAttestationsMetrics = this.metrics?.opPool.aggregatedAttestationPool.packedAttestations;
417
- const packedAttestations: electra.Attestation[] = new Array(sortedConsolidationsByScore.length);
418
- for (const [i, consolidation] of sortedConsolidationsByScore.entries()) {
419
- packedAttestations[i] = aggregateConsolidation(consolidation);
417
+ const packedAttestations: electra.Attestation[] = [];
418
+ for (const consolidation of sortedConsolidationsByScore) {
419
+ if (packedAttestations.length >= MAX_ATTESTATIONS_ELECTRA) {
420
+ break;
421
+ }
422
+
423
+ const attestation = aggregateConsolidation(consolidation);
424
+ // The point at infinity is not a valid aggregate signature, exclude it from the block
425
+ if (byteArrayEquals(attestation.signature, G2_POINT_AT_INFINITY)) {
426
+ this.logger?.debug("Excluding aggregate with infinity signature", {
427
+ slot: stateSlot,
428
+ attestationSlot: attestation.data.slot,
429
+ committees: consolidation.byCommittee.size,
430
+ });
431
+ continue;
432
+ }
433
+
434
+ const i = packedAttestations.push(attestation) - 1;
420
435
 
421
436
  // record metrics of packed attestations
422
437
  packedAttestationsMetrics?.committeeCount.set({index: i}, consolidation.byCommittee.size);
423
438
  packedAttestationsMetrics?.totalAttesters.set({index: i}, consolidation.totalAttesters);
424
439
  packedAttestationsMetrics?.nonParticipation.set({index: i}, consolidation.notSeenAttesters);
425
- packedAttestationsMetrics?.inclusionDistance.set({index: i}, stateSlot - packedAttestations[i].data.slot);
440
+ packedAttestationsMetrics?.inclusionDistance.set({index: i}, stateSlot - attestation.data.slot);
426
441
  packedAttestationsMetrics?.newSeenAttesters.set({index: i}, consolidation.newSeenAttesters);
427
442
  packedAttestationsMetrics?.totalEffectiveBalance.set({index: i}, consolidation.totalNewSeenEffectiveBalance);
428
443
  }
@@ -462,7 +477,8 @@ export class AggregatedAttestationPool {
462
477
  attestations.push(...attestationGroup.getAttestations());
463
478
  }
464
479
  }
465
- return attestations;
480
+ // The point at infinity is not a valid aggregate signature, do not serve such an aggregate
481
+ return attestations.filter((attestation) => !byteArrayEquals(attestation.signature, G2_POINT_AT_INFINITY));
466
482
  }
467
483
 
468
484
  private onScrapeMetrics(metrics: Metrics): void {
@@ -1,9 +1,10 @@
1
- import {Signature, aggregateSignatures} from "@chainsafe/lodestar-z/blst";
2
1
  import {BitArray} from "@chainsafe/ssz";
3
2
  import {ChainForkConfig} from "@lodestar/config";
3
+ import {Signature, aggregateSignatures} from "@lodestar/native/blst";
4
4
  import {MAX_COMMITTEES_PER_SLOT, isForkPostElectra} from "@lodestar/params";
5
+ import {G2_POINT_AT_INFINITY} from "@lodestar/state-transition";
5
6
  import {Attestation, RootHex, SingleAttestation, Slot, isElectraSingleAttestation} from "@lodestar/types";
6
- import {MapDef, assert} from "@lodestar/utils";
7
+ import {MapDef, assert, byteArrayEquals} from "@lodestar/utils";
7
8
  import {Metrics} from "../../metrics/metrics.js";
8
9
  import {IClock} from "../../util/clock.js";
9
10
  import {InsertOutcome, OpPoolError, OpPoolErrorCode} from "./types.js";
@@ -180,7 +181,13 @@ export class AttestationPool {
180
181
  assert.true(!isElectraAggregate(aggregate), "Aggregate should be type AggregateFastPhase0");
181
182
  }
182
183
 
183
- return fastToAttestation(aggregate);
184
+ const attestation = fastToAttestation(aggregate);
185
+ // The point at infinity is not a valid aggregate signature, do not serve such an aggregate
186
+ if (byteArrayEquals(attestation.signature, G2_POINT_AT_INFINITY)) {
187
+ return null;
188
+ }
189
+
190
+ return attestation;
184
191
  }
185
192
 
186
193
  /**
@@ -209,7 +216,12 @@ export class AttestationPool {
209
216
  if (aggregateByRoot) {
210
217
  for (const aggFastByIndex of aggregateByRoot.values()) {
211
218
  for (const aggFast of aggFastByIndex.values()) {
212
- attestations.push(fastToAttestation(aggFast));
219
+ const attestation = fastToAttestation(aggFast);
220
+ // The point at infinity is not a valid aggregate signature, do not serve such an aggregate
221
+ if (byteArrayEquals(attestation.signature, G2_POINT_AT_INFINITY)) {
222
+ continue;
223
+ }
224
+ attestations.push(attestation);
213
225
  }
214
226
  }
215
227
  }
@@ -1,9 +1,10 @@
1
- import {Signature, aggregateSignatures} from "@chainsafe/lodestar-z/blst";
2
1
  import {BitArray} from "@chainsafe/ssz";
3
2
  import {ChainForkConfig} from "@lodestar/config";
3
+ import {Signature, aggregateSignatures} from "@lodestar/native/blst";
4
4
  import {MAX_COMMITTEES_PER_SLOT, MAX_PAYLOAD_ATTESTATIONS, PTC_SIZE} from "@lodestar/params";
5
+ import {G2_POINT_AT_INFINITY} from "@lodestar/state-transition";
5
6
  import {RootHex, Slot, gloas} from "@lodestar/types";
6
- import {MapDef, toRootHex} from "@lodestar/utils";
7
+ import {MapDef, byteArrayEquals, toRootHex} from "@lodestar/utils";
7
8
  import {Metrics} from "../../metrics/metrics.js";
8
9
  import {IClock} from "../../util/clock.js";
9
10
  import {InsertOutcome, OpPoolError, OpPoolErrorCode} from "./types.js";
@@ -112,11 +113,19 @@ export class PayloadAttestationPool {
112
113
  return [];
113
114
  }
114
115
 
115
- return Array.from(aggregateByDataRoot.values())
116
- .slice()
116
+ const payloadAttestations: gloas.PayloadAttestation[] = [];
117
+ for (const aggregate of aggregateByDataRoot.values()) {
118
+ const payloadAttestation = fastToPayloadAttestation(aggregate);
119
+ // The point at infinity is not a valid aggregate signature, exclude it from the block
120
+ if (byteArrayEquals(payloadAttestation.signature, G2_POINT_AT_INFINITY)) {
121
+ continue;
122
+ }
123
+ payloadAttestations.push(payloadAttestation);
124
+ }
125
+
126
+ return payloadAttestations
117
127
  .sort((a, b) => b.aggregationBits.getTrueBitIndexes().length - a.aggregationBits.getTrueBitIndexes().length)
118
- .slice(0, MAX_PAYLOAD_ATTESTATIONS)
119
- .map(fastToPayloadAttestation);
128
+ .slice(0, MAX_PAYLOAD_ATTESTATIONS);
120
129
  }
121
130
 
122
131
  getAll(slot?: Slot): gloas.PayloadAttestation[] {
@@ -139,9 +148,11 @@ export class PayloadAttestationPool {
139
148
  }
140
149
  }
141
150
 
151
+ // The point at infinity is not a valid aggregate signature, do not serve such an aggregate
142
152
  return aggregates
143
153
  .sort((a, b) => b.aggregationBits.getTrueBitIndexes().length - a.aggregationBits.getTrueBitIndexes().length)
144
- .map(fastToPayloadAttestation);
154
+ .map(fastToPayloadAttestation)
155
+ .filter((attestation) => !byteArrayEquals(attestation.signature, G2_POINT_AT_INFINITY));
145
156
  }
146
157
 
147
158
  prune(clockSlot: Slot): void {
@@ -1,9 +1,10 @@
1
- import {Signature, aggregateSignatures} from "@chainsafe/lodestar-z/blst";
2
1
  import {BitArray} from "@chainsafe/ssz";
3
2
  import {ChainForkConfig} from "@lodestar/config";
3
+ import {Signature, aggregateSignatures} from "@lodestar/native/blst";
4
4
  import {SYNC_COMMITTEE_SIZE, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params";
5
+ import {G2_POINT_AT_INFINITY} from "@lodestar/state-transition";
5
6
  import {Root, Slot, SubcommitteeIndex, SubnetID, altair} from "@lodestar/types";
6
- import {MapDef, toRootHex} from "@lodestar/utils";
7
+ import {MapDef, byteArrayEquals, toRootHex} from "@lodestar/utils";
7
8
  import {IClock} from "../../util/clock.js";
8
9
  import {InsertOutcome, OpPoolError, OpPoolErrorCode} from "./types.js";
9
10
  import {pruneBySlot, signatureFromBytesNoCheck} from "./utils.js";
@@ -110,10 +111,16 @@ export class SyncCommitteeMessagePool {
110
111
  return null;
111
112
  }
112
113
 
114
+ const signature = contribution.signature.toBytes();
115
+ // The point at infinity is not a valid contribution signature, do not serve such a contribution
116
+ if (byteArrayEquals(signature, G2_POINT_AT_INFINITY)) {
117
+ return null;
118
+ }
119
+
113
120
  return {
114
121
  ...contribution,
115
122
  aggregationBits: contribution.aggregationBits,
116
- signature: contribution.signature.toBytes(),
123
+ signature,
117
124
  };
118
125
  }
119
126
 
@@ -1,10 +1,10 @@
1
- import {Signature, aggregateSignatures} from "@chainsafe/lodestar-z/blst";
2
1
  import {BitArray} from "@chainsafe/ssz";
3
2
  import {ChainForkConfig} from "@lodestar/config";
3
+ import {Signature, aggregateSignatures} from "@lodestar/native/blst";
4
4
  import {SYNC_COMMITTEE_SIZE, SYNC_COMMITTEE_SUBNET_SIZE} from "@lodestar/params";
5
5
  import {G2_POINT_AT_INFINITY} from "@lodestar/state-transition";
6
6
  import {Root, Slot, SubnetID, altair, ssz} from "@lodestar/types";
7
- import {Logger, MapDef, toRootHex} from "@lodestar/utils";
7
+ import {Logger, MapDef, byteArrayEquals, toRootHex} from "@lodestar/utils";
8
8
  import {Metrics} from "../../metrics/metrics.js";
9
9
  import {IClock} from "../../util/clock.js";
10
10
  import {InsertOutcome, OpPoolError, OpPoolErrorCode} from "./types.js";
@@ -234,8 +234,18 @@ export function aggregate(
234
234
  }
235
235
 
236
236
  metrics?.opPool.syncContributionAndProofPool.getAggregateParticipants.set(participationCount);
237
+
238
+ const syncCommitteeSignature = aggregateSignatures(signatures).toBytes();
239
+ // The point at infinity is only a valid sync aggregate signature with empty participation bits
240
+ if (byteArrayEquals(syncCommitteeSignature, G2_POINT_AT_INFINITY)) {
241
+ return {
242
+ syncCommitteeBits: BitArray.fromBitLen(SYNC_COMMITTEE_SIZE),
243
+ syncCommitteeSignature,
244
+ };
245
+ }
246
+
237
247
  return {
238
248
  syncCommitteeBits,
239
- syncCommitteeSignature: aggregateSignatures(signatures).toBytes(),
249
+ syncCommitteeSignature,
240
250
  };
241
251
  }