@lodestar/beacon-node 1.47.0-dev.9572bcc698 → 1.47.0-dev.9ba9a5ce85

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 (148) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +41 -10
  3. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  4. package/lib/api/impl/lodestar/index.js +1 -1
  5. package/lib/api/impl/lodestar/index.js.map +1 -1
  6. package/lib/api/impl/validator/index.d.ts.map +1 -1
  7. package/lib/api/impl/validator/index.js +237 -49
  8. package/lib/api/impl/validator/index.js.map +1 -1
  9. package/lib/api/impl/validator/utils.js +1 -1
  10. package/lib/api/impl/validator/utils.js.map +1 -1
  11. package/lib/chain/archiveStore/archiveStore.js +1 -1
  12. package/lib/chain/archiveStore/archiveStore.js.map +1 -1
  13. package/lib/chain/blocks/index.js +7 -7
  14. package/lib/chain/blocks/index.js.map +1 -1
  15. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  16. package/lib/chain/blocks/verifyBlock.js +5 -2
  17. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  18. package/lib/chain/chain.d.ts +5 -2
  19. package/lib/chain/chain.d.ts.map +1 -1
  20. package/lib/chain/chain.js +6 -2
  21. package/lib/chain/chain.js.map +1 -1
  22. package/lib/chain/errors/executionPayloadBid.d.ts +5 -0
  23. package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
  24. package/lib/chain/errors/executionPayloadBid.js +1 -0
  25. package/lib/chain/errors/executionPayloadBid.js.map +1 -1
  26. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  27. package/lib/chain/forkChoice/index.js +4 -0
  28. package/lib/chain/forkChoice/index.js.map +1 -1
  29. package/lib/chain/interface.d.ts +4 -2
  30. package/lib/chain/interface.d.ts.map +1 -1
  31. package/lib/chain/interface.js.map +1 -1
  32. package/lib/chain/opPools/executionPayloadBidPool.d.ts +7 -2
  33. package/lib/chain/opPools/executionPayloadBidPool.d.ts.map +1 -1
  34. package/lib/chain/opPools/executionPayloadBidPool.js +4 -4
  35. package/lib/chain/opPools/executionPayloadBidPool.js.map +1 -1
  36. package/lib/chain/opPools/index.d.ts +1 -1
  37. package/lib/chain/opPools/index.d.ts.map +1 -1
  38. package/lib/chain/opPools/index.js.map +1 -1
  39. package/lib/chain/prepareNextSlot.d.ts +5 -0
  40. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  41. package/lib/chain/prepareNextSlot.js +47 -6
  42. package/lib/chain/prepareNextSlot.js.map +1 -1
  43. package/lib/chain/produceBlock/computeNewStateRoot.d.ts.map +1 -1
  44. package/lib/chain/produceBlock/computeNewStateRoot.js +3 -25
  45. package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
  46. package/lib/chain/produceBlock/produceBlockBody.js +1 -1
  47. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  48. package/lib/chain/regen/interface.d.ts +3 -2
  49. package/lib/chain/regen/interface.d.ts.map +1 -1
  50. package/lib/chain/regen/interface.js +1 -0
  51. package/lib/chain/regen/interface.js.map +1 -1
  52. package/lib/chain/regen/queued.d.ts +2 -2
  53. package/lib/chain/regen/queued.d.ts.map +1 -1
  54. package/lib/chain/regen/queued.js +5 -5
  55. package/lib/chain/regen/queued.js.map +1 -1
  56. package/lib/chain/stateCache/fifoBlockStateCache.d.ts +5 -1
  57. package/lib/chain/stateCache/fifoBlockStateCache.d.ts.map +1 -1
  58. package/lib/chain/stateCache/fifoBlockStateCache.js +6 -0
  59. package/lib/chain/stateCache/fifoBlockStateCache.js.map +1 -1
  60. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts +47 -5
  61. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
  62. package/lib/chain/stateCache/persistentCheckpointsCache.js +117 -7
  63. package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
  64. package/lib/chain/stateCache/types.d.ts +3 -3
  65. package/lib/chain/stateCache/types.d.ts.map +1 -1
  66. package/lib/chain/validation/block.d.ts.map +1 -1
  67. package/lib/chain/validation/block.js +40 -10
  68. package/lib/chain/validation/block.js.map +1 -1
  69. package/lib/chain/validation/executionPayloadBid.d.ts +15 -3
  70. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  71. package/lib/chain/validation/executionPayloadBid.js +165 -10
  72. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  73. package/lib/execution/builder/apiClient.d.ts +70 -0
  74. package/lib/execution/builder/apiClient.d.ts.map +1 -0
  75. package/lib/execution/builder/apiClient.js +202 -0
  76. package/lib/execution/builder/apiClient.js.map +1 -0
  77. package/lib/execution/builder/validateBid.d.ts +23 -0
  78. package/lib/execution/builder/validateBid.d.ts.map +1 -0
  79. package/lib/execution/builder/validateBid.js +119 -0
  80. package/lib/execution/builder/validateBid.js.map +1 -0
  81. package/lib/metrics/metrics/lodestar.d.ts +29 -1
  82. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  83. package/lib/metrics/metrics/lodestar.js +61 -3
  84. package/lib/metrics/metrics/lodestar.js.map +1 -1
  85. package/lib/network/network.d.ts.map +1 -1
  86. package/lib/network/network.js +5 -4
  87. package/lib/network/network.js.map +1 -1
  88. package/lib/network/processor/constants.d.ts +7 -0
  89. package/lib/network/processor/constants.d.ts.map +1 -0
  90. package/lib/network/processor/constants.js +7 -0
  91. package/lib/network/processor/constants.js.map +1 -0
  92. package/lib/network/processor/gossipHandlers.js +1 -1
  93. package/lib/network/processor/gossipHandlers.js.map +1 -1
  94. package/lib/network/processor/gossipQueues/indexed.d.ts.map +1 -1
  95. package/lib/network/processor/gossipQueues/indexed.js +0 -1
  96. package/lib/network/processor/gossipQueues/indexed.js.map +1 -1
  97. package/lib/network/processor/index.d.ts +3 -0
  98. package/lib/network/processor/index.d.ts.map +1 -1
  99. package/lib/network/processor/index.js +52 -23
  100. package/lib/network/processor/index.js.map +1 -1
  101. package/lib/node/nodejs.d.ts.map +1 -1
  102. package/lib/node/nodejs.js +5 -0
  103. package/lib/node/nodejs.js.map +1 -1
  104. package/lib/sync/range/chain.d.ts.map +1 -1
  105. package/lib/sync/range/chain.js +9 -2
  106. package/lib/sync/range/chain.js.map +1 -1
  107. package/lib/sync/range/range.js +1 -1
  108. package/lib/sync/range/range.js.map +1 -1
  109. package/lib/sync/unknownBlock.d.ts +6 -2
  110. package/lib/sync/unknownBlock.d.ts.map +1 -1
  111. package/lib/sync/unknownBlock.js +48 -17
  112. package/lib/sync/unknownBlock.js.map +1 -1
  113. package/package.json +15 -15
  114. package/src/api/impl/beacon/blocks/index.ts +48 -13
  115. package/src/api/impl/lodestar/index.ts +1 -1
  116. package/src/api/impl/validator/index.ts +290 -49
  117. package/src/api/impl/validator/utils.ts +1 -1
  118. package/src/chain/archiveStore/archiveStore.ts +1 -1
  119. package/src/chain/blocks/index.ts +7 -7
  120. package/src/chain/blocks/verifyBlock.ts +5 -2
  121. package/src/chain/chain.ts +8 -1
  122. package/src/chain/errors/executionPayloadBid.ts +6 -0
  123. package/src/chain/forkChoice/index.ts +4 -0
  124. package/src/chain/interface.ts +4 -2
  125. package/src/chain/opPools/executionPayloadBidPool.ts +13 -7
  126. package/src/chain/opPools/index.ts +1 -1
  127. package/src/chain/prepareNextSlot.ts +49 -6
  128. package/src/chain/produceBlock/computeNewStateRoot.ts +3 -38
  129. package/src/chain/produceBlock/produceBlockBody.ts +1 -1
  130. package/src/chain/regen/interface.ts +3 -2
  131. package/src/chain/regen/queued.ts +5 -5
  132. package/src/chain/stateCache/fifoBlockStateCache.ts +8 -1
  133. package/src/chain/stateCache/persistentCheckpointsCache.ts +133 -8
  134. package/src/chain/stateCache/types.ts +3 -3
  135. package/src/chain/validation/block.ts +43 -10
  136. package/src/chain/validation/executionPayloadBid.ts +192 -12
  137. package/src/execution/builder/apiClient.ts +264 -0
  138. package/src/execution/builder/validateBid.ts +181 -0
  139. package/src/metrics/metrics/lodestar.ts +64 -4
  140. package/src/network/network.ts +7 -4
  141. package/src/network/processor/constants.ts +6 -0
  142. package/src/network/processor/gossipHandlers.ts +1 -1
  143. package/src/network/processor/gossipQueues/indexed.ts +0 -1
  144. package/src/network/processor/index.ts +67 -30
  145. package/src/node/nodejs.ts +5 -0
  146. package/src/sync/range/chain.ts +9 -2
  147. package/src/sync/range/range.ts +1 -1
  148. package/src/sync/unknownBlock.ts +62 -18
@@ -17,6 +17,7 @@ import {validateGossipExecutionPayloadEnvelope} from "../chain/validation/execut
17
17
  import {Metrics} from "../metrics/index.js";
18
18
  import {INetwork, NetworkEvent, NetworkEventData, prettyPrintPeerIdStr} from "../network/index.js";
19
19
  import {PeerSyncMeta} from "../network/peers/peersData.js";
20
+ import {MAX_PEERS_PER_ROOT} from "../network/processor/constants.js";
20
21
  import {PeerIdStr} from "../util/peerId.js";
21
22
  import {shuffle} from "../util/shuffle.js";
22
23
  import {sortBy} from "../util/sortBy.js";
@@ -165,6 +166,16 @@ export class BlockInputSync {
165
166
  this.chain.emitter.on(routes.events.EventType.executionPayload, this.onPayloadImported);
166
167
  this.network.events.on(NetworkEvent.peerConnected, this.onPeerConnected);
167
168
  this.network.events.on(NetworkEvent.peerDisconnected, this.onPeerDisconnected);
169
+
170
+ // Seed the balancer with peers that connected before we subscribed
171
+ for (const peerId of this.network.getConnectedPeers()) {
172
+ try {
173
+ this.peerBalancer.onPeerConnected(peerId, this.network.getConnectedPeerSyncMeta(peerId));
174
+ } catch (e) {
175
+ this.logger.debug("Failed to seed connected peer into BlockInputSync balancer", {peerId}, e as Error);
176
+ }
177
+ }
178
+
168
179
  this.subscribedToNetworkEvents = true;
169
180
  }
170
181
  }
@@ -182,6 +193,7 @@ export class BlockInputSync {
182
193
  this.chain.emitter.off(routes.events.EventType.executionPayload, this.onPayloadImported);
183
194
  this.network.events.off(NetworkEvent.peerConnected, this.onPeerConnected);
184
195
  this.network.events.off(NetworkEvent.peerDisconnected, this.onPeerDisconnected);
196
+ this.peerBalancer.clear();
185
197
  this.subscribedToNetworkEvents = false;
186
198
  }
187
199
 
@@ -198,10 +210,12 @@ export class BlockInputSync {
198
210
  */
199
211
  private onUnknownBlockRoot = (data: ChainEventData[ChainEvent.unknownBlockRoot]): void => {
200
212
  try {
201
- this.addByRootHex(data.rootHex, data.peer);
202
- this.triggerUnknownBlockSearch();
203
- this.metrics?.blockInputSync.requests.inc({type: PendingBlockType.UNKNOWN_BLOCK_ROOT});
204
- this.metrics?.blockInputSync.source.inc({source: data.source});
213
+ const isNewRoot = this.addByRootHex(data.rootHex, data.peer);
214
+ if (isNewRoot) {
215
+ this.triggerUnknownBlockSearch();
216
+ this.metrics?.blockInputSync.requests.inc({type: PendingBlockType.UNKNOWN_BLOCK_ROOT});
217
+ this.metrics?.blockInputSync.source.inc({source: data.source});
218
+ }
205
219
  } catch (e) {
206
220
  this.logger.debug("Error handling unknownBlockRoot event", {}, e as Error);
207
221
  }
@@ -223,10 +237,12 @@ export class BlockInputSync {
223
237
 
224
238
  private onUnknownEnvelopeBlockRoot = (data: ChainEventData[ChainEvent.unknownEnvelopeBlockRoot]): void => {
225
239
  try {
226
- this.addByPayloadRootHex(data.rootHex, data.peer, this.resolvePayloadSlot(data.rootHex));
227
- this.triggerUnknownBlockSearch();
228
- this.metrics?.blockInputSync.requests.inc({type: PendingBlockType.UNKNOWN_PAYLOAD_BLOCK_ROOT});
229
- this.metrics?.blockInputSync.payloadSource.inc({source: data.source});
240
+ const isNewRoot = this.addByPayloadRootHex(data.rootHex, data.peer, this.resolvePayloadSlot(data.rootHex));
241
+ if (isNewRoot) {
242
+ this.triggerUnknownBlockSearch();
243
+ this.metrics?.blockInputSync.requests.inc({type: PendingBlockType.UNKNOWN_PAYLOAD_BLOCK_ROOT});
244
+ this.metrics?.blockInputSync.payloadSource.inc({source: data.source});
245
+ }
230
246
  } catch (e) {
231
247
  this.logger.debug("Error handling unknownEnvelopeBlockRoot event", {}, e as Error);
232
248
  }
@@ -385,7 +401,9 @@ export class BlockInputSync {
385
401
  });
386
402
  }
387
403
 
388
- if (peerIdStr) {
404
+ // bound peers tracked per root: propagationSource is recorded pre-validation, so cap the set (#9923).
405
+ // Once at the cap, ignore further peers rather than evicting already-tracked ones.
406
+ if (peerIdStr && pendingBlock.peerIdStrings.size < MAX_PEERS_PER_ROOT) {
389
407
  pendingBlock.peerIdStrings.add(peerIdStr);
390
408
  }
391
409
 
@@ -420,7 +438,9 @@ export class BlockInputSync {
420
438
  });
421
439
  }
422
440
 
423
- if (peerIdStr) {
441
+ // bound peers tracked per root: propagationSource is recorded pre-validation, so cap the set (#9923).
442
+ // Once at the cap, ignore further peers rather than evicting already-tracked ones.
443
+ if (peerIdStr && pendingBlock.peerIdStrings.size < MAX_PEERS_PER_ROOT) {
424
444
  pendingBlock.peerIdStrings.add(peerIdStr);
425
445
  }
426
446
 
@@ -462,8 +482,7 @@ export class BlockInputSync {
462
482
  ) {
463
483
  pendingPayload.slot = slot;
464
484
  }
465
-
466
- if (peerIdStr) {
485
+ if (peerIdStr && pendingPayload.peerIdStrings.size < MAX_PEERS_PER_ROOT) {
467
486
  pendingPayload.peerIdStrings.add(peerIdStr);
468
487
  }
469
488
 
@@ -509,7 +528,7 @@ export class BlockInputSync {
509
528
  envelope
510
529
  );
511
530
 
512
- if (peerIdStr) {
531
+ if (peerIdStr && pendingPayload.peerIdStrings.size < MAX_PEERS_PER_ROOT) {
513
532
  pendingPayload.peerIdStrings.add(peerIdStr);
514
533
  }
515
534
 
@@ -1235,7 +1254,12 @@ export class BlockInputSync {
1235
1254
  const pendingColumns = payloadInput?.hasAllData()
1236
1255
  ? new Set<number>()
1237
1256
  : new Set(payloadInput?.getMissingSampledColumnMeta().missing ?? []);
1238
- const peerMeta = this.peerBalancer.bestPeerForPendingColumns(pendingColumns, excludedPeers);
1257
+ // prefer peers that gossiped this payload root to us (#9923)
1258
+ const peerMeta = this.peerBalancer.bestPeerForPendingColumns(
1259
+ pendingColumns,
1260
+ excludedPeers,
1261
+ cacheItem.peerIdStrings
1262
+ );
1239
1263
  if (peerMeta === null) {
1240
1264
  if (this.peerBalancer.getNextRateLimitRetryAt(pendingColumns, excludedPeers) !== null) {
1241
1265
  throw new UnknownBlockRateLimitedError(
@@ -1444,7 +1468,12 @@ export class BlockInputSync {
1444
1468
  isPendingBlockInput(cacheItem) && isBlockInputColumns(cacheItem.blockInput)
1445
1469
  ? new Set(cacheItem.blockInput.getMissingSampledColumnMeta().missing)
1446
1470
  : defaultPendingColumns;
1447
- const peerMeta = this.peerBalancer.bestPeerForPendingColumns(pendingColumns, excludedPeers);
1471
+ // prefer peers that gossiped this block root to us (#9923)
1472
+ const peerMeta = this.peerBalancer.bestPeerForPendingColumns(
1473
+ pendingColumns,
1474
+ excludedPeers,
1475
+ cacheItem.peerIdStrings
1476
+ );
1448
1477
  if (peerMeta === null) {
1449
1478
  if (this.peerBalancer.getNextRateLimitRetryAt(pendingColumns, excludedPeers) !== null) {
1450
1479
  throw new UnknownBlockRateLimitedError(
@@ -1720,6 +1749,13 @@ export class UnknownBlockPeerBalancer {
1720
1749
  this.rateLimitedUntilByPeer.delete(peerId);
1721
1750
  }
1722
1751
 
1752
+ /** Reset all tracked peer state, e.g. when BlockInputSync unsubscribes from the network. */
1753
+ clear(): void {
1754
+ this.peersMeta.clear();
1755
+ this.activeRequests.clear();
1756
+ this.rateLimitedUntilByPeer.clear();
1757
+ }
1758
+
1723
1759
  onRateLimited(peerId: PeerIdStr, rateLimitedUntilMs: number): void {
1724
1760
  this.rateLimitedUntilByPeer.set(peerId, rateLimitedUntilMs);
1725
1761
  }
@@ -1755,11 +1791,17 @@ export class UnknownBlockPeerBalancer {
1755
1791
  }
1756
1792
 
1757
1793
  /**
1758
- * called from fetchBlockInput() where we only have block root and nothing else
1794
+ * called from fetchBlockInput()/fetchPayloadInput() with a block/payload root.
1759
1795
  * excludedPeers are the peers that we requested already so we don't want to try again
1760
1796
  * pendingColumns is empty for prefulu, or the 1st time we we download a block by root
1797
+ * preferredPeers are the peers NetworkProcessor told us gossiped this root (from
1798
+ * pendingBlock/cacheItem.peerIdStrings). They are preferred but not required.
1761
1799
  */
1762
- bestPeerForPendingColumns(pendingColumns: Set<number>, excludedPeers: Set<PeerIdStr>): PeerSyncMeta | null {
1800
+ bestPeerForPendingColumns(
1801
+ pendingColumns: Set<number>,
1802
+ excludedPeers: Set<PeerIdStr>,
1803
+ preferredPeers?: Set<PeerIdStr>
1804
+ ): PeerSyncMeta | null {
1763
1805
  const eligiblePeers = this.filterPeers(pendingColumns, excludedPeers);
1764
1806
  if (eligiblePeers.length === 0) {
1765
1807
  return null;
@@ -1767,7 +1809,9 @@ export class UnknownBlockPeerBalancer {
1767
1809
 
1768
1810
  const sortedEligiblePeers = sortBy(
1769
1811
  shuffle(eligiblePeers),
1770
- // prefer peers with least active req
1812
+ // 1st key: prefer peers we heard about this root from
1813
+ (peerId) => (preferredPeers?.has(peerId) ? 0 : 1),
1814
+ // 2nd key (tiebreak): prefer peers with least active req
1771
1815
  (peerId) => this.activeRequests.get(peerId) ?? 0
1772
1816
  );
1773
1817