@lodestar/beacon-node 1.49.0-dev.4d35c8b82e → 1.49.0-dev.535f5dd45f

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 (222) hide show
  1. package/lib/api/impl/beacon/blocks/index.js +2 -2
  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 +4 -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 +9 -7
  8. package/lib/api/impl/validator/index.js.map +1 -1
  9. package/lib/chain/archiveStore/archiveStore.d.ts +1 -2
  10. package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
  11. package/lib/chain/archiveStore/archiveStore.js +0 -5
  12. package/lib/chain/archiveStore/archiveStore.js.map +1 -1
  13. package/lib/chain/archiveStore/historicalState/metrics.d.ts.map +1 -1
  14. package/lib/chain/archiveStore/historicalState/metrics.js +5 -6
  15. package/lib/chain/archiveStore/historicalState/metrics.js.map +1 -1
  16. package/lib/chain/archiveStore/utils/pruneHistory.d.ts.map +1 -1
  17. package/lib/chain/archiveStore/utils/pruneHistory.js +14 -3
  18. package/lib/chain/archiveStore/utils/pruneHistory.js.map +1 -1
  19. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  20. package/lib/chain/blocks/importExecutionPayload.js +13 -0
  21. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  22. package/lib/chain/blocks/index.js +2 -2
  23. package/lib/chain/blocks/index.js.map +1 -1
  24. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +1 -1
  25. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
  26. package/lib/chain/emitter.d.ts +10 -0
  27. package/lib/chain/emitter.d.ts.map +1 -1
  28. package/lib/chain/emitter.js +4 -0
  29. package/lib/chain/emitter.js.map +1 -1
  30. package/lib/chain/errors/attesterSlashingError.d.ts +4 -1
  31. package/lib/chain/errors/attesterSlashingError.d.ts.map +1 -1
  32. package/lib/chain/errors/attesterSlashingError.js +1 -0
  33. package/lib/chain/errors/attesterSlashingError.js.map +1 -1
  34. package/lib/chain/errors/payloadAttestation.d.ts +4 -0
  35. package/lib/chain/errors/payloadAttestation.d.ts.map +1 -1
  36. package/lib/chain/errors/payloadAttestation.js +1 -0
  37. package/lib/chain/errors/payloadAttestation.js.map +1 -1
  38. package/lib/chain/errors/proposerSlashingError.d.ts +4 -1
  39. package/lib/chain/errors/proposerSlashingError.d.ts.map +1 -1
  40. package/lib/chain/errors/proposerSlashingError.js +1 -0
  41. package/lib/chain/errors/proposerSlashingError.js.map +1 -1
  42. package/lib/chain/options.d.ts +0 -4
  43. package/lib/chain/options.d.ts.map +1 -1
  44. package/lib/chain/options.js +0 -1
  45. package/lib/chain/options.js.map +1 -1
  46. package/lib/chain/produceBlock/computeNewStateRoot.d.ts.map +1 -1
  47. package/lib/chain/produceBlock/computeNewStateRoot.js +4 -2
  48. package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
  49. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  50. package/lib/chain/produceBlock/produceBlockBody.js +6 -6
  51. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  52. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +2 -1
  53. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  54. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +3 -2
  55. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  56. package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
  57. package/lib/chain/validation/attesterSlashing.js +1 -2
  58. package/lib/chain/validation/attesterSlashing.js.map +1 -1
  59. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
  60. package/lib/chain/validation/payloadAttestationMessage.js +8 -1
  61. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
  62. package/lib/chain/validation/proposerSlashing.js +1 -2
  63. package/lib/chain/validation/proposerSlashing.js.map +1 -1
  64. package/lib/chain/validatorMonitor.d.ts.map +1 -1
  65. package/lib/chain/validatorMonitor.js +2 -2
  66. package/lib/chain/validatorMonitor.js.map +1 -1
  67. package/lib/db/beacon.d.ts +1 -2
  68. package/lib/db/beacon.d.ts.map +1 -1
  69. package/lib/db/beacon.js +1 -3
  70. package/lib/db/beacon.js.map +1 -1
  71. package/lib/db/buckets.d.ts +0 -1
  72. package/lib/db/buckets.d.ts.map +1 -1
  73. package/lib/db/buckets.js +1 -1
  74. package/lib/db/buckets.js.map +1 -1
  75. package/lib/db/interface.d.ts +1 -2
  76. package/lib/db/interface.d.ts.map +1 -1
  77. package/lib/db/repositories/blockArchive.d.ts +5 -0
  78. package/lib/db/repositories/blockArchive.d.ts.map +1 -1
  79. package/lib/db/repositories/blockArchive.js +36 -1
  80. package/lib/db/repositories/blockArchive.js.map +1 -1
  81. package/lib/db/repositories/blockArchiveIndex.d.ts +2 -2
  82. package/lib/db/repositories/blockArchiveIndex.d.ts.map +1 -1
  83. package/lib/db/repositories/index.d.ts +0 -1
  84. package/lib/db/repositories/index.d.ts.map +1 -1
  85. package/lib/db/repositories/index.js +0 -1
  86. package/lib/db/repositories/index.js.map +1 -1
  87. package/lib/metrics/metrics/lodestar.d.ts +35 -14
  88. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  89. package/lib/metrics/metrics/lodestar.js +76 -24
  90. package/lib/metrics/metrics/lodestar.js.map +1 -1
  91. package/lib/metrics/metrics.d.ts +3 -1
  92. package/lib/metrics/metrics.d.ts.map +1 -1
  93. package/lib/metrics/metrics.js +2 -2
  94. package/lib/metrics/metrics.js.map +1 -1
  95. package/lib/network/gossip/encoding.d.ts +1 -2
  96. package/lib/network/gossip/encoding.d.ts.map +1 -1
  97. package/lib/network/gossip/encoding.js +5 -10
  98. package/lib/network/gossip/encoding.js.map +1 -1
  99. package/lib/network/gossip/gossipsub.d.ts.map +1 -1
  100. package/lib/network/gossip/gossipsub.js +16 -1
  101. package/lib/network/gossip/gossipsub.js.map +1 -1
  102. package/lib/network/gossip/topic.d.ts +9 -6
  103. package/lib/network/gossip/topic.d.ts.map +1 -1
  104. package/lib/network/gossip/topic.js +23 -8
  105. package/lib/network/gossip/topic.js.map +1 -1
  106. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  107. package/lib/network/processor/gossipHandlers.js +16 -5
  108. package/lib/network/processor/gossipHandlers.js.map +1 -1
  109. package/lib/network/processor/gossipValidatorFn.d.ts +2 -0
  110. package/lib/network/processor/gossipValidatorFn.d.ts.map +1 -1
  111. package/lib/network/processor/gossipValidatorFn.js +88 -7
  112. package/lib/network/processor/gossipValidatorFn.js.map +1 -1
  113. package/lib/network/processor/index.d.ts +6 -2
  114. package/lib/network/processor/index.d.ts.map +1 -1
  115. package/lib/network/processor/index.js +62 -24
  116. package/lib/network/processor/index.js.map +1 -1
  117. package/lib/network/reqresp/handlers/index.d.ts.map +1 -1
  118. package/lib/network/reqresp/handlers/index.js +20 -4
  119. package/lib/network/reqresp/handlers/index.js.map +1 -1
  120. package/lib/network/reqresp/protocols.d.ts.map +1 -1
  121. package/lib/network/reqresp/protocols.js +19 -5
  122. package/lib/network/reqresp/protocols.js.map +1 -1
  123. package/lib/node/nodejs.d.ts +2 -7
  124. package/lib/node/nodejs.d.ts.map +1 -1
  125. package/lib/node/nodejs.js +2 -22
  126. package/lib/node/nodejs.js.map +1 -1
  127. package/lib/sync/interface.d.ts +1 -2
  128. package/lib/sync/interface.d.ts.map +1 -1
  129. package/lib/sync/options.d.ts +0 -6
  130. package/lib/sync/options.d.ts.map +1 -1
  131. package/lib/sync/options.js +0 -2
  132. package/lib/sync/options.js.map +1 -1
  133. package/lib/sync/types.d.ts +39 -2
  134. package/lib/sync/types.d.ts.map +1 -1
  135. package/lib/sync/types.js +42 -2
  136. package/lib/sync/types.js.map +1 -1
  137. package/lib/sync/unknownBlock.d.ts +20 -0
  138. package/lib/sync/unknownBlock.d.ts.map +1 -1
  139. package/lib/sync/unknownBlock.js +231 -26
  140. package/lib/sync/unknownBlock.js.map +1 -1
  141. package/lib/util/shuffle.d.ts +0 -4
  142. package/lib/util/shuffle.d.ts.map +1 -1
  143. package/lib/util/shuffle.js +0 -8
  144. package/lib/util/shuffle.js.map +1 -1
  145. package/lib/util/sszBytes.d.ts +5 -0
  146. package/lib/util/sszBytes.d.ts.map +1 -1
  147. package/lib/util/sszBytes.js +13 -1
  148. package/lib/util/sszBytes.js.map +1 -1
  149. package/package.json +16 -16
  150. package/src/api/impl/beacon/blocks/index.ts +2 -2
  151. package/src/api/impl/beacon/pool/index.ts +6 -2
  152. package/src/api/impl/validator/index.ts +9 -7
  153. package/src/chain/archiveStore/archiveStore.ts +0 -6
  154. package/src/chain/archiveStore/historicalState/metrics.ts +5 -7
  155. package/src/chain/archiveStore/utils/pruneHistory.ts +14 -4
  156. package/src/chain/blocks/importExecutionPayload.ts +14 -0
  157. package/src/chain/blocks/index.ts +2 -2
  158. package/src/chain/blocks/payloadEnvelopeInput/types.ts +1 -1
  159. package/src/chain/emitter.ts +7 -2
  160. package/src/chain/errors/attesterSlashingError.ts +3 -1
  161. package/src/chain/errors/payloadAttestation.ts +2 -0
  162. package/src/chain/errors/proposerSlashingError.ts +3 -1
  163. package/src/chain/options.ts +0 -5
  164. package/src/chain/produceBlock/computeNewStateRoot.ts +9 -2
  165. package/src/chain/produceBlock/produceBlockBody.ts +17 -6
  166. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +3 -2
  167. package/src/chain/validation/attesterSlashing.ts +1 -2
  168. package/src/chain/validation/payloadAttestationMessage.ts +9 -0
  169. package/src/chain/validation/proposerSlashing.ts +1 -2
  170. package/src/chain/validatorMonitor.ts +12 -2
  171. package/src/db/beacon.ts +0 -5
  172. package/src/db/buckets.ts +1 -1
  173. package/src/db/interface.ts +0 -3
  174. package/src/db/repositories/blockArchive.ts +38 -1
  175. package/src/db/repositories/index.ts +0 -1
  176. package/src/metrics/metrics/lodestar.ts +87 -28
  177. package/src/metrics/metrics.ts +7 -2
  178. package/src/network/gossip/encoding.ts +5 -8
  179. package/src/network/gossip/gossipsub.ts +19 -2
  180. package/src/network/gossip/topic.ts +25 -7
  181. package/src/network/processor/gossipHandlers.ts +18 -5
  182. package/src/network/processor/gossipValidatorFn.ts +111 -7
  183. package/src/network/processor/index.ts +81 -24
  184. package/src/network/reqresp/handlers/index.ts +49 -5
  185. package/src/network/reqresp/protocols.ts +31 -6
  186. package/src/node/nodejs.ts +0 -27
  187. package/src/sync/interface.ts +1 -2
  188. package/src/sync/options.ts +0 -8
  189. package/src/sync/types.ts +44 -5
  190. package/src/sync/unknownBlock.ts +254 -26
  191. package/src/util/shuffle.ts +0 -9
  192. package/src/util/sszBytes.ts +18 -0
  193. package/lib/chain/archiveStore/utils/updateBackfillRange.d.ts +0 -20
  194. package/lib/chain/archiveStore/utils/updateBackfillRange.d.ts.map +0 -1
  195. package/lib/chain/archiveStore/utils/updateBackfillRange.js +0 -40
  196. package/lib/chain/archiveStore/utils/updateBackfillRange.js.map +0 -1
  197. package/lib/db/repositories/backfilledRanges.d.ts +0 -18
  198. package/lib/db/repositories/backfilledRanges.d.ts.map +0 -1
  199. package/lib/db/repositories/backfilledRanges.js +0 -26
  200. package/lib/db/repositories/backfilledRanges.js.map +0 -1
  201. package/lib/sync/backfill/backfill.d.ts +0 -169
  202. package/lib/sync/backfill/backfill.d.ts.map +0 -1
  203. package/lib/sync/backfill/backfill.js +0 -686
  204. package/lib/sync/backfill/backfill.js.map +0 -1
  205. package/lib/sync/backfill/errors.d.ts +0 -30
  206. package/lib/sync/backfill/errors.d.ts.map +0 -1
  207. package/lib/sync/backfill/errors.js +0 -15
  208. package/lib/sync/backfill/errors.js.map +0 -1
  209. package/lib/sync/backfill/index.d.ts +0 -2
  210. package/lib/sync/backfill/index.d.ts.map +0 -1
  211. package/lib/sync/backfill/index.js +0 -2
  212. package/lib/sync/backfill/index.js.map +0 -1
  213. package/lib/sync/backfill/verify.d.ts +0 -18
  214. package/lib/sync/backfill/verify.d.ts.map +0 -1
  215. package/lib/sync/backfill/verify.js +0 -36
  216. package/lib/sync/backfill/verify.js.map +0 -1
  217. package/src/chain/archiveStore/utils/updateBackfillRange.ts +0 -50
  218. package/src/db/repositories/backfilledRanges.ts +0 -29
  219. package/src/sync/backfill/backfill.ts +0 -916
  220. package/src/sync/backfill/errors.ts +0 -23
  221. package/src/sync/backfill/index.ts +0 -1
  222. package/src/sync/backfill/verify.ts +0 -58
@@ -5,7 +5,7 @@ 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";
8
- import {Logger, fromHex, prettyPrintIndices, pruneSetToMax, sleep, toRootHex} from "@lodestar/utils";
8
+ import {Logger, fromHex, isErrorAborted, prettyPrintIndices, pruneSetToMax, sleep, toRootHex} from "@lodestar/utils";
9
9
  import {isBlockInputBlobs, isBlockInputColumns} from "../chain/blocks/blockInput/blockInput.js";
10
10
  import {BlockInputSource, IBlockInput} from "../chain/blocks/blockInput/types.js";
11
11
  import {PayloadError, PayloadErrorCode} from "../chain/blocks/importExecutionPayload.js";
@@ -18,6 +18,7 @@ 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
20
  import {MAX_PEERS_PER_ROOT} from "../network/processor/constants.js";
21
+ import {ClockEvent} from "../util/clock.js";
21
22
  import {PeerIdStr} from "../util/peerId.js";
22
23
  import {shuffle} from "../util/shuffle.js";
23
24
  import {sortBy} from "../util/sortBy.js";
@@ -26,7 +27,10 @@ import {MAX_CONCURRENT_REQUESTS} from "./constants.js";
26
27
  import {SyncOptions} from "./options.js";
27
28
  import {
28
29
  BlockInputSyncCacheItem,
30
+ DeferredPayloadResult,
31
+ DownloadResult,
29
32
  DroppedItemReason,
33
+ FetchResult,
30
34
  PayloadSyncCacheItem,
31
35
  PendingBlockInput,
32
36
  PendingBlockInputStatus,
@@ -55,6 +59,11 @@ const MAX_PENDING_BLOCKS = 100;
55
59
  */
56
60
  const PRUNE_UNRESOLVED_SLOT_EPOCHS = 2;
57
61
 
62
+ /**
63
+ * Poll pending payloads of the current slot this often, between PAYLOAD_DUE and the end of the slot.
64
+ */
65
+ export const PAYLOAD_POLL_INTERVAL_MS = 1_000;
66
+
58
67
  type AdvancePendingBlockResult =
59
68
  | "ready"
60
69
  | "queued_block"
@@ -63,14 +72,6 @@ type AdvancePendingBlockResult =
63
72
  | "blocked"
64
73
  | "removed";
65
74
 
66
- enum FetchResult {
67
- SuccessResolved = "success_resolved",
68
- SuccessMissingParent = "success_missing_parent",
69
- SuccessLate = "success_late",
70
- FailureTriedAllPeers = "failure_tried_all_peers",
71
- FailureMaxAttempts = "failure_max_attempts",
72
- }
73
-
74
75
  class UnknownBlockRateLimitedError extends Error {
75
76
  constructor(message: string) {
76
77
  super(message);
@@ -122,6 +123,11 @@ export class BlockInputSync {
122
123
  private subscribedToNetworkEvents = false;
123
124
  private peerBalancer: UnknownBlockPeerBalancer;
124
125
  private rateLimitBackoffTimeout: NodeJS.Timeout | undefined;
126
+ /**
127
+ * Search unknown payload starting at PAYLOAD_DUE_BPS.
128
+ */
129
+ private readonly deferredPayloadRoots = new Map<RootHex, {slot: Slot; source: BlockInputSource; peer?: PeerIdStr}>();
130
+ private payloadPollAbortController: AbortController | undefined;
125
131
 
126
132
  constructor(
127
133
  private readonly config: ChainForkConfig,
@@ -158,6 +164,7 @@ export class BlockInputSync {
158
164
  this.logger.verbose("BlockInputSync enabled.");
159
165
  this.chain.emitter.on(ChainEvent.unknownBlockRoot, this.onUnknownBlockRoot);
160
166
  this.chain.emitter.on(ChainEvent.unknownEnvelopeBlockRoot, this.onUnknownEnvelopeBlockRoot);
167
+ this.chain.emitter.on(ChainEvent.unknownEnvelopeBlockRootSlot, this.onUnknownEnvelopeBlockRootSlot);
161
168
  this.chain.emitter.on(ChainEvent.incompleteBlockInput, this.onIncompleteBlockInput);
162
169
  this.chain.emitter.on(ChainEvent.incompletePayloadEnvelope, this.onIncompletePayloadEnvelope);
163
170
  this.chain.emitter.on(ChainEvent.blockUnknownParent, this.onUnknownParent);
@@ -166,6 +173,7 @@ export class BlockInputSync {
166
173
  this.chain.emitter.on(routes.events.EventType.executionPayload, this.onPayloadImported);
167
174
  this.network.events.on(NetworkEvent.peerConnected, this.onPeerConnected);
168
175
  this.network.events.on(NetworkEvent.peerDisconnected, this.onPeerDisconnected);
176
+ this.chain.clock.on(ClockEvent.slot, this.startPayloadPollAtSlot);
169
177
 
170
178
  // Seed the balancer with peers that connected before we subscribed
171
179
  for (const peerId of this.network.getConnectedPeers()) {
@@ -177,14 +185,22 @@ export class BlockInputSync {
177
185
  }
178
186
 
179
187
  this.subscribedToNetworkEvents = true;
188
+ // we subscribe mid-slot, and a root can be deferred at any point in the slot, so start this
189
+ // slot's loop now instead of waiting for the next ClockEvent.slot
190
+ this.startPayloadPollAtSlot(this.chain.clock.currentSlot);
180
191
  }
181
192
  }
182
193
 
183
194
  unsubscribeFromNetwork(): void {
184
195
  this.logger.verbose("BlockInputSync disabled.");
185
196
  this.clearRateLimitBackoffTimer();
197
+ this.chain.clock.off(ClockEvent.slot, this.startPayloadPollAtSlot);
198
+ this.payloadPollAbortController?.abort();
199
+ this.payloadPollAbortController = undefined;
200
+ this.deferredPayloadRoots.clear();
186
201
  this.chain.emitter.off(ChainEvent.unknownBlockRoot, this.onUnknownBlockRoot);
187
202
  this.chain.emitter.off(ChainEvent.unknownEnvelopeBlockRoot, this.onUnknownEnvelopeBlockRoot);
203
+ this.chain.emitter.off(ChainEvent.unknownEnvelopeBlockRootSlot, this.onUnknownEnvelopeBlockRootSlot);
188
204
  this.chain.emitter.off(ChainEvent.incompleteBlockInput, this.onIncompleteBlockInput);
189
205
  this.chain.emitter.off(ChainEvent.incompletePayloadEnvelope, this.onIncompletePayloadEnvelope);
190
206
  this.chain.emitter.off(ChainEvent.blockUnknownParent, this.onUnknownParent);
@@ -211,8 +227,11 @@ export class BlockInputSync {
211
227
  private onUnknownBlockRoot = (data: ChainEventData[ChainEvent.unknownBlockRoot]): void => {
212
228
  try {
213
229
  const isNewRoot = this.addByRootHex(data.rootHex, data.peer);
214
- if (isNewRoot) {
230
+ // A retained entry (an earlier download failed, #10018) is not new but still needs a retry pass.
231
+ if (this.pendingBlocks.get(data.rootHex)?.status === PendingBlockInputStatus.pending) {
215
232
  this.triggerUnknownBlockSearch();
233
+ }
234
+ if (isNewRoot) {
216
235
  this.metrics?.blockInputSync.requests.inc({type: PendingBlockType.UNKNOWN_BLOCK_ROOT});
217
236
  this.metrics?.blockInputSync.source.inc({source: data.source});
218
237
  }
@@ -248,6 +267,33 @@ export class BlockInputSync {
248
267
  }
249
268
  };
250
269
 
270
+ private onUnknownEnvelopeBlockRootSlot = (data: ChainEventData[ChainEvent.unknownEnvelopeBlockRootSlot]): void => {
271
+ try {
272
+ if (data.slot === this.chain.clock.currentSlot) {
273
+ // we receive the optimistic search, the poll loop searches it at PAYLOAD_DUE or on its next
274
+ // tick. If that loop already returned - every root it watched was imported - this root waits
275
+ // for the next slot, where startPayloadPollAtSlot moves it to pendingPayloads. That is not the normal
276
+ // scenario, and in a forking condition it only delays the search of the extra root
277
+ const deferred = this.deferredPayloadRoots.get(data.rootHex);
278
+ if (deferred === undefined) {
279
+ this.deferredPayloadRoots.set(data.rootHex, {slot: data.slot, source: data.source, peer: data.peer});
280
+ } else if (deferred.peer === undefined) {
281
+ deferred.peer = data.peer;
282
+ }
283
+ return;
284
+ }
285
+
286
+ const isNewRoot = this.addByPayloadRootHex(data.rootHex, data.peer, data.slot);
287
+ if (isNewRoot) {
288
+ this.triggerUnknownBlockSearch();
289
+ this.metrics?.blockInputSync.requests.inc({type: PendingBlockType.UNKNOWN_PAYLOAD_BLOCK_ROOT_SLOT});
290
+ this.metrics?.blockInputSync.payloadSource.inc({source: data.source});
291
+ }
292
+ } catch (e) {
293
+ this.logger.debug("Error handling unknownEnvelopeBlockRootSlot event", {}, e as Error);
294
+ }
295
+ };
296
+
251
297
  private onIncompletePayloadEnvelope = (data: ChainEventData[ChainEvent.incompletePayloadEnvelope]): void => {
252
298
  try {
253
299
  this.addByPayloadInput(data.payloadInput, data.peer);
@@ -350,12 +396,21 @@ export class BlockInputSync {
350
396
  }
351
397
  }
352
398
 
353
- let deletedBlocks = 0;
399
+ let belowFinalizedBlocks = 0;
400
+ let agedOutBlocks = 0;
354
401
  for (const [rootHex, block] of this.pendingBlocks) {
355
402
  const slot = getBlockInputSyncCacheItemSlot(block);
356
- if (typeof slot === "number" && slot < finalizedSlot) {
403
+ if (typeof slot !== "number") {
404
+ // we may not be able to download a root, hence there is no slot for it
405
+ if (nowSec - block.timeAddedSec > maxSecInCache) {
406
+ this.pendingBlocks.delete(rootHex);
407
+ agedOutBlocks++;
408
+ }
409
+ continue;
410
+ }
411
+ if (slot < finalizedSlot) {
357
412
  this.pendingBlocks.delete(rootHex);
358
- deletedBlocks++;
413
+ belowFinalizedBlocks++;
359
414
  }
360
415
  }
361
416
 
@@ -368,16 +423,20 @@ export class BlockInputSync {
368
423
  if (agedOutPayloads > 0) {
369
424
  this.metrics?.blockInputSync.removedPayloads.inc({reason: DroppedItemReason.agedOut}, agedOutPayloads);
370
425
  }
371
- if (deletedBlocks > 0) {
372
- this.metrics?.blockInputSync.removedBlocks.inc({reason: DroppedItemReason.belowFinalized}, deletedBlocks);
426
+ if (belowFinalizedBlocks > 0) {
427
+ this.metrics?.blockInputSync.removedBlocks.inc({reason: DroppedItemReason.belowFinalized}, belowFinalizedBlocks);
428
+ }
429
+ if (agedOutBlocks > 0) {
430
+ this.metrics?.blockInputSync.removedBlocks.inc({reason: DroppedItemReason.agedOut}, agedOutBlocks);
373
431
  }
374
432
 
375
- this.logger.debug("BlockInputSync.pruneFinalized dropped pre-finalized pending items", {
433
+ this.logger.debug("BlockInputSync.pruneFinalized dropped stale pending items", {
376
434
  finalizedSlot,
377
435
  finalizedRoot: checkpoint.rootHex,
378
436
  belowFinalizedPayloads,
379
437
  agedOutPayloads,
380
- deletedBlocks,
438
+ belowFinalizedBlocks,
439
+ agedOutBlocks,
381
440
  unresolvedSlotPayloads,
382
441
  });
383
442
  };
@@ -791,6 +850,122 @@ export class BlockInputSync {
791
850
  }
792
851
  }
793
852
 
853
+ /**
854
+ * Start this slot's payload poll: end the previous slot's loop, move roots it never got to
855
+ * into pendingPayloads, then poll from PAYLOAD_DUE to the end of the slot.
856
+ */
857
+ private startPayloadPollAtSlot = (slot: Slot): void => {
858
+ if (!isForkPostGloas(this.config.getForkName(slot))) {
859
+ return;
860
+ }
861
+ // end the previous slot's loop, wherever it is: its sleep is bound to this same controller
862
+ this.payloadPollAbortController?.abort();
863
+ this.payloadPollAbortController = new AbortController();
864
+ // entries from an earlier slot is not polled
865
+ for (const [rootHex, {slot: deferredSlot, source, peer}] of this.deferredPayloadRoots) {
866
+ if (deferredSlot < slot) {
867
+ if (!this.chain.forkChoice.hasPayloadHexUnsafe(rootHex)) {
868
+ this.addDeferredPayloadRoot(rootHex, deferredSlot, source, peer);
869
+ }
870
+ this.deferredPayloadRoots.delete(rootHex);
871
+ }
872
+ }
873
+ this.pollPayloadsAtSlot(slot, this.payloadPollAbortController.signal).catch((e) => {
874
+ if (!isErrorAborted(e)) {
875
+ this.logger.debug("Error polling payloads", {slot}, e as Error);
876
+ }
877
+ });
878
+ };
879
+
880
+ /**
881
+ * Poll unknown payloads of the current slot.
882
+ */
883
+ private async pollPayloadsAtSlot(slot: Slot, signal: AbortSignal): Promise<void> {
884
+ // fixed tick count so the loop cannot outlive its slot: for mainnet, it's 6 ticks
885
+ const tickCount = Math.floor(
886
+ (this.config.SLOT_DURATION_MS - this.config.getPayloadDueMs()) / PAYLOAD_POLL_INTERVAL_MS
887
+ );
888
+ // a root still missing on several ticks is searched on each of them, recorded once
889
+ const searchedRoots = new Set<RootHex>();
890
+ let polls = 0;
891
+
892
+ try {
893
+ await sleep(Math.max(0, this.config.getPayloadDueMs() - this.chain.clock.msFromSlot(slot)), signal);
894
+
895
+ for (polls = 0; polls < tickCount; polls++) {
896
+ let importedCount = 0;
897
+ for (const [rootHex, {slot: deferredSlot, source, peer}] of this.deferredPayloadRoots) {
898
+ if (this.chain.forkChoice.hasPayloadHexUnsafe(rootHex)) {
899
+ importedCount++;
900
+ continue;
901
+ }
902
+ // copy to the regular pendingPayloads so that we can search
903
+ this.addDeferredPayloadRoot(rootHex, deferredSlot, source, peer);
904
+ searchedRoots.add(rootHex);
905
+ }
906
+
907
+ // an empty deferredPayloadRoots means there is no optimistic search comes before PAYLOAD_DUE
908
+ // we have to poll until the payload of current slot is imported or slot end
909
+ if (this.deferredPayloadRoots.size > 0 && importedCount === this.deferredPayloadRoots.size) {
910
+ if (searchedRoots.size > 0) {
911
+ // the backup search was needed
912
+ this.metrics?.blockInputSync.deferredPayloadResult.inc({
913
+ result: DeferredPayloadResult.ImportedAfterSearch,
914
+ });
915
+ this.metrics?.blockInputSync.deferredPayloadPolls.observe(polls);
916
+ this.logger.verbose("Payload imported after unknown sync search", {
917
+ slot,
918
+ roots: Array.from(searchedRoots).join(","),
919
+ polls,
920
+ });
921
+ } else {
922
+ // this happens most of the time on devnet
923
+ // gossip delivered everything before PAYLOAD_DUE
924
+ this.metrics?.blockInputSync.deferredPayloadResult.inc({
925
+ result: DeferredPayloadResult.ImportedBeforeSearch,
926
+ });
927
+ }
928
+ return;
929
+ }
930
+
931
+ this.triggerUnknownBlockSearch();
932
+ if (polls < tickCount - 1) {
933
+ // no sleep after the last tick: the loop would otherwise end right at the slot boundary,
934
+ // where startPayloadPollAtSlot aborts it
935
+ await sleep(PAYLOAD_POLL_INTERVAL_MS, signal);
936
+ }
937
+ }
938
+
939
+ // reaching here means the early return never fired
940
+ if (this.deferredPayloadRoots.size > 0) {
941
+ this.metrics?.blockInputSync.deferredPayloadResult.inc({result: DeferredPayloadResult.Unresolved});
942
+ this.logger.debug("Deferred payloads still missing at end of slot", {
943
+ slot,
944
+ roots: Array.from(this.deferredPayloadRoots.keys()).join(","),
945
+ });
946
+ } else {
947
+ // no optimistic search and no payload import ended the loop, eg a skipped slot
948
+ this.metrics?.blockInputSync.deferredPayloadResult.inc({result: DeferredPayloadResult.ResolvedNoRoot});
949
+ this.logger.debug("No deferred payloads at slot", {
950
+ slot,
951
+ });
952
+ }
953
+ } catch (e) {
954
+ if (!isErrorAborted(e)) {
955
+ throw e;
956
+ }
957
+ this.logger.verbose("Payload poll aborted", {slot, polls, msIntoSlot: this.chain.clock.msFromSlot(slot)});
958
+ }
959
+ }
960
+
961
+ private addDeferredPayloadRoot(rootHex: RootHex, slot: Slot, source: BlockInputSource, peer?: PeerIdStr): void {
962
+ const isNewRoot = this.addByPayloadRootHex(rootHex, peer, slot);
963
+ if (isNewRoot) {
964
+ this.metrics?.blockInputSync.requests.inc({type: PendingBlockType.DEFERRED_PAYLOAD_BLOCK_ROOT});
965
+ this.metrics?.blockInputSync.payloadSource.inc({source});
966
+ }
967
+ }
968
+
794
969
  private async downloadBlock(block: BlockInputSyncCacheItem): Promise<void> {
795
970
  if (block.status !== PendingBlockInputStatus.pending) {
796
971
  return;
@@ -814,7 +989,12 @@ export class BlockInputSync {
814
989
  if (!res.err) {
815
990
  this.metrics?.blockInputSync.downloadedBlocksSuccess.inc();
816
991
  const pending = res.result;
817
- this.pendingBlocks.set(pending.blockInput.blockRootHex, pending);
992
+ // pruning may have deleted this entry while we were awaiting the network, do not resurrect it via the set below
993
+ if (!this.pendingBlocks.has(rootHex)) {
994
+ this.logger.verbose("Dropping downloaded block, entry pruned during fetch", logCtx);
995
+ return;
996
+ }
997
+ this.pendingBlocks.set(rootHex, pending);
818
998
  const blockSlot = pending.blockInput.slot;
819
999
  const finalizedSlot = this.chain.forkChoice.getFinalizedBlock().slot;
820
1000
  const delaySec = Date.now() / 1000 - computeTimeAtSlot(this.config, blockSlot, this.chain.genesisTime);
@@ -876,8 +1056,11 @@ export class BlockInputSync {
876
1056
  }
877
1057
 
878
1058
  this.metrics?.blockInputSync.downloadedBlocksError.inc();
879
- this.logger.debug("Ignoring unknown block root after many failed downloads", logCtx, res.err);
880
- this.removeAndDownScoreAllDescendants(block, DroppedItemReason.unavailable);
1059
+ this.logger.debug("Failed to download unknown block root, retained for retry", logCtx, res.err);
1060
+ const pendingBlock = this.pendingBlocks.get(rootHex);
1061
+ if (pendingBlock && pendingBlock.status === PendingBlockInputStatus.fetching) {
1062
+ pendingBlock.status = PendingBlockInputStatus.pending;
1063
+ }
881
1064
  }
882
1065
  }
883
1066
 
@@ -1125,16 +1308,26 @@ export class BlockInputSync {
1125
1308
  return;
1126
1309
  }
1127
1310
  this.pendingPayloads.set(resultRootHex, pendingPayload);
1311
+ const result = isPendingPayloadEnvelope(pendingPayload)
1312
+ ? DownloadResult.WaitingForBlock
1313
+ : this.chain.forkChoice.hasPayloadHexUnsafe(resultRootHex)
1314
+ ? DownloadResult.Late
1315
+ : DownloadResult.Resolved;
1316
+ this.metrics?.blockInputSync.downloadedPayloadsResult.inc({result});
1128
1317
 
1129
1318
  if (isPendingPayloadEnvelope(pendingPayload)) {
1130
1319
  await this.reconcilePayloadEnvelope(pendingPayload);
1131
1320
  } else if (pendingPayload.status === PendingPayloadInputStatus.downloaded) {
1321
+ this.metrics?.blockInputSync.elapsedTimeTillPayloadReceived.observe(
1322
+ Date.now() / 1000 - computeTimeAtSlot(this.config, pendingPayload.payloadInput.slot, this.chain.genesisTime)
1323
+ );
1132
1324
  await this.processPayload(pendingPayload);
1133
1325
  }
1134
1326
  return;
1135
1327
  }
1136
1328
 
1137
- this.logger.debug("Ignoring unknown payload root after failed download", logCtx, res.err);
1329
+ this.metrics?.blockInputSync.downloadedPayloadsResult.inc({result: DownloadResult.Failed});
1330
+ this.logger.debug("Failed to download unknown payload root, retained for retry", logCtx, res.err);
1138
1331
  if (!isPendingPayloadEnvelope(payload)) {
1139
1332
  payload.status = PendingPayloadInputStatus.pending;
1140
1333
  }
@@ -1248,6 +1441,11 @@ export class BlockInputSync {
1248
1441
  : await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
1249
1442
  let envelope = payloadInput?.hasPayloadEnvelope() ? payloadInput.getPayloadEnvelope() : undefined;
1250
1443
 
1444
+ const fetchStartSec = Date.now() / 1000;
1445
+ if (typeof slot === "number") {
1446
+ this.metrics?.blockInputSync.payloadFetchBegin.observe(this.chain.clock.secFromSlot(slot, fetchStartSec));
1447
+ }
1448
+
1251
1449
  let i = 0;
1252
1450
  let deferredByRateLimit = false;
1253
1451
  while (i++ < this.getMaxDownloadAttempts()) {
@@ -1271,6 +1469,11 @@ export class BlockInputSync {
1271
1469
  pendingColumns.size > 0
1272
1470
  ? `cannot find peer with needed columns=${prettyPrintIndices(Array.from(pendingColumns))}`
1273
1471
  : "no peer available to download pending payload";
1472
+ this.metrics?.blockInputSync.payloadFetchTime.observe(
1473
+ {result: FetchResult.FailureTriedAllPeers},
1474
+ Date.now() / 1000 - fetchStartSec
1475
+ );
1476
+ this.metrics?.blockInputSync.payloadFetchPeers.set({result: FetchResult.FailureTriedAllPeers}, i);
1274
1477
  throw Error(`Error fetching payload by root slot=${slot} root=${rootHex} after ${i}: ${reason}`);
1275
1478
  }
1276
1479
 
@@ -1280,7 +1483,12 @@ export class BlockInputSync {
1280
1483
  try {
1281
1484
  if (!envelope) {
1282
1485
  envelope = await this.fetchExecutionPayloadEnvelope(peerId, blockRoot, rootHex);
1486
+ const slotWasUnknown = typeof slot !== "number";
1283
1487
  slot = envelope.message.payload.slotNumber;
1488
+ if (slotWasUnknown) {
1489
+ // we were not able to observe the time into slot when starting the fetch, do it now
1490
+ this.metrics?.blockInputSync.payloadFetchBegin.observe(this.chain.clock.secFromSlot(slot, fetchStartSec));
1491
+ }
1284
1492
  }
1285
1493
 
1286
1494
  payloadInput ??= await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
@@ -1289,6 +1497,11 @@ export class BlockInputSync {
1289
1497
  // envelope and wait for the block body; reconcilePayloadEnvelope validates once the block lands.
1290
1498
  // payloadInput may be seeded from the block body during download, so a non-null payloadInput does not
1291
1499
  // imply the block is imported.
1500
+ this.metrics?.blockInputSync.payloadFetchTime.observe(
1501
+ {result: FetchResult.SuccessWaitingForBlock},
1502
+ Date.now() / 1000 - fetchStartSec
1503
+ );
1504
+ this.metrics?.blockInputSync.payloadFetchPeers.set({result: FetchResult.SuccessWaitingForBlock}, i);
1292
1505
  return {
1293
1506
  status: PendingPayloadInputStatus.waitingForBlock,
1294
1507
  envelope,
@@ -1339,6 +1552,12 @@ export class BlockInputSync {
1339
1552
  });
1340
1553
 
1341
1554
  if (pendingPayload.status === PendingPayloadInputStatus.downloaded) {
1555
+ // late = the payload got imported (via gossip) while we were downloading, same as the block path
1556
+ const result = this.chain.forkChoice.hasPayloadHexUnsafe(rootHex)
1557
+ ? FetchResult.SuccessLate
1558
+ : FetchResult.SuccessResolved;
1559
+ this.metrics?.blockInputSync.payloadFetchTime.observe({result}, Date.now() / 1000 - fetchStartSec);
1560
+ this.metrics?.blockInputSync.payloadFetchPeers.set({result}, i);
1342
1561
  return pendingPayload;
1343
1562
  }
1344
1563
 
@@ -1373,12 +1592,17 @@ export class BlockInputSync {
1373
1592
  }
1374
1593
  }
1375
1594
 
1595
+ this.metrics?.blockInputSync.payloadFetchTime.observe(
1596
+ {result: FetchResult.FailureMaxAttempts},
1597
+ Date.now() / 1000 - fetchStartSec
1598
+ );
1599
+ this.metrics?.blockInputSync.payloadFetchPeers.set({result: FetchResult.FailureMaxAttempts}, i - 1);
1600
+
1376
1601
  if (deferredByRateLimit && this.peerBalancer.getNextRateLimitRetryAt() !== null) {
1377
1602
  throw new UnknownBlockRateLimitedError(
1378
1603
  `Error fetching payload with slot=${slot} root=${rootHex} after ${i - 1} attempts: peers are rate-limited`
1379
1604
  );
1380
1605
  }
1381
-
1382
1606
  throw Error(`Error fetching payload with slot=${slot} root=${rootHex} after ${i - 1} attempts.`);
1383
1607
  }
1384
1608
 
@@ -1483,7 +1707,7 @@ export class BlockInputSync {
1483
1707
 
1484
1708
  // no more peer with needed columns to try, throw error
1485
1709
  const message = `Error fetching UnknownBlockRoot slot=${slot} root=${rootHex} after ${i}: cannot find peer with needed columns=${prettyPrintIndices(Array.from(pendingColumns))}`;
1486
- this.metrics?.blockInputSync.fetchTimeSec.observe(
1710
+ this.metrics?.blockInputSync.fetchTime.observe(
1487
1711
  {result: FetchResult.FailureTriedAllPeers},
1488
1712
  Date.now() / 1000 - fetchStartSec
1489
1713
  );
@@ -1563,7 +1787,11 @@ export class BlockInputSync {
1563
1787
  this.peerBalancer.onRequestCompleted(peerId);
1564
1788
  }
1565
1789
 
1566
- this.pendingBlocks.set(getBlockInputSyncCacheItemRootHex(cacheItem), cacheItem);
1790
+ const cacheItemRootHex = getBlockInputSyncCacheItemRootHex(cacheItem);
1791
+ // pruning may have dropped it mid-fetch
1792
+ if (this.pendingBlocks.has(cacheItemRootHex)) {
1793
+ this.pendingBlocks.set(cacheItemRootHex, cacheItem);
1794
+ }
1567
1795
 
1568
1796
  if (cacheItem.status === PendingBlockInputStatus.downloaded) {
1569
1797
  // download was successful, no need to go with another peer, return
@@ -1572,7 +1800,7 @@ export class BlockInputSync {
1572
1800
  : this.chain.forkChoice.hasBlockHex(cacheItem.blockInput.parentRootHex)
1573
1801
  ? FetchResult.SuccessResolved
1574
1802
  : FetchResult.SuccessMissingParent;
1575
- this.metrics?.blockInputSync.fetchTimeSec.observe({result}, Date.now() / 1000 - fetchStartSec);
1803
+ this.metrics?.blockInputSync.fetchTime.observe({result}, Date.now() / 1000 - fetchStartSec);
1576
1804
  this.metrics?.blockInputSync.fetchPeers.set({result}, i);
1577
1805
  return cacheItem;
1578
1806
  }
@@ -1606,7 +1834,7 @@ export class BlockInputSync {
1606
1834
  }
1607
1835
  }
1608
1836
 
1609
- this.metrics?.blockInputSync.fetchTimeSec.observe(
1837
+ this.metrics?.blockInputSync.fetchTime.observe(
1610
1838
  {result: FetchResult.FailureMaxAttempts},
1611
1839
  Date.now() / 1000 - fetchStartSec
1612
1840
  );
@@ -10,12 +10,3 @@ export function shuffle<T>(arr: T[]): T[] {
10
10
  }
11
11
  return _arr;
12
12
  }
13
-
14
- /**
15
- * Return one random item from array
16
- */
17
- export function shuffleOne<T>(arr: T[]): T | undefined {
18
- if (arr.length === 0) return undefined;
19
-
20
- return arr[Math.floor(Math.random() * arr.length)];
21
- }
@@ -1,6 +1,7 @@
1
1
  import {BitArray, deserializeUint8ArrayBitListFromBytes} from "@chainsafe/ssz";
2
2
  import {ChainForkConfig} from "@lodestar/config";
3
3
  import {
4
+ BYTES_PER_CELL,
4
5
  BYTES_PER_FIELD_ELEMENT,
5
6
  FIELD_ELEMENTS_PER_BLOB,
6
7
  ForkName,
@@ -551,6 +552,23 @@ export function getBeaconBlockRootFromDataColumnSidecarSerialized(data: Uint8Arr
551
552
  return "0x" + blockRootBuf.toString("hex");
552
553
  }
553
554
 
555
+ // beaconBlockRoot is the last fixed field in the Gloas layout
556
+ const DATA_COLUMN_SIDECAR_GLOAS_FIXED_SIZE = BEACON_BLOCK_ROOT_POSITION_IN_GLOAS_DATA_COLUMN_SIDECAR + ROOT_SIZE; // 56 bytes
557
+ const KZG_PROOF_SIZE = 48; // Bytes48
558
+ const DATA_COLUMN_SIDECAR_GLOAS_PER_BLOB_SIZE = BYTES_PER_CELL + KZG_PROOF_SIZE; // 2048 + 48 = 2096 bytes
559
+
560
+ /**
561
+ * Gloas sidecar size bound uses the largest blob limit across the entire schedule, including future entries.
562
+ * https://github.com/ethereum/consensus-specs/pull/5613
563
+ */
564
+ export function computeMaxGloasDataColumnSidecarSize(config: ChainForkConfig): number {
565
+ const maxBlobs = config.BLOB_SCHEDULE.reduce(
566
+ (max, entry) => Math.max(max, entry.MAX_BLOBS_PER_BLOCK),
567
+ config.MAX_BLOBS_PER_BLOCK_ELECTRA
568
+ );
569
+ return DATA_COLUMN_SIDECAR_GLOAS_FIXED_SIZE + maxBlobs * DATA_COLUMN_SIDECAR_GLOAS_PER_BLOB_SIZE;
570
+ }
571
+
554
572
  /**
555
573
  * SignedExecutionPayloadEnvelope SSZ Layout:
556
574
  * ├─ 4 bytes: message offset (points to byte 100)
@@ -1,20 +0,0 @@
1
- import { CheckpointWithHex } from "@lodestar/fork-choice";
2
- import { Logger } from "@lodestar/logger";
3
- import { IBeaconDb } from "../../../db/interface.js";
4
- import { IBeaconChain } from "../../interface.js";
5
- /**
6
- * Backfill sync relies on verified connected ranges (which are represented as key,value
7
- * with a verified jump from a key back to value). Since the node could have progressed
8
- * ahead from, we need to save the forward progress of this node as another backfill
9
- * range entry, that backfill sync will use to jump back if this node is restarted
10
- * for any reason.
11
- * The current backfill has its own backfill entry from anchor slot to last backfilled
12
- * slot. And this would create the entry from the current finalized slot to the anchor
13
- * slot.
14
- */
15
- export declare function updateBackfillRange({ chain, db, logger }: {
16
- chain: IBeaconChain;
17
- db: IBeaconDb;
18
- logger: Logger;
19
- }, finalized: CheckpointWithHex): Promise<void>;
20
- //# sourceMappingURL=updateBackfillRange.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"updateBackfillRange.d.ts","sourceRoot":"","sources":["../../../../src/chain/archiveStore/utils/updateBackfillRange.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,iBAAiB,EAAC,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAC,MAAM,EAAC,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAC,SAAS,EAAC,MAAM,0BAA0B,CAAC;AACnD,OAAO,EAAC,YAAY,EAAC,MAAM,oBAAoB,CAAC;AAEhD;;;;;;;;;GASG;AACH,wBAAsB,mBAAmB,CACvC,EAAC,KAAK,EAAE,EAAE,EAAE,MAAM,EAAC,EAAE;IAAC,KAAK,EAAE,YAAY,CAAC;IAAC,EAAE,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAC,EACzE,SAAS,EAAE,iBAAiB,GAC3B,OAAO,CAAC,IAAI,CAAC,CA+Bf"}
@@ -1,40 +0,0 @@
1
- /**
2
- * Backfill sync relies on verified connected ranges (which are represented as key,value
3
- * with a verified jump from a key back to value). Since the node could have progressed
4
- * ahead from, we need to save the forward progress of this node as another backfill
5
- * range entry, that backfill sync will use to jump back if this node is restarted
6
- * for any reason.
7
- * The current backfill has its own backfill entry from anchor slot to last backfilled
8
- * slot. And this would create the entry from the current finalized slot to the anchor
9
- * slot.
10
- */
11
- export async function updateBackfillRange({ chain, db, logger }, finalized) {
12
- try {
13
- // Mark the sequence in backfill db from finalized block's slot till anchor slot as
14
- // filled.
15
- const finalizedBlockFC = chain.forkChoice.getBlockHexDefaultStatus(finalized.rootHex);
16
- if (finalizedBlockFC && finalizedBlockFC.slot > chain.anchorStateLatestBlockSlot) {
17
- await db.backfilledRanges.put(finalizedBlockFC.slot, chain.anchorStateLatestBlockSlot);
18
- // Clear previously marked sequence till anchorStateLatestBlockSlot, without
19
- // touching backfill sync process sequence which are at
20
- // <=anchorStateLatestBlockSlot i.e. clear >anchorStateLatestBlockSlot
21
- // and < currentSlot
22
- const filteredSeqs = await db.backfilledRanges.entries({
23
- gt: chain.anchorStateLatestBlockSlot,
24
- lt: finalizedBlockFC.slot,
25
- });
26
- logger.debug("updated backfilledRanges", {
27
- key: finalizedBlockFC.slot,
28
- value: chain.anchorStateLatestBlockSlot,
29
- });
30
- if (filteredSeqs.length > 0) {
31
- await db.backfilledRanges.batchDelete(filteredSeqs.map((entry) => entry.key));
32
- logger.debug(`Forward Sync - cleaned up backfilledRanges between ${finalizedBlockFC.slot},${chain.anchorStateLatestBlockSlot}`, { seqs: JSON.stringify(filteredSeqs) });
33
- }
34
- }
35
- }
36
- catch (e) {
37
- logger.error("Error updating backfilledRanges on finalization", { epoch: finalized.epoch }, e);
38
- }
39
- }
40
- //# sourceMappingURL=updateBackfillRange.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"updateBackfillRange.js","sourceRoot":"","sources":["../../../../src/chain/archiveStore/utils/updateBackfillRange.ts"],"names":[],"mappings":"AAKA;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,EAAC,KAAK,EAAE,EAAE,EAAE,MAAM,EAAuD,EACzE,SAA4B;IAE5B,IAAI,CAAC;QACH,mFAAmF;QACnF,UAAU;QACV,MAAM,gBAAgB,GAAG,KAAK,CAAC,UAAU,CAAC,wBAAwB,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACtF,IAAI,gBAAgB,IAAI,gBAAgB,CAAC,IAAI,GAAG,KAAK,CAAC,0BAA0B,EAAE,CAAC;YACjF,MAAM,EAAE,CAAC,gBAAgB,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,0BAA0B,CAAC,CAAC;YAEvF,4EAA4E;YAC5E,uDAAuD;YACvD,sEAAsE;YACtE,oBAAoB;YACpB,MAAM,YAAY,GAAG,MAAM,EAAE,CAAC,gBAAgB,CAAC,OAAO,CAAC;gBACrD,EAAE,EAAE,KAAK,CAAC,0BAA0B;gBACpC,EAAE,EAAE,gBAAgB,CAAC,IAAI;aAC1B,CAAC,CAAC;YACH,MAAM,CAAC,KAAK,CAAC,0BAA0B,EAAE;gBACvC,GAAG,EAAE,gBAAgB,CAAC,IAAI;gBAC1B,KAAK,EAAE,KAAK,CAAC,0BAA0B;aACxC,CAAC,CAAC;YACH,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC5B,MAAM,EAAE,CAAC,gBAAgB,CAAC,WAAW,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;gBAC9E,MAAM,CAAC,KAAK,CACV,sDAAsD,gBAAgB,CAAC,IAAI,IAAI,KAAK,CAAC,0BAA0B,EAAE,EACjH,EAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,EAAC,CACrC,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,CAAC,KAAK,CAAC,iDAAiD,EAAE,EAAC,KAAK,EAAE,SAAS,CAAC,KAAK,EAAC,EAAE,CAAU,CAAC,CAAC;IACxG,CAAC;AACH,CAAC"}
@@ -1,18 +0,0 @@
1
- import { ChainForkConfig } from "@lodestar/config";
2
- import { DatabaseController, Repository } from "@lodestar/db";
3
- import { Slot } from "@lodestar/types";
4
- /**
5
- * Slot to slot ranges that ensure that block range is fully backfilled
6
- *
7
- * If node starts backfilling at slots 1000, and backfills to 800, there will be an entry
8
- * 1000 -> 800
9
- *
10
- * When the node is backfilling if it starts at 1200 and backfills to 1000, it will find this sequence and,
11
- * jump directly to 800 and delete the key 1000.
12
- */
13
- export declare class BackfilledRanges extends Repository<Slot, Slot> {
14
- constructor(config: ChainForkConfig, db: DatabaseController<Uint8Array, Uint8Array>);
15
- decodeKey(data: Buffer): number;
16
- getId(_value: Slot): number;
17
- }
18
- //# sourceMappingURL=backfilledRanges.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"backfilledRanges.d.ts","sourceRoot":"","sources":["../../../src/db/repositories/backfilledRanges.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,eAAe,EAAC,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAC,kBAAkB,EAAE,UAAU,EAAC,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAC,IAAI,EAAM,MAAM,iBAAiB,CAAC;AAI1C;;;;;;;;GAQG;AACH,qBAAa,gBAAiB,SAAQ,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC;IAC1D,YAAY,MAAM,EAAE,eAAe,EAAE,EAAE,EAAE,kBAAkB,CAAC,UAAU,EAAE,UAAU,CAAC,EAGlF;IAED,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9B;IAED,KAAK,CAAC,MAAM,EAAE,IAAI,GAAG,MAAM,CAE1B;CACF"}
@@ -1,26 +0,0 @@
1
- import { Repository } from "@lodestar/db";
2
- import { ssz } from "@lodestar/types";
3
- import { bytesToInt } from "@lodestar/utils";
4
- import { Bucket, getBucketNameByValue } from "../buckets.js";
5
- /**
6
- * Slot to slot ranges that ensure that block range is fully backfilled
7
- *
8
- * If node starts backfilling at slots 1000, and backfills to 800, there will be an entry
9
- * 1000 -> 800
10
- *
11
- * When the node is backfilling if it starts at 1200 and backfills to 1000, it will find this sequence and,
12
- * jump directly to 800 and delete the key 1000.
13
- */
14
- export class BackfilledRanges extends Repository {
15
- constructor(config, db) {
16
- const bucket = Bucket.backfilled_ranges;
17
- super(config, db, bucket, ssz.Slot, getBucketNameByValue(bucket));
18
- }
19
- decodeKey(data) {
20
- return bytesToInt(super.decodeKey(data), "be");
21
- }
22
- getId(_value) {
23
- throw new Error("Cannot get the db key from slot");
24
- }
25
- }
26
- //# sourceMappingURL=backfilledRanges.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"backfilledRanges.js","sourceRoot":"","sources":["../../../src/db/repositories/backfilledRanges.ts"],"names":[],"mappings":"AACA,OAAO,EAAqB,UAAU,EAAC,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAO,GAAG,EAAC,MAAM,iBAAiB,CAAC;AAC1C,OAAO,EAAC,UAAU,EAAC,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAC,MAAM,EAAE,oBAAoB,EAAC,MAAM,eAAe,CAAC;AAE3D;;;;;;;;GAQG;AACH,MAAM,OAAO,gBAAiB,SAAQ,UAAsB;IAC1D,YAAY,MAAuB,EAAE,EAA8C;QACjF,MAAM,MAAM,GAAG,MAAM,CAAC,iBAAiB,CAAC;QACxC,KAAK,CAAC,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,IAAI,EAAE,oBAAoB,CAAC,MAAM,CAAC,CAAC,CAAC;IACpE,CAAC;IAED,SAAS,CAAC,IAAY;QACpB,OAAO,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,IAAI,CAA0B,EAAE,IAAI,CAAC,CAAC;IAC1E,CAAC;IAED,KAAK,CAAC,MAAY;QAChB,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACrD,CAAC;CACF"}