@lodestar/beacon-node 1.43.0-dev.1540a78cd0 → 1.43.0-dev.1629c3a59e

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 (147) hide show
  1. package/lib/api/impl/beacon/blocks/index.js +3 -3
  2. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  3. package/lib/api/impl/beacon/pool/index.d.ts.map +1 -1
  4. package/lib/api/impl/beacon/pool/index.js +45 -2
  5. package/lib/api/impl/beacon/pool/index.js.map +1 -1
  6. package/lib/api/impl/validator/index.d.ts.map +1 -1
  7. package/lib/api/impl/validator/index.js +66 -1
  8. package/lib/api/impl/validator/index.js.map +1 -1
  9. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  10. package/lib/chain/blocks/importBlock.js +1 -3
  11. package/lib/chain/blocks/importBlock.js.map +1 -1
  12. package/lib/chain/blocks/importExecutionPayload.d.ts +5 -3
  13. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  14. package/lib/chain/blocks/importExecutionPayload.js +23 -10
  15. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  16. package/lib/chain/blocks/index.d.ts.map +1 -1
  17. package/lib/chain/blocks/index.js +7 -5
  18. package/lib/chain/blocks/index.js.map +1 -1
  19. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +1 -0
  20. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
  21. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +4 -1
  22. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
  23. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +1 -0
  24. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
  25. package/lib/chain/blocks/verifyBlock.d.ts +2 -1
  26. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  27. package/lib/chain/blocks/verifyBlock.js +26 -7
  28. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  29. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +2 -2
  30. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -1
  31. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts.map +1 -1
  32. package/lib/chain/blocks/verifyPayloadsDataAvailability.js +8 -3
  33. package/lib/chain/blocks/verifyPayloadsDataAvailability.js.map +1 -1
  34. package/lib/chain/chain.d.ts +2 -1
  35. package/lib/chain/chain.d.ts.map +1 -1
  36. package/lib/chain/chain.js +5 -1
  37. package/lib/chain/chain.js.map +1 -1
  38. package/lib/chain/emitter.d.ts +0 -11
  39. package/lib/chain/emitter.d.ts.map +1 -1
  40. package/lib/chain/emitter.js +0 -4
  41. package/lib/chain/emitter.js.map +1 -1
  42. package/lib/chain/errors/index.d.ts +1 -0
  43. package/lib/chain/errors/index.d.ts.map +1 -1
  44. package/lib/chain/errors/index.js +1 -0
  45. package/lib/chain/errors/index.js.map +1 -1
  46. package/lib/chain/errors/proposerPreferences.d.ts +33 -0
  47. package/lib/chain/errors/proposerPreferences.d.ts.map +1 -0
  48. package/lib/chain/errors/proposerPreferences.js +13 -0
  49. package/lib/chain/errors/proposerPreferences.js.map +1 -0
  50. package/lib/chain/interface.d.ts +2 -1
  51. package/lib/chain/interface.d.ts.map +1 -1
  52. package/lib/chain/interface.js.map +1 -1
  53. package/lib/chain/opPools/payloadAttestationPool.d.ts +3 -2
  54. package/lib/chain/opPools/payloadAttestationPool.d.ts.map +1 -1
  55. package/lib/chain/opPools/payloadAttestationPool.js +26 -4
  56. package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
  57. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  58. package/lib/chain/prepareNextSlot.js +15 -17
  59. package/lib/chain/prepareNextSlot.js.map +1 -1
  60. package/lib/chain/produceBlock/produceBlockBody.d.ts +11 -3
  61. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  62. package/lib/chain/produceBlock/produceBlockBody.js +41 -18
  63. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  64. package/lib/chain/regen/interface.d.ts +1 -0
  65. package/lib/chain/regen/interface.d.ts.map +1 -1
  66. package/lib/chain/regen/interface.js +1 -0
  67. package/lib/chain/regen/interface.js.map +1 -1
  68. package/lib/chain/seenCache/index.d.ts +1 -0
  69. package/lib/chain/seenCache/index.d.ts.map +1 -1
  70. package/lib/chain/seenCache/index.js +1 -0
  71. package/lib/chain/seenCache/index.js.map +1 -1
  72. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +8 -2
  73. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  74. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +8 -2
  75. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  76. package/lib/chain/seenCache/seenProposerPreferences.d.ts +15 -0
  77. package/lib/chain/seenCache/seenProposerPreferences.d.ts.map +1 -0
  78. package/lib/chain/seenCache/seenProposerPreferences.js +25 -0
  79. package/lib/chain/seenCache/seenProposerPreferences.js.map +1 -0
  80. package/lib/chain/validation/proposerPreferences.d.ts +8 -0
  81. package/lib/chain/validation/proposerPreferences.d.ts.map +1 -0
  82. package/lib/chain/validation/proposerPreferences.js +69 -0
  83. package/lib/chain/validation/proposerPreferences.js.map +1 -0
  84. package/lib/network/gossip/interface.d.ts +7 -1
  85. package/lib/network/gossip/interface.d.ts.map +1 -1
  86. package/lib/network/gossip/interface.js +1 -0
  87. package/lib/network/gossip/interface.js.map +1 -1
  88. package/lib/network/gossip/scoringParameters.d.ts.map +1 -1
  89. package/lib/network/gossip/scoringParameters.js +12 -1
  90. package/lib/network/gossip/scoringParameters.js.map +1 -1
  91. package/lib/network/gossip/topic.d.ts +27 -766
  92. package/lib/network/gossip/topic.d.ts.map +1 -1
  93. package/lib/network/gossip/topic.js +6 -0
  94. package/lib/network/gossip/topic.js.map +1 -1
  95. package/lib/network/interface.d.ts +1 -0
  96. package/lib/network/interface.d.ts.map +1 -1
  97. package/lib/network/network.d.ts +1 -0
  98. package/lib/network/network.d.ts.map +1 -1
  99. package/lib/network/network.js +5 -0
  100. package/lib/network/network.js.map +1 -1
  101. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  102. package/lib/network/processor/gossipHandlers.js +12 -15
  103. package/lib/network/processor/gossipHandlers.js.map +1 -1
  104. package/lib/network/processor/gossipQueues/index.d.ts.map +1 -1
  105. package/lib/network/processor/gossipQueues/index.js +5 -0
  106. package/lib/network/processor/gossipQueues/index.js.map +1 -1
  107. package/lib/network/processor/index.d.ts.map +1 -1
  108. package/lib/network/processor/index.js +6 -5
  109. package/lib/network/processor/index.js.map +1 -1
  110. package/lib/sync/unknownBlock.d.ts +0 -2
  111. package/lib/sync/unknownBlock.d.ts.map +1 -1
  112. package/lib/sync/unknownBlock.js +0 -47
  113. package/lib/sync/unknownBlock.js.map +1 -1
  114. package/package.json +15 -15
  115. package/src/api/impl/beacon/blocks/index.ts +3 -3
  116. package/src/api/impl/beacon/pool/index.ts +83 -1
  117. package/src/api/impl/validator/index.ts +80 -0
  118. package/src/chain/blocks/importBlock.ts +0 -1
  119. package/src/chain/blocks/importExecutionPayload.ts +31 -10
  120. package/src/chain/blocks/index.ts +14 -6
  121. package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +5 -1
  122. package/src/chain/blocks/payloadEnvelopeInput/types.ts +1 -0
  123. package/src/chain/blocks/verifyBlock.ts +39 -9
  124. package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +2 -2
  125. package/src/chain/blocks/verifyPayloadsDataAvailability.ts +7 -4
  126. package/src/chain/chain.ts +5 -0
  127. package/src/chain/emitter.ts +0 -11
  128. package/src/chain/errors/index.ts +1 -0
  129. package/src/chain/errors/proposerPreferences.ts +39 -0
  130. package/src/chain/interface.ts +2 -0
  131. package/src/chain/opPools/payloadAttestationPool.ts +29 -8
  132. package/src/chain/prepareNextSlot.ts +20 -28
  133. package/src/chain/produceBlock/produceBlockBody.ts +51 -23
  134. package/src/chain/regen/interface.ts +1 -0
  135. package/src/chain/seenCache/index.ts +1 -0
  136. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +13 -3
  137. package/src/chain/seenCache/seenProposerPreferences.ts +29 -0
  138. package/src/chain/validation/proposerPreferences.ts +91 -0
  139. package/src/network/gossip/interface.ts +6 -0
  140. package/src/network/gossip/scoringParameters.ts +14 -1
  141. package/src/network/gossip/topic.ts +6 -0
  142. package/src/network/interface.ts +1 -0
  143. package/src/network/network.ts +11 -0
  144. package/src/network/processor/gossipHandlers.ts +19 -16
  145. package/src/network/processor/gossipQueues/index.ts +5 -0
  146. package/src/network/processor/index.ts +6 -5
  147. package/src/sync/unknownBlock.ts +0 -50
@@ -52,6 +52,8 @@ import {
52
52
  ExecutionPayloadEnvelopeErrorCode,
53
53
  GossipAction,
54
54
  GossipActionError,
55
+ PayloadAttestationError,
56
+ PayloadAttestationErrorCode,
55
57
  SyncCommitteeError,
56
58
  } from "../../chain/errors/index.js";
57
59
  import {IBeaconChain} from "../../chain/interface.js";
@@ -79,6 +81,7 @@ import {
79
81
  import {validateLightClientFinalityUpdate} from "../../chain/validation/lightClientFinalityUpdate.js";
80
82
  import {validateLightClientOptimisticUpdate} from "../../chain/validation/lightClientOptimisticUpdate.js";
81
83
  import {validateGossipPayloadAttestationMessage} from "../../chain/validation/payloadAttestationMessage.js";
84
+ import {validateGossipProposerPreferences} from "../../chain/validation/proposerPreferences.js";
82
85
  import {OpSource} from "../../chain/validatorMonitor.js";
83
86
  import {Metrics} from "../../metrics/index.js";
84
87
  import {kzgCommitmentToVersionedHash} from "../../util/blobs.js";
@@ -1060,10 +1063,8 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
1060
1063
  const signedEnvelope = sszDeserialize(topic, serializedData);
1061
1064
  const envelope = signedEnvelope.message;
1062
1065
 
1063
- // TODO GLOAS: consider optimistically create PayloadEnvelopeInput here similar to how we do that for beacon_block
1064
- // so that UnknownBlockSync can handle backward sync
1065
- // the problem now is we cannot create a PayloadEnvelopeInput without the beacon block being known, we need at least the proposer index
1066
- // we can achieve that by looking into the EpochCache
1066
+ // unlike BlockInput, we send the envelope into UnknownBlockInput sync
1067
+ // inside the sync it'll reconcile into PayloadEnvelopeInput and share the same cache with gossip
1067
1068
  try {
1068
1069
  await validateGossipExecutionPayloadEnvelope(chain, signedEnvelope);
1069
1070
  } catch (e) {
@@ -1071,14 +1072,6 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
1071
1072
  const {beaconBlockRoot} = signedEnvelope.message;
1072
1073
  const slot = signedEnvelope.message.payload.slotNumber;
1073
1074
  logger.debug("Gossip envelope has error", {slot, root: toRootHex(beaconBlockRoot), code: e.type.code});
1074
- if (e.type.code === ExecutionPayloadEnvelopeErrorCode.BLOCK_ROOT_UNKNOWN) {
1075
- // TODO GLOAS: UnknownBlockSync to handle this
1076
- chain.emitter.emit(ChainEvent.envelopeUnknownBlock, {
1077
- envelope: signedEnvelope,
1078
- peer: peerIdStr,
1079
- source: BlockInputSource.gossip,
1080
- });
1081
- }
1082
1075
 
1083
1076
  if (e.action === GossipAction.REJECT) {
1084
1077
  chain.persistInvalidSszValue(
@@ -1173,6 +1166,14 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
1173
1166
  data: executionPayloadBid,
1174
1167
  });
1175
1168
  },
1169
+ [GossipType.proposer_preferences]: async ({
1170
+ gossipData,
1171
+ topic,
1172
+ }: GossipHandlerParamGeneric<GossipType.proposer_preferences>) => {
1173
+ const {serializedData} = gossipData;
1174
+ const signedProposerPreferences = sszDeserialize(topic, serializedData);
1175
+ await validateGossipProposerPreferences(chain, signedProposerPreferences);
1176
+ },
1176
1177
  };
1177
1178
  }
1178
1179
 
@@ -1295,10 +1296,12 @@ export async function validateGossipFnRetryUnknownRoot<T>(
1295
1296
  try {
1296
1297
  return await fn();
1297
1298
  } catch (e) {
1298
- if (
1299
- e instanceof AttestationError &&
1300
- e.type.code === AttestationErrorCode.UNKNOWN_OR_PREFINALIZED_BEACON_BLOCK_ROOT
1301
- ) {
1299
+ const isUnknownAttestationRoot =
1300
+ e instanceof AttestationError && e.type.code === AttestationErrorCode.UNKNOWN_OR_PREFINALIZED_BEACON_BLOCK_ROOT;
1301
+ const isUnknownPayloadAttestationRoot =
1302
+ e instanceof PayloadAttestationError && e.type.code === PayloadAttestationErrorCode.UNKNOWN_BLOCK_ROOT;
1303
+
1304
+ if (isUnknownAttestationRoot || isUnknownPayloadAttestationRoot) {
1302
1305
  if (unknownBlockRootRetries === 0) {
1303
1306
  // Trigger unknown block root search here
1304
1307
  const rootHex = toRootHex(blockRoot);
@@ -83,6 +83,11 @@ const linearGossipQueueOpts: {
83
83
  type: QueueType.FIFO,
84
84
  dropOpts: {type: DropType.count, count: 1},
85
85
  },
86
+ [GossipType.proposer_preferences]: {
87
+ maxLength: 1024,
88
+ type: QueueType.FIFO,
89
+ dropOpts: {type: DropType.count, count: 1},
90
+ },
86
91
  };
87
92
 
88
93
  const indexedGossipQueueOpts: {
@@ -76,6 +76,7 @@ type WorkOpts = {
76
76
  */
77
77
  const executeGossipWorkOrderObj: Record<GossipType, WorkOpts> = {
78
78
  [GossipType.beacon_block]: {bypassQueue: true},
79
+ [GossipType.execution_payload]: {bypassQueue: true},
79
80
  [GossipType.blob_sidecar]: {bypassQueue: true},
80
81
  [GossipType.data_column_sidecar]: {bypassQueue: true},
81
82
  [GossipType.beacon_aggregate_and_proof]: {},
@@ -88,9 +89,9 @@ const executeGossipWorkOrderObj: Record<GossipType, WorkOpts> = {
88
89
  [GossipType.sync_committee]: {},
89
90
  [GossipType.light_client_finality_update]: {},
90
91
  [GossipType.light_client_optimistic_update]: {},
91
- [GossipType.execution_payload]: {bypassQueue: true},
92
92
  [GossipType.payload_attestation_message]: {},
93
93
  [GossipType.execution_payload_bid]: {},
94
+ [GossipType.proposer_preferences]: {},
94
95
  };
95
96
  const executeGossipWorkOrder = Object.keys(executeGossipWorkOrderObj) as (keyof typeof executeGossipWorkOrderObj)[];
96
97
 
@@ -443,8 +444,7 @@ export class NetworkProcessor {
443
444
  }
444
445
  case GossipType.execution_payload: {
445
446
  // extractBlockSlotRootFn does not return a root for this topic.
446
- // Extract beacon_block_root directly and proactively trigger block sync if missing.
447
- // Do NOT await the block — the handler runs immediately; BlockInputSync handles recovery.
447
+ // Extract beacon_block_root directly
448
448
  const blockRoot = getBeaconBlockRootFromExecutionPayloadEnvelopeSerialized(message.msg.data);
449
449
  if (blockRoot && !this.chain.forkChoice.hasBlockHexUnsafe(blockRoot)) {
450
450
  this.searchUnknownBlock(
@@ -452,9 +452,10 @@ export class NetworkProcessor {
452
452
  BlockInputSource.network_processor,
453
453
  message.propagationSource.toString()
454
454
  );
455
+ // We always want to await the block
456
+ // This allows us to properly forward the payload envelope
457
+ preprocessResult = {action: PreprocessAction.AwaitBlock, root: blockRoot};
455
458
  }
456
- // do not await the block, we want UnknownBlockSync to handle it.
457
- preprocessResult = {action: PreprocessAction.PushToQueue};
458
459
  break;
459
460
  }
460
461
  case GossipType.execution_payload_bid: {
@@ -145,7 +145,6 @@ export class BlockInputSync {
145
145
  this.chain.emitter.on(ChainEvent.incompleteBlockInput, this.onIncompleteBlockInput);
146
146
  this.chain.emitter.on(ChainEvent.incompletePayloadEnvelope, this.onIncompletePayloadEnvelope);
147
147
  this.chain.emitter.on(ChainEvent.blockUnknownParent, this.onUnknownParent);
148
- this.chain.emitter.on(ChainEvent.envelopeUnknownBlock, this.onEnvelopeUnknownBlock);
149
148
  this.chain.emitter.on(routes.events.EventType.block, this.onBlockImported);
150
149
  this.chain.emitter.on(routes.events.EventType.executionPayload, this.onPayloadImported);
151
150
  this.network.events.on(NetworkEvent.peerConnected, this.onPeerConnected);
@@ -161,7 +160,6 @@ export class BlockInputSync {
161
160
  this.chain.emitter.off(ChainEvent.incompleteBlockInput, this.onIncompleteBlockInput);
162
161
  this.chain.emitter.off(ChainEvent.incompletePayloadEnvelope, this.onIncompletePayloadEnvelope);
163
162
  this.chain.emitter.off(ChainEvent.blockUnknownParent, this.onUnknownParent);
164
- this.chain.emitter.off(ChainEvent.envelopeUnknownBlock, this.onEnvelopeUnknownBlock);
165
163
  this.chain.emitter.off(routes.events.EventType.block, this.onBlockImported);
166
164
  this.chain.emitter.off(routes.events.EventType.executionPayload, this.onPayloadImported);
167
165
  this.network.events.off(NetworkEvent.peerConnected, this.onPeerConnected);
@@ -263,19 +261,6 @@ export class BlockInputSync {
263
261
  }
264
262
  };
265
263
 
266
- private onEnvelopeUnknownBlock = (data: ChainEventData[ChainEvent.envelopeUnknownBlock]): void => {
267
- try {
268
- const blockRootHex = toRootHex(data.envelope.message.beaconBlockRoot);
269
- this.addByRootHex(blockRootHex, data.peer);
270
- this.addByPayloadEnvelope(data.envelope, data.peer);
271
- this.triggerUnknownBlockSearch();
272
- this.metrics?.blockInputSync.requests.inc({type: PendingBlockType.UNKNOWN_DATA});
273
- this.metrics?.blockInputSync.source.inc({source: data.source});
274
- } catch (e) {
275
- this.logger.debug("Error handling envelopeUnknownBlock event", {}, e as Error);
276
- }
277
- };
278
-
279
264
  private onBlockImported = (): void => {
280
265
  if (this.pendingPayloads.size > 0) {
281
266
  this.triggerUnknownBlockSearch();
@@ -381,41 +366,6 @@ export class BlockInputSync {
381
366
  return added;
382
367
  };
383
368
 
384
- private addByPayloadEnvelope = (envelope: gloas.SignedExecutionPayloadEnvelope, peerIdStr?: PeerIdStr): void => {
385
- const rootHex = toRootHex(envelope.message.beaconBlockRoot);
386
- const existingPendingPayload = this.pendingPayloads.get(rootHex);
387
- let pendingPayload = this.pendingPayloads.get(rootHex);
388
- if (!pendingPayload || !isPendingPayloadEnvelope(pendingPayload)) {
389
- pendingPayload = {
390
- status: PendingPayloadInputStatus.waitingForBlock,
391
- envelope,
392
- peerIdStrings: new Set(existingPendingPayload?.peerIdStrings ?? []),
393
- timeAddedSec: existingPendingPayload?.timeAddedSec ?? Date.now() / 1000,
394
- };
395
- this.pendingPayloads.set(rootHex, pendingPayload);
396
-
397
- this.logger.verbose("Added payload envelope to BlockInputSync.pendingPayloads", {
398
- slot: envelope.message.payload.slotNumber,
399
- root: rootHex,
400
- });
401
- } else {
402
- this.logger.debug("Overwriting pending payload envelope for root already waiting for block", {
403
- slot: envelope.message.payload.slotNumber,
404
- root: rootHex,
405
- });
406
- pendingPayload.envelope = envelope;
407
- }
408
-
409
- if (peerIdStr) {
410
- pendingPayload.peerIdStrings.add(peerIdStr);
411
- }
412
-
413
- const prunedItemCount = pruneSetToMax(this.pendingPayloads, this.maxPendingBlocks);
414
- if (prunedItemCount > 0) {
415
- this.logger.verbose(`Pruned ${prunedItemCount} items from BlockInputSync.pendingPayloads`);
416
- }
417
- };
418
-
419
369
  private addByPayloadInput = (
420
370
  payloadInput: PayloadEnvelopeInput,
421
371
  peerIdStr?: PeerIdStr,