@lodestar/beacon-node 1.47.0-dev.be9d5b774d → 1.47.0-dev.c1d9395d5e

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 (218) 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/beacon/pool/index.d.ts.map +1 -1
  5. package/lib/api/impl/beacon/pool/index.js +8 -1
  6. package/lib/api/impl/beacon/pool/index.js.map +1 -1
  7. package/lib/api/impl/beacon/state/utils.d.ts +2 -1
  8. package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
  9. package/lib/api/impl/beacon/state/utils.js.map +1 -1
  10. package/lib/api/impl/events/index.d.ts.map +1 -1
  11. package/lib/api/impl/events/index.js +2 -0
  12. package/lib/api/impl/events/index.js.map +1 -1
  13. package/lib/api/rest/base.d.ts.map +1 -1
  14. package/lib/api/rest/base.js +7 -0
  15. package/lib/api/rest/base.js.map +1 -1
  16. package/lib/chain/blocks/importExecutionPayload.d.ts +3 -2
  17. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  18. package/lib/chain/blocks/importExecutionPayload.js +11 -9
  19. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  20. package/lib/chain/blocks/index.d.ts.map +1 -1
  21. package/lib/chain/blocks/index.js +14 -6
  22. package/lib/chain/blocks/index.js.map +1 -1
  23. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +2 -1
  24. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
  25. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +6 -2
  26. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
  27. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +14 -5
  28. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
  29. package/lib/chain/blocks/payloadEnvelopeInput/types.js +5 -0
  30. package/lib/chain/blocks/payloadEnvelopeInput/types.js.map +1 -1
  31. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts.map +1 -1
  32. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js +22 -12
  33. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js.map +1 -1
  34. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts +2 -2
  35. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -1
  36. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +2 -2
  37. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -1
  38. package/lib/chain/bls/index.d.ts +1 -1
  39. package/lib/chain/bls/index.d.ts.map +1 -1
  40. package/lib/chain/bls/interface.d.ts +5 -5
  41. package/lib/chain/bls/interface.d.ts.map +1 -1
  42. package/lib/chain/bls/multithread/index.d.ts +5 -11
  43. package/lib/chain/bls/multithread/index.d.ts.map +1 -1
  44. package/lib/chain/bls/multithread/index.js +116 -101
  45. package/lib/chain/bls/multithread/index.js.map +1 -1
  46. package/lib/chain/bls/multithread/jobItem.d.ts +5 -19
  47. package/lib/chain/bls/multithread/jobItem.d.ts.map +1 -1
  48. package/lib/chain/bls/multithread/jobItem.js +10 -65
  49. package/lib/chain/bls/multithread/jobItem.js.map +1 -1
  50. package/lib/chain/bls/multithread/types.d.ts +29 -8
  51. package/lib/chain/bls/multithread/types.d.ts.map +1 -1
  52. package/lib/chain/bls/multithread/types.js +12 -0
  53. package/lib/chain/bls/multithread/types.js.map +1 -1
  54. package/lib/chain/bls/multithread/utils.d.ts +4 -0
  55. package/lib/chain/bls/multithread/utils.d.ts.map +1 -1
  56. package/lib/chain/bls/multithread/utils.js +10 -0
  57. package/lib/chain/bls/multithread/utils.js.map +1 -1
  58. package/lib/chain/bls/multithread/worker.js +49 -23
  59. package/lib/chain/bls/multithread/worker.js.map +1 -1
  60. package/lib/chain/bls/singleThread.d.ts +4 -10
  61. package/lib/chain/bls/singleThread.d.ts.map +1 -1
  62. package/lib/chain/bls/singleThread.js +8 -45
  63. package/lib/chain/bls/singleThread.js.map +1 -1
  64. package/lib/chain/bls/utils.d.ts +4 -4
  65. package/lib/chain/bls/utils.d.ts.map +1 -1
  66. package/lib/chain/bls/utils.js +18 -19
  67. package/lib/chain/bls/utils.js.map +1 -1
  68. package/lib/chain/chain.d.ts +2 -1
  69. package/lib/chain/chain.d.ts.map +1 -1
  70. package/lib/chain/chain.js +12 -5
  71. package/lib/chain/chain.js.map +1 -1
  72. package/lib/chain/errors/blockError.d.ts +1 -0
  73. package/lib/chain/errors/blockError.d.ts.map +1 -1
  74. package/lib/chain/errors/blockError.js +6 -1
  75. package/lib/chain/errors/blockError.js.map +1 -1
  76. package/lib/chain/interface.d.ts +2 -1
  77. package/lib/chain/interface.d.ts.map +1 -1
  78. package/lib/chain/interface.js.map +1 -1
  79. package/lib/chain/opPools/aggregatedAttestationPool.js +1 -1
  80. package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
  81. package/lib/chain/opPools/attestationPool.d.ts +1 -1
  82. package/lib/chain/opPools/attestationPool.d.ts.map +1 -1
  83. package/lib/chain/opPools/attestationPool.js +1 -1
  84. package/lib/chain/opPools/attestationPool.js.map +1 -1
  85. package/lib/chain/opPools/payloadAttestationPool.js +3 -3
  86. package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
  87. package/lib/chain/opPools/syncCommitteeMessagePool.js +1 -1
  88. package/lib/chain/opPools/syncCommitteeMessagePool.js.map +1 -1
  89. package/lib/chain/opPools/syncContributionAndProofPool.js +1 -1
  90. package/lib/chain/opPools/syncContributionAndProofPool.js.map +1 -1
  91. package/lib/chain/opPools/utils.d.ts +1 -1
  92. package/lib/chain/opPools/utils.d.ts.map +1 -1
  93. package/lib/chain/opPools/utils.js +1 -1
  94. package/lib/chain/opPools/utils.js.map +1 -1
  95. package/lib/chain/seenCache/seenAttesters.d.ts +9 -5
  96. package/lib/chain/seenCache/seenAttesters.d.ts.map +1 -1
  97. package/lib/chain/seenCache/seenAttesters.js +25 -4
  98. package/lib/chain/seenCache/seenAttesters.js.map +1 -1
  99. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +28 -1
  100. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  101. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +121 -13
  102. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  103. package/lib/chain/validation/attestation.d.ts.map +1 -1
  104. package/lib/chain/validation/attestation.js +1 -4
  105. package/lib/chain/validation/attestation.js.map +1 -1
  106. package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
  107. package/lib/chain/validation/attesterSlashing.js +1 -1
  108. package/lib/chain/validation/attesterSlashing.js.map +1 -1
  109. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  110. package/lib/chain/validation/executionPayloadBid.js +1 -2
  111. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  112. package/lib/chain/validation/executionPayloadEnvelope.js +1 -1
  113. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  114. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
  115. package/lib/chain/validation/payloadAttestationMessage.js +5 -14
  116. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
  117. package/lib/chain/validation/proposerPreferences.js +2 -2
  118. package/lib/chain/validation/proposerPreferences.js.map +1 -1
  119. package/lib/chain/validation/proposerSlashing.js +1 -1
  120. package/lib/chain/validation/proposerSlashing.js.map +1 -1
  121. package/lib/metrics/metrics/lodestar.d.ts +52 -22
  122. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  123. package/lib/metrics/metrics/lodestar.js +94 -52
  124. package/lib/metrics/metrics/lodestar.js.map +1 -1
  125. package/lib/network/gossip/topic.d.ts +13 -0
  126. package/lib/network/gossip/topic.d.ts.map +1 -1
  127. package/lib/network/gossip/topic.js +37 -0
  128. package/lib/network/gossip/topic.js.map +1 -1
  129. package/lib/network/network.d.ts.map +1 -1
  130. package/lib/network/network.js +22 -43
  131. package/lib/network/network.js.map +1 -1
  132. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  133. package/lib/network/processor/gossipHandlers.js +5 -1
  134. package/lib/network/processor/gossipHandlers.js.map +1 -1
  135. package/lib/network/util.d.ts +0 -1
  136. package/lib/network/util.d.ts.map +1 -1
  137. package/lib/network/util.js +0 -4
  138. package/lib/network/util.js.map +1 -1
  139. package/lib/node/nodejs.d.ts +2 -1
  140. package/lib/node/nodejs.d.ts.map +1 -1
  141. package/lib/node/nodejs.js.map +1 -1
  142. package/lib/sync/range/batch.d.ts +23 -5
  143. package/lib/sync/range/batch.d.ts.map +1 -1
  144. package/lib/sync/range/batch.js +61 -22
  145. package/lib/sync/range/batch.js.map +1 -1
  146. package/lib/sync/range/chain.d.ts +2 -1
  147. package/lib/sync/range/chain.d.ts.map +1 -1
  148. package/lib/sync/range/chain.js +23 -10
  149. package/lib/sync/range/chain.js.map +1 -1
  150. package/lib/sync/types.d.ts +32 -0
  151. package/lib/sync/types.d.ts.map +1 -1
  152. package/lib/sync/types.js +33 -0
  153. package/lib/sync/types.js.map +1 -1
  154. package/lib/sync/unknownBlock.d.ts.map +1 -1
  155. package/lib/sync/unknownBlock.js +95 -51
  156. package/lib/sync/unknownBlock.js.map +1 -1
  157. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  158. package/lib/sync/utils/downloadByRange.js +16 -11
  159. package/lib/sync/utils/downloadByRange.js.map +1 -1
  160. package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
  161. package/lib/sync/utils/downloadByRoot.js +3 -1
  162. package/lib/sync/utils/downloadByRoot.js.map +1 -1
  163. package/package.json +35 -35
  164. package/src/api/impl/beacon/blocks/index.ts +3 -2
  165. package/src/api/impl/beacon/pool/index.ts +7 -1
  166. package/src/api/impl/beacon/state/utils.ts +2 -1
  167. package/src/api/impl/events/index.ts +3 -1
  168. package/src/api/rest/base.ts +7 -0
  169. package/src/chain/blocks/importExecutionPayload.ts +12 -11
  170. package/src/chain/blocks/index.ts +18 -6
  171. package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +8 -2
  172. package/src/chain/blocks/payloadEnvelopeInput/types.ts +17 -4
  173. package/src/chain/blocks/verifyBlocksStateTransitionOnly.ts +25 -16
  174. package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +1 -9
  175. package/src/chain/bls/index.ts +1 -1
  176. package/src/chain/bls/interface.ts +7 -3
  177. package/src/chain/bls/multithread/index.ts +148 -120
  178. package/src/chain/bls/multithread/jobItem.ts +12 -82
  179. package/src/chain/bls/multithread/types.ts +33 -8
  180. package/src/chain/bls/multithread/utils.ts +11 -0
  181. package/src/chain/bls/multithread/worker.ts +85 -27
  182. package/src/chain/bls/singleThread.ts +11 -55
  183. package/src/chain/bls/utils.ts +23 -24
  184. package/src/chain/chain.ts +13 -6
  185. package/src/chain/errors/blockError.ts +8 -2
  186. package/src/chain/interface.ts +2 -1
  187. package/src/chain/opPools/aggregatedAttestationPool.ts +1 -1
  188. package/src/chain/opPools/attestationPool.ts +1 -1
  189. package/src/chain/opPools/payloadAttestationPool.ts +3 -3
  190. package/src/chain/opPools/syncCommitteeMessagePool.ts +1 -1
  191. package/src/chain/opPools/syncContributionAndProofPool.ts +1 -1
  192. package/src/chain/opPools/utils.ts +1 -1
  193. package/src/chain/seenCache/seenAttesters.ts +31 -5
  194. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +143 -14
  195. package/src/chain/validation/attestation.ts +1 -7
  196. package/src/chain/validation/attesterSlashing.ts +1 -8
  197. package/src/chain/validation/executionPayloadBid.ts +1 -2
  198. package/src/chain/validation/executionPayloadEnvelope.ts +0 -1
  199. package/src/chain/validation/payloadAttestationMessage.ts +6 -17
  200. package/src/chain/validation/proposerPreferences.ts +3 -3
  201. package/src/chain/validation/proposerSlashing.ts +1 -1
  202. package/src/metrics/metrics/lodestar.ts +106 -57
  203. package/src/network/gossip/topic.ts +38 -0
  204. package/src/network/network.ts +27 -55
  205. package/src/network/processor/gossipHandlers.ts +5 -1
  206. package/src/network/util.ts +0 -5
  207. package/src/node/nodejs.ts +2 -1
  208. package/src/sync/range/batch.ts +83 -28
  209. package/src/sync/range/chain.ts +26 -11
  210. package/src/sync/types.ts +33 -0
  211. package/src/sync/unknownBlock.ts +105 -55
  212. package/src/sync/utils/downloadByRange.ts +21 -12
  213. package/src/sync/utils/downloadByRoot.ts +3 -1
  214. package/lib/chain/bls/maybeBatch.d.ts +0 -12
  215. package/lib/chain/bls/maybeBatch.d.ts.map +0 -1
  216. package/lib/chain/bls/maybeBatch.js +0 -35
  217. package/lib/chain/bls/maybeBatch.js.map +0 -1
  218. package/src/chain/bls/maybeBatch.ts +0 -45
@@ -1,7 +1,7 @@
1
1
  import {routes} from "@lodestar/api";
2
2
  import {ChainForkConfig} from "@lodestar/config";
3
3
  import {CheckpointWithHex} from "@lodestar/fork-choice";
4
- import {ForkSeq, isForkPostGloas} from "@lodestar/params";
4
+ import {ForkSeq, SLOTS_PER_EPOCH, isForkPostGloas} from "@lodestar/params";
5
5
  import {RequestError, RequestErrorCode} from "@lodestar/reqresp";
6
6
  import {computeTimeAtSlot} from "@lodestar/state-transition";
7
7
  import {RootHex, Slot, gloas} from "@lodestar/types";
@@ -25,6 +25,7 @@ import {MAX_CONCURRENT_REQUESTS} from "./constants.js";
25
25
  import {SyncOptions} from "./options.js";
26
26
  import {
27
27
  BlockInputSyncCacheItem,
28
+ DroppedItemReason,
28
29
  PayloadSyncCacheItem,
29
30
  PendingBlockInput,
30
31
  PendingBlockInputStatus,
@@ -48,6 +49,10 @@ import {getRateLimitedUntilMs} from "./utils/rateLimit.js";
48
49
  const MAX_ATTEMPTS_PER_BLOCK = 5;
49
50
  const MAX_KNOWN_BAD_BLOCKS = 500;
50
51
  const MAX_PENDING_BLOCKS = 100;
52
+ /**
53
+ * A pending payload without slot can only stay at most 2 epochs.
54
+ */
55
+ const PRUNE_UNRESOLVED_SLOT_EPOCHS = 2;
51
56
 
52
57
  type AdvancePendingBlockResult =
53
58
  | "ready"
@@ -255,7 +260,7 @@ export class BlockInputSync {
255
260
  parentRoot: missingDependency.parentRootHex,
256
261
  parentBlockHash: missingDependency.parentBlockHashHex,
257
262
  });
258
- this.removeAndDownScoreAllDescendants(pendingBlock);
263
+ this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.invalidParentPayload);
259
264
  }
260
265
  return;
261
266
  }
@@ -295,28 +300,37 @@ export class BlockInputSync {
295
300
  // Use the actual finalized block slot, not computeStartSlotAtEpoch(checkpoint.epoch)
296
301
  // because the payload at the finalized block is not finalized
297
302
  const finalizedSlot = this.chain.forkChoice.getFinalizedBlock().slot;
303
+ const nowSec = Date.now() / 1000;
304
+ const maxSecInCache = (PRUNE_UNRESOLVED_SLOT_EPOCHS * SLOTS_PER_EPOCH * this.config.SLOT_DURATION_MS) / 1000;
298
305
 
299
- let deletedPayloads = 0;
306
+ let belowFinalizedPayloads = 0;
307
+ let agedOutPayloads = 0;
300
308
  let unresolvedSlotPayloads = 0;
309
+
301
310
  for (const [rootHex, payload] of this.pendingPayloads) {
302
311
  // Last-effort resolve for a slot-less PendingPayloadRootHex, and store it back for later passes.
303
312
  if (!isPendingPayloadInput(payload) && !isPendingPayloadEnvelope(payload) && payload.slot === undefined) {
304
313
  payload.slot = this.resolvePayloadSlot(rootHex);
314
+ if (payload.slot === undefined) {
315
+ // Still unresolvable: age it out so the MAX_PENDING_BLOCKS cap cannot stay saturated.
316
+ if (nowSec - payload.timeAddedSec > maxSecInCache) {
317
+ this.pendingPayloads.delete(rootHex);
318
+ agedOutPayloads++;
319
+ } else {
320
+ unresolvedSlotPayloads++;
321
+ this.logger.debug("BlockInputSync.pruneFinalized: pending payload with unresolved slot", {
322
+ root: rootHex,
323
+ finalizedSlot,
324
+ });
325
+ }
326
+ continue;
327
+ }
305
328
  }
306
329
 
307
330
  const slot = getPayloadSyncCacheItemSlot(payload);
308
- if (typeof slot !== "number") {
309
- unresolvedSlotPayloads++;
310
- this.logger.debug("BlockInputSync.pruneFinalized: pending payload with unresolved slot", {
311
- root: rootHex,
312
- finalizedSlot,
313
- });
314
- continue;
315
- }
316
-
317
- if (slot < finalizedSlot) {
331
+ if (typeof slot === "number" && slot < finalizedSlot) {
318
332
  this.pendingPayloads.delete(rootHex);
319
- deletedPayloads++;
333
+ belowFinalizedPayloads++;
320
334
  }
321
335
  }
322
336
 
@@ -329,14 +343,24 @@ export class BlockInputSync {
329
343
  }
330
344
  }
331
345
 
332
- if (deletedPayloads > 0 || deletedBlocks > 0) {
333
- this.metrics?.blockInputSync.removedBlocks.inc(deletedPayloads + deletedBlocks);
346
+ if (belowFinalizedPayloads > 0) {
347
+ this.metrics?.blockInputSync.removedPayloads.inc(
348
+ {reason: DroppedItemReason.belowFinalized},
349
+ belowFinalizedPayloads
350
+ );
351
+ }
352
+ if (agedOutPayloads > 0) {
353
+ this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.agedOut}, agedOutPayloads);
354
+ }
355
+ if (deletedBlocks > 0) {
356
+ this.metrics?.blockInputSync.removedBlocks.inc({reason: DroppedItemReason.belowFinalized}, deletedBlocks);
334
357
  }
335
358
 
336
359
  this.logger.debug("BlockInputSync.pruneFinalized dropped pre-finalized pending items", {
337
360
  finalizedSlot,
338
361
  finalizedRoot: checkpoint.rootHex,
339
- deletedPayloads,
362
+ belowFinalizedPayloads,
363
+ agedOutPayloads,
340
364
  deletedBlocks,
341
365
  unresolvedSlotPayloads,
342
366
  });
@@ -369,6 +393,7 @@ export class BlockInputSync {
369
393
  // Limit pending blocks to prevent DOS attacks that cause OOM
370
394
  const prunedItemCount = pruneSetToMax(this.pendingBlocks, this.maxPendingBlocks);
371
395
  if (prunedItemCount > 0) {
396
+ this.metrics?.blockInputSync.removedBlocks.inc({reason: DroppedItemReason.capacity}, prunedItemCount);
372
397
  this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingBlocks`);
373
398
  }
374
399
  return added;
@@ -403,6 +428,7 @@ export class BlockInputSync {
403
428
  // Limit pending blocks to prevent DOS attacks that cause OOM
404
429
  const prunedItemCount = pruneSetToMax(this.pendingBlocks, this.maxPendingBlocks);
405
430
  if (prunedItemCount > 0) {
431
+ this.metrics?.blockInputSync.removedBlocks.inc({reason: DroppedItemReason.capacity}, prunedItemCount);
406
432
  this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingBlocks`);
407
433
  }
408
434
  };
@@ -427,6 +453,14 @@ export class BlockInputSync {
427
453
  root: rootHex,
428
454
  peerIdStr: peerIdStr ?? "unknown peer",
429
455
  });
456
+ } else if (
457
+ // update a previously slot-less entry once a slot becomes available
458
+ slot !== undefined &&
459
+ !isPendingPayloadInput(pendingPayload) &&
460
+ !isPendingPayloadEnvelope(pendingPayload) &&
461
+ pendingPayload.slot === undefined
462
+ ) {
463
+ pendingPayload.slot = slot;
430
464
  }
431
465
 
432
466
  if (peerIdStr) {
@@ -435,6 +469,7 @@ export class BlockInputSync {
435
469
 
436
470
  const prunedItemCount = pruneSetToMax(this.pendingPayloads, this.maxPendingBlocks);
437
471
  if (prunedItemCount > 0) {
472
+ this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.capacity}, prunedItemCount);
438
473
  this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingPayloads`);
439
474
  }
440
475
  return added;
@@ -488,6 +523,7 @@ export class BlockInputSync {
488
523
 
489
524
  const prunedItemCount = pruneSetToMax(this.pendingPayloads, this.maxPendingBlocks);
490
525
  if (prunedItemCount > 0) {
526
+ this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.capacity}, prunedItemCount);
491
527
  this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingPayloads`);
492
528
  }
493
529
  };
@@ -544,15 +580,7 @@ export class BlockInputSync {
544
580
  return {kind: "invalidParentPayload", parentRootHex, parentBlockHashHex};
545
581
  }
546
582
 
547
- const parentPayloadInput = this.chain.seenPayloadEnvelopeInputCache.get(parentRootHex);
548
- if (parentPayloadInput) {
549
- if (parentPayloadInput.getBlockHashHex() === parentBlockHashHex) {
550
- return {kind: "parentPayload", rootHex: parentRootHex, slot: parentBlock.slot};
551
- }
552
-
553
- return {kind: "invalidParentPayload", parentRootHex, parentBlockHashHex};
554
- }
555
-
583
+ // Parent is in fork choice but its payload `parentBlockHashHex` isn't revealed yet
556
584
  return {kind: "parentPayload", rootHex: parentRootHex, slot: parentBlock.slot};
557
585
  }
558
586
 
@@ -590,7 +618,7 @@ export class BlockInputSync {
590
618
  parentRoot: missingDependency.parentRootHex,
591
619
  parentBlockHash: missingDependency.parentBlockHashHex,
592
620
  });
593
- this.removeAndDownScoreAllDescendants(pendingBlock);
621
+ this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.invalidParentPayload);
594
622
  return "removed";
595
623
  }
596
624
  }
@@ -813,7 +841,7 @@ export class BlockInputSync {
813
841
  ...logCtx2,
814
842
  finalizedSlot,
815
843
  });
816
- this.removeAndDownScoreAllDescendants(block);
844
+ this.removeAndDownScoreAllDescendants(block, DroppedItemReason.belowFinalized);
817
845
  } else {
818
846
  this.onUnknownBlockRoot({rootHex: pending.blockInput.parentRootHex, source: BlockInputSource.byRoot});
819
847
  }
@@ -830,7 +858,7 @@ export class BlockInputSync {
830
858
 
831
859
  this.metrics?.blockInputSync.downloadedBlocksError.inc();
832
860
  this.logger.debug("Ignoring unknown block root after many failed downloads", logCtx, res.err);
833
- this.removeAndDownScoreAllDescendants(block);
861
+ this.removeAndDownScoreAllDescendants(block, DroppedItemReason.unavailable);
834
862
  }
835
863
  }
836
864
 
@@ -894,9 +922,9 @@ export class BlockInputSync {
894
922
  this.pendingBlocks.delete(blockRootHex);
895
923
 
896
924
  if (isForkPostGloas(fork)) {
897
- const payloadInput = this.chain.seenPayloadEnvelopeInputCache.get(blockRootHex);
925
+ const payloadInput = await this.chain.seenPayloadEnvelopeInputCache.getOrReload(blockRootHex);
898
926
  if (!payloadInput) {
899
- this.logger.warn("PayloadEnvelopeInput not seeded during unknown sync processReadyBlock()", logCtx);
927
+ this.logger.debug("PayloadEnvelopeInput unavailable during unknown sync processReadyBlock()", logCtx);
900
928
  } else {
901
929
  // Similar to the gossip path: immediately attempt fetch of data columns from the execution engine.
902
930
  // The bid already carries the kzg commitments, so there is no reason to wait for the payload to arrive.
@@ -938,19 +966,19 @@ export class BlockInputSync {
938
966
  case BlockErrorCode.EXECUTION_ENGINE_ERROR:
939
967
  // Removing the block(s) without penalizing the peers, hoping for EL to
940
968
  // recover on a latter download + verify attempt.
941
- this.removeAllDescendants(pendingBlock);
969
+ this.removeAllDescendants(pendingBlock, DroppedItemReason.elError, DroppedItemReason.elError);
942
970
  break;
943
971
 
944
972
  case BlockErrorCode.EXECUTION_ENGINE_INVALID:
945
973
  // the peer served a bad block
946
974
  this.logger.debug("Execution engine rejected block from unknown parent sync", errorData, res.err);
947
- this.removeAndDownScoreAllDescendants(pendingBlock);
975
+ this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.elInvalid);
948
976
  break;
949
977
 
950
978
  default:
951
979
  // Block is not correct with respect to our chain. Log error loudly
952
980
  this.logger.debug("Error processing block from unknown parent sync", errorData, res.err);
953
- this.removeAndDownScoreAllDescendants(pendingBlock);
981
+ this.removeAndDownScoreAllDescendants(pendingBlock, DroppedItemReason.invalidBlock);
954
982
  }
955
983
  }
956
984
 
@@ -969,12 +997,12 @@ export class BlockInputSync {
969
997
  */
970
998
  private async reconcilePayloadEnvelope(pendingPayload: PendingPayloadEnvelope): Promise<void> {
971
999
  const rootHex = getPayloadSyncCacheItemRootHex(pendingPayload);
1000
+
972
1001
  if (this.chain.forkChoice.hasPayloadHexUnsafe(rootHex)) {
973
1002
  this.pendingPayloads.delete(rootHex);
974
1003
  return;
975
1004
  }
976
1005
 
977
- const payloadInput = this.chain.seenPayloadEnvelopeInputCache.get(rootHex);
978
1006
  if (!this.chain.forkChoice.hasBlockHex(rootHex)) {
979
1007
  // Block not in fork choice yet. payloadInput may be seeded from the block body during download, so a
980
1008
  // non-null payloadInput does not imply the block is imported; defer regardless and pull the block first.
@@ -990,8 +1018,9 @@ export class BlockInputSync {
990
1018
  return;
991
1019
  }
992
1020
 
1021
+ const payloadInput = await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
993
1022
  if (!payloadInput) {
994
- this.logger.debug("Missing PayloadEnvelopeInput for known block while reconciling payload envelope", {
1023
+ this.logger.debug("PayloadEnvelopeInput not yet reloadable for imported block, will retry", {
995
1024
  root: rootHex,
996
1025
  });
997
1026
  return;
@@ -1153,17 +1182,27 @@ export class BlockInputSync {
1153
1182
  break;
1154
1183
 
1155
1184
  case PayloadErrorCode.EXECUTION_ENGINE_INVALID:
1185
+ this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
1186
+ this.removePendingPayloadAndDescendants(rootHex, DroppedItemReason.elInvalid);
1187
+ break;
1188
+
1156
1189
  case PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR:
1190
+ this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
1191
+ this.removePendingPayloadAndDescendants(rootHex, DroppedItemReason.invalidEnvelope);
1192
+ break;
1193
+
1157
1194
  case PayloadErrorCode.INVALID_SIGNATURE:
1158
1195
  // TODO GLOAS: Decide how invalid payload inputs should eventually leave memory without
1159
1196
  // reintroducing envelope replacement / recreation flows.
1160
1197
  this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
1161
- this.removePendingPayloadAndDescendants(rootHex);
1198
+ this.removePendingPayloadAndDescendants(rootHex, DroppedItemReason.invalidSignature);
1162
1199
  break;
1163
1200
 
1164
1201
  default:
1165
1202
  this.logger.debug("Error processing payload from unknown sync", logCtx, res.err);
1166
- this.pendingPayloads.delete(rootHex);
1203
+ if (this.pendingPayloads.delete(rootHex)) {
1204
+ this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.unknown}, 1);
1205
+ }
1167
1206
  }
1168
1207
  return;
1169
1208
  }
@@ -1187,7 +1226,7 @@ export class BlockInputSync {
1187
1226
  let slot = getPayloadSyncCacheItemSlot(cacheItem);
1188
1227
  let payloadInput = isPendingPayloadInput(cacheItem)
1189
1228
  ? cacheItem.payloadInput
1190
- : this.chain.seenPayloadEnvelopeInputCache.get(rootHex);
1229
+ : await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
1191
1230
  let envelope = payloadInput?.hasPayloadEnvelope() ? payloadInput.getPayloadEnvelope() : undefined;
1192
1231
 
1193
1232
  let i = 0;
@@ -1220,7 +1259,7 @@ export class BlockInputSync {
1220
1259
  slot = envelope.message.payload.slotNumber;
1221
1260
  }
1222
1261
 
1223
- payloadInput ??= this.chain.seenPayloadEnvelopeInputCache.get(rootHex);
1262
+ payloadInput ??= await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
1224
1263
  if (!this.chain.forkChoice.hasBlockHex(rootHex)) {
1225
1264
  // Block not in fork choice yet. Validating now would throw BLOCK_ROOT_UNKNOWN, so keep the downloaded
1226
1265
  // envelope and wait for the block body; reconcilePayloadEnvelope validates once the block lands.
@@ -1553,9 +1592,9 @@ export class BlockInputSync {
1553
1592
  * Downscore all peers that have referenced any of this bad blocks. May report peers multiple times if they have
1554
1593
  * referenced more than one bad block.
1555
1594
  */
1556
- private removeAndDownScoreAllDescendants(block: BlockInputSyncCacheItem): void {
1595
+ private removeAndDownScoreAllDescendants(block: BlockInputSyncCacheItem, headReason: DroppedItemReason): void {
1557
1596
  // Get all blocks that are a descendant of this one
1558
- const badPendingBlocks = this.removeAllDescendants(block);
1597
+ const badPendingBlocks = this.removeAllDescendants(block, headReason, DroppedItemReason.invalidParent);
1559
1598
  // just console log and do not penalize on pending/bad blocks for debugging
1560
1599
  // console.log("removeAndDownscoreAllDescendants", {block});
1561
1600
 
@@ -1582,18 +1621,22 @@ export class BlockInputSync {
1582
1621
  }
1583
1622
 
1584
1623
  // Once a parent payload is invalid, every descendant waiting on that payload lineage becomes unrecoverable too.
1585
- private removePendingPayloadAndDescendants(rootHex: RootHex): void {
1624
+ private removePendingPayloadAndDescendants(rootHex: RootHex, headReason: DroppedItemReason): void {
1586
1625
  // Keep PayloadEnvelopeInput resident in the seen cache. importBlock() owns that object and
1587
1626
  // later validation/finalization logic decides when it can leave memory.
1588
- this.pendingPayloads.delete(rootHex);
1627
+ if (this.pendingPayloads.delete(rootHex)) {
1628
+ this.metrics?.blockInputSync.removedPayloads.inc({reason: headReason}, 1);
1629
+ }
1589
1630
 
1590
1631
  const badPendingBlocks = getAllDescendantBlocks(rootHex, this.pendingBlocks);
1591
- this.metrics?.blockInputSync.removedBlocks.inc(badPendingBlocks.length);
1592
-
1593
1632
  for (const block of badPendingBlocks) {
1594
1633
  const descendantRootHex = getBlockInputSyncCacheItemRootHex(block);
1595
- this.pendingBlocks.delete(descendantRootHex);
1596
- this.pendingPayloads.delete(descendantRootHex);
1634
+ if (this.pendingBlocks.delete(descendantRootHex)) {
1635
+ this.metrics?.blockInputSync.removedBlocks.inc({reason: DroppedItemReason.invalidParent}, 1);
1636
+ }
1637
+ if (this.pendingPayloads.delete(descendantRootHex)) {
1638
+ this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.invalidParent}, 1);
1639
+ }
1597
1640
  this.chain.seenBlockInputCache.prune(descendantRootHex);
1598
1641
  this.logger.debug("Removing pending descendant after invalid parent payload", {
1599
1642
  slot: getBlockInputSyncCacheItemSlot(block),
@@ -1603,18 +1646,25 @@ export class BlockInputSync {
1603
1646
  }
1604
1647
  }
1605
1648
 
1606
- private removeAllDescendants(block: BlockInputSyncCacheItem): BlockInputSyncCacheItem[] {
1649
+ private removeAllDescendants(
1650
+ block: BlockInputSyncCacheItem,
1651
+ headReason: DroppedItemReason,
1652
+ descendantReason: DroppedItemReason = DroppedItemReason.invalidParent
1653
+ ): BlockInputSyncCacheItem[] {
1607
1654
  const rootHex = getBlockInputSyncCacheItemRootHex(block);
1608
1655
  const slot = getBlockInputSyncCacheItemSlot(block);
1609
- // Get all blocks that are a descendant of this one
1656
+ // Get all blocks that are a descendant of this one (index 0 is the head item itself)
1610
1657
  const badPendingBlocks = [block, ...getAllDescendantBlocks(rootHex, this.pendingBlocks)];
1611
1658
 
1612
- this.metrics?.blockInputSync.removedBlocks.inc(badPendingBlocks.length);
1613
-
1614
- for (const block of badPendingBlocks) {
1659
+ for (const [i, block] of badPendingBlocks.entries()) {
1615
1660
  const rootHex = getBlockInputSyncCacheItemRootHex(block);
1616
- this.pendingBlocks.delete(rootHex);
1617
- this.pendingPayloads.delete(rootHex);
1661
+ const reason = i === 0 ? headReason : descendantReason;
1662
+ if (this.pendingBlocks.delete(rootHex)) {
1663
+ this.metrics?.blockInputSync.removedBlocks.inc({reason}, 1);
1664
+ }
1665
+ if (this.pendingPayloads.delete(rootHex)) {
1666
+ this.metrics?.blockInputSync.removedPayloads.inc({reason}, 1);
1667
+ }
1618
1668
  this.chain.seenBlockInputCache.prune(rootHex);
1619
1669
  // Keep PayloadEnvelopeInput resident in the seen cache for consistency with the
1620
1670
  // importBlock()-owned lifecycle.
@@ -136,6 +136,8 @@ export function cacheByRangeResponses({
136
136
  const source = BlockInputSource.byRange;
137
137
  const updatedBatchBlocks = new Map<Slot, IBlockInput>(batchBlocks.map((block) => [block.slot, block]));
138
138
 
139
+ const payloadEnvelopes = new Map<Slot, PayloadEnvelopeInput>(existingPayloadEnvelopes);
140
+
139
141
  const blocks = responses.validatedBlocks ?? [];
140
142
  for (let i = 0; i < blocks.length; i++) {
141
143
  const {block, blockRoot} = blocks[i];
@@ -172,15 +174,17 @@ export function cacheByRangeResponses({
172
174
  // later step) can throw and abort the batch — otherwise a gloas block would sit in
173
175
  // seenBlockInputCache but unseeded here, and payload-by-root sync would later throw "Missing
174
176
  // PayloadEnvelopeInput for known block" (see issue #9306). add() is idempotent.
175
- if (isForkPostGloas(blockInput.forkName)) {
176
- seenPayloadEnvelopeInputCache.add({
177
+ if (isForkPostGloas(blockInput.forkName) && !payloadEnvelopes.has(blockInput.slot)) {
178
+ const payloadInput = seenPayloadEnvelopeInputCache.add({
177
179
  blockRootHex: blockInput.blockRootHex,
178
180
  block: blockInput.getBlock() as SignedBeaconBlock<ForkPostGloas>,
179
181
  forkName: blockInput.forkName,
180
182
  sampledColumns: custodyConfig.sampledColumns,
181
183
  custodyColumns: custodyConfig.custodyColumns,
182
- timeCreatedSec: seenTimestampSec,
184
+ seenTimestampSec,
185
+ source: PayloadEnvelopeInputSource.byRange,
183
186
  });
187
+ payloadEnvelopes.set(blockInput.slot, payloadInput);
184
188
  }
185
189
  }
186
190
 
@@ -222,17 +226,22 @@ export function cacheByRangeResponses({
222
226
  }
223
227
  }
224
228
 
225
- let payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null =
226
- existingPayloadEnvelopes !== null ? new Map(existingPayloadEnvelopes) : null;
227
229
  if (downloadedPayloadEnvelopes !== null) {
228
- payloadEnvelopes ??= new Map();
229
230
  for (const [slot, envelope] of downloadedPayloadEnvelopes) {
230
- const envelopeBlockRootHex = toRootHex(envelope.message.beaconBlockRoot);
231
- const payloadInput = seenPayloadEnvelopeInputCache.get(envelopeBlockRootHex);
231
+ // the only PayloadEnvelopeInput miss is the dangling parent, which we can get from the seen cache
232
+ let payloadInput = payloadEnvelopes.get(slot);
232
233
  if (payloadInput === undefined) {
233
- // Unreachable given the validatedBlocks loop above seeded an entry for every gloas block in
234
- // the batch. for the parent block, it's populated at BeaconChain init
235
- throw new Error(`Missing PayloadEnvelopeInput for block ${envelopeBlockRootHex}`);
234
+ if (updatedBatchBlocks.has(slot)) {
235
+ throw new Error(
236
+ `Missing PayloadEnvelopeInput for in-batch slot ${slot} root ${toRootHex(envelope.message.beaconBlockRoot)}`
237
+ );
238
+ }
239
+ payloadInput = seenPayloadEnvelopeInputCache.get(toRootHex(envelope.message.beaconBlockRoot));
240
+ }
241
+ if (payloadInput === undefined) {
242
+ throw new Error(
243
+ `Missing PayloadEnvelopeInput for slot ${slot} root ${toRootHex(envelope.message.beaconBlockRoot)}`
244
+ );
236
245
  }
237
246
 
238
247
  if (!payloadInput.hasPayloadEnvelope()) {
@@ -262,7 +271,7 @@ export function cacheByRangeResponses({
262
271
  // Gloas columns are attached to the matching PayloadEnvelopeInput, NOT to IBlockInput.
263
272
  // Gloas DataColumnSidecar has `slot` directly (no signedBlockHeader).
264
273
  const dataSlot = firstColumn.slot;
265
- const payloadInput = payloadEnvelopes?.get(dataSlot);
274
+ const payloadInput = payloadEnvelopes.get(dataSlot);
266
275
  if (!payloadInput) {
267
276
  // Should not happen: we built payloadInputs for all gloas blocks above
268
277
  continue;
@@ -13,6 +13,7 @@ import {BlobIndex, ColumnIndex, SignedBeaconBlock, Slot, deneb, fulu} from "@lod
13
13
  import {LodestarError, byteArrayEquals, fromHex, prettyPrintIndices, toHex, toRootHex} from "@lodestar/utils";
14
14
  import {isBlockInputBlobs, isBlockInputColumns} from "../../chain/blocks/blockInput/blockInput.js";
15
15
  import {BlockInputSource, IBlockInput} from "../../chain/blocks/blockInput/types.js";
16
+ import {PayloadEnvelopeInputSource} from "../../chain/blocks/payloadEnvelopeInput/index.js";
16
17
  import {ChainEventEmitter} from "../../chain/emitter.js";
17
18
  import {IBeaconChain} from "../../chain/interface.js";
18
19
  import {validateBlockBlobSidecars} from "../../chain/validation/blobSidecar.js";
@@ -122,7 +123,8 @@ export async function downloadByRoot({
122
123
  forkName: blockInput.forkName,
123
124
  sampledColumns: chain.custodyConfig.sampledColumns,
124
125
  custodyColumns: chain.custodyConfig.custodyColumns,
125
- timeCreatedSec: Date.now() / 1000,
126
+ seenTimestampSec: Date.now() / 1000,
127
+ source: PayloadEnvelopeInputSource.byRoot,
126
128
  });
127
129
  }
128
130
 
@@ -1,12 +0,0 @@
1
- import { PublicKey } from "@chainsafe/blst";
2
- export type SignatureSetDeserialized = {
3
- publicKey: PublicKey;
4
- message: Uint8Array;
5
- signature: Uint8Array;
6
- };
7
- /**
8
- * Verify signatures sets with batch verification or regular core verify depending on the set count.
9
- * Abstracted in a separate file to be consumed by the threaded pool and the main thread implementation.
10
- */
11
- export declare function verifySignatureSetsMaybeBatch(sets: SignatureSetDeserialized[]): boolean;
12
- //# sourceMappingURL=maybeBatch.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"maybeBatch.d.ts","sourceRoot":"","sources":["../../../src/chain/bls/maybeBatch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAuD,MAAM,iBAAiB,CAAC;AAIhG,MAAM,MAAM,wBAAwB,GAAG;IACrC,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,UAAU,CAAC;IACpB,SAAS,EAAE,UAAU,CAAC;CACvB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,wBAAwB,EAAE,GAAG,OAAO,CA8BvF"}
@@ -1,35 +0,0 @@
1
- import { Signature, verify, verifyMultipleAggregateSignatures } from "@chainsafe/blst";
2
- const MIN_SET_COUNT_TO_BATCH = 2;
3
- /**
4
- * Verify signatures sets with batch verification or regular core verify depending on the set count.
5
- * Abstracted in a separate file to be consumed by the threaded pool and the main thread implementation.
6
- */
7
- export function verifySignatureSetsMaybeBatch(sets) {
8
- try {
9
- if (sets.length >= MIN_SET_COUNT_TO_BATCH) {
10
- return verifyMultipleAggregateSignatures(sets.map((s) => ({
11
- pk: s.publicKey,
12
- msg: s.message,
13
- // true = validate signature
14
- sig: Signature.fromBytes(s.signature, true),
15
- })));
16
- }
17
- // .every on an empty array returns true
18
- if (sets.length === 0) {
19
- throw Error("Empty signature set");
20
- }
21
- // If too few signature sets verify them without batching
22
- return sets.every((set) => {
23
- // true = validate signature
24
- const sig = Signature.fromBytes(set.signature, true);
25
- return verify(set.message, set.publicKey, sig);
26
- });
27
- }
28
- catch (_) {
29
- // A signature could be malformed, in that case fromBytes throws error
30
- // blst-ts `verifyMultipleSignatures` is also a fallible operation if mul_n_aggregate fails
31
- // see https://github.com/ChainSafe/blst-ts/blob/b1ba6333f664b08e5c50b2b0d18c4f079203962b/src/lib.ts#L291
32
- return false;
33
- }
34
- }
35
- //# sourceMappingURL=maybeBatch.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"maybeBatch.js","sourceRoot":"","sources":["../../../src/chain/bls/maybeBatch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,SAAS,EAAE,MAAM,EAAE,iCAAiC,EAAC,MAAM,iBAAiB,CAAC;AAEhG,MAAM,sBAAsB,GAAG,CAAC,CAAC;AAQjC;;;GAGG;AACH,MAAM,UAAU,6BAA6B,CAAC,IAAgC;IAC5E,IAAI,CAAC;QACH,IAAI,IAAI,CAAC,MAAM,IAAI,sBAAsB,EAAE,CAAC;YAC1C,OAAO,iCAAiC,CACtC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACf,EAAE,EAAE,CAAC,CAAC,SAAS;gBACf,GAAG,EAAE,CAAC,CAAC,OAAO;gBACd,4BAA4B;gBAC5B,GAAG,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,EAAE,IAAI,CAAC;aAC5C,CAAC,CAAC,CACJ,CAAC;QACJ,CAAC;QAED,wCAAwC;QACxC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,MAAM,KAAK,CAAC,qBAAqB,CAAC,CAAC;QACrC,CAAC;QAED,yDAAyD;QACzD,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACxB,4BAA4B;YAC5B,MAAM,GAAG,GAAG,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;YACrD,OAAO,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,sEAAsE;QACtE,2FAA2F;QAC3F,yGAAyG;QACzG,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -1,45 +0,0 @@
1
- import {PublicKey, Signature, verify, verifyMultipleAggregateSignatures} from "@chainsafe/blst";
2
-
3
- const MIN_SET_COUNT_TO_BATCH = 2;
4
-
5
- export type SignatureSetDeserialized = {
6
- publicKey: PublicKey;
7
- message: Uint8Array;
8
- signature: Uint8Array;
9
- };
10
-
11
- /**
12
- * Verify signatures sets with batch verification or regular core verify depending on the set count.
13
- * Abstracted in a separate file to be consumed by the threaded pool and the main thread implementation.
14
- */
15
- export function verifySignatureSetsMaybeBatch(sets: SignatureSetDeserialized[]): boolean {
16
- try {
17
- if (sets.length >= MIN_SET_COUNT_TO_BATCH) {
18
- return verifyMultipleAggregateSignatures(
19
- sets.map((s) => ({
20
- pk: s.publicKey,
21
- msg: s.message,
22
- // true = validate signature
23
- sig: Signature.fromBytes(s.signature, true),
24
- }))
25
- );
26
- }
27
-
28
- // .every on an empty array returns true
29
- if (sets.length === 0) {
30
- throw Error("Empty signature set");
31
- }
32
-
33
- // If too few signature sets verify them without batching
34
- return sets.every((set) => {
35
- // true = validate signature
36
- const sig = Signature.fromBytes(set.signature, true);
37
- return verify(set.message, set.publicKey, sig);
38
- });
39
- } catch (_) {
40
- // A signature could be malformed, in that case fromBytes throws error
41
- // blst-ts `verifyMultipleSignatures` is also a fallible operation if mul_n_aggregate fails
42
- // see https://github.com/ChainSafe/blst-ts/blob/b1ba6333f664b08e5c50b2b0d18c4f079203962b/src/lib.ts#L291
43
- return false;
44
- }
45
- }