@lodestar/beacon-node 1.49.0-dev.4d35c8b82e → 1.49.0-dev.52a50304a4

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 (205) 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 +4 -0
  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/index.js +2 -2
  20. package/lib/chain/blocks/index.js.map +1 -1
  21. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +1 -1
  22. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
  23. package/lib/chain/emitter.d.ts +10 -0
  24. package/lib/chain/emitter.d.ts.map +1 -1
  25. package/lib/chain/emitter.js +4 -0
  26. package/lib/chain/emitter.js.map +1 -1
  27. package/lib/chain/errors/attesterSlashingError.d.ts +4 -1
  28. package/lib/chain/errors/attesterSlashingError.d.ts.map +1 -1
  29. package/lib/chain/errors/attesterSlashingError.js +1 -0
  30. package/lib/chain/errors/attesterSlashingError.js.map +1 -1
  31. package/lib/chain/errors/payloadAttestation.d.ts +4 -0
  32. package/lib/chain/errors/payloadAttestation.d.ts.map +1 -1
  33. package/lib/chain/errors/payloadAttestation.js +1 -0
  34. package/lib/chain/errors/payloadAttestation.js.map +1 -1
  35. package/lib/chain/errors/proposerSlashingError.d.ts +4 -1
  36. package/lib/chain/errors/proposerSlashingError.d.ts.map +1 -1
  37. package/lib/chain/errors/proposerSlashingError.js +1 -0
  38. package/lib/chain/errors/proposerSlashingError.js.map +1 -1
  39. package/lib/chain/options.d.ts +0 -4
  40. package/lib/chain/options.d.ts.map +1 -1
  41. package/lib/chain/options.js +0 -1
  42. package/lib/chain/options.js.map +1 -1
  43. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  44. package/lib/chain/produceBlock/produceBlockBody.js +6 -6
  45. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  46. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +2 -1
  47. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  48. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +3 -2
  49. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  50. package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
  51. package/lib/chain/validation/attesterSlashing.js +1 -2
  52. package/lib/chain/validation/attesterSlashing.js.map +1 -1
  53. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
  54. package/lib/chain/validation/payloadAttestationMessage.js +8 -1
  55. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
  56. package/lib/chain/validation/proposerSlashing.js +1 -2
  57. package/lib/chain/validation/proposerSlashing.js.map +1 -1
  58. package/lib/chain/validatorMonitor.d.ts.map +1 -1
  59. package/lib/chain/validatorMonitor.js +2 -2
  60. package/lib/chain/validatorMonitor.js.map +1 -1
  61. package/lib/db/beacon.d.ts +1 -2
  62. package/lib/db/beacon.d.ts.map +1 -1
  63. package/lib/db/beacon.js +1 -3
  64. package/lib/db/beacon.js.map +1 -1
  65. package/lib/db/buckets.d.ts +0 -1
  66. package/lib/db/buckets.d.ts.map +1 -1
  67. package/lib/db/buckets.js +1 -1
  68. package/lib/db/buckets.js.map +1 -1
  69. package/lib/db/interface.d.ts +1 -2
  70. package/lib/db/interface.d.ts.map +1 -1
  71. package/lib/db/repositories/blockArchive.d.ts +5 -0
  72. package/lib/db/repositories/blockArchive.d.ts.map +1 -1
  73. package/lib/db/repositories/blockArchive.js +36 -1
  74. package/lib/db/repositories/blockArchive.js.map +1 -1
  75. package/lib/db/repositories/blockArchiveIndex.d.ts +2 -2
  76. package/lib/db/repositories/blockArchiveIndex.d.ts.map +1 -1
  77. package/lib/db/repositories/index.d.ts +0 -1
  78. package/lib/db/repositories/index.d.ts.map +1 -1
  79. package/lib/db/repositories/index.js +0 -1
  80. package/lib/db/repositories/index.js.map +1 -1
  81. package/lib/metrics/metrics/lodestar.d.ts +19 -14
  82. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  83. package/lib/metrics/metrics/lodestar.js +38 -24
  84. package/lib/metrics/metrics/lodestar.js.map +1 -1
  85. package/lib/network/gossip/encoding.d.ts +1 -2
  86. package/lib/network/gossip/encoding.d.ts.map +1 -1
  87. package/lib/network/gossip/encoding.js +5 -10
  88. package/lib/network/gossip/encoding.js.map +1 -1
  89. package/lib/network/gossip/gossipsub.d.ts.map +1 -1
  90. package/lib/network/gossip/gossipsub.js +16 -1
  91. package/lib/network/gossip/gossipsub.js.map +1 -1
  92. package/lib/network/gossip/topic.d.ts +9 -6
  93. package/lib/network/gossip/topic.d.ts.map +1 -1
  94. package/lib/network/gossip/topic.js +23 -8
  95. package/lib/network/gossip/topic.js.map +1 -1
  96. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  97. package/lib/network/processor/gossipHandlers.js +16 -5
  98. package/lib/network/processor/gossipHandlers.js.map +1 -1
  99. package/lib/network/processor/gossipValidatorFn.d.ts +2 -0
  100. package/lib/network/processor/gossipValidatorFn.d.ts.map +1 -1
  101. package/lib/network/processor/gossipValidatorFn.js +88 -7
  102. package/lib/network/processor/gossipValidatorFn.js.map +1 -1
  103. package/lib/network/processor/index.d.ts +6 -2
  104. package/lib/network/processor/index.d.ts.map +1 -1
  105. package/lib/network/processor/index.js +62 -24
  106. package/lib/network/processor/index.js.map +1 -1
  107. package/lib/network/reqresp/protocols.d.ts.map +1 -1
  108. package/lib/network/reqresp/protocols.js +19 -5
  109. package/lib/network/reqresp/protocols.js.map +1 -1
  110. package/lib/node/nodejs.d.ts +2 -7
  111. package/lib/node/nodejs.d.ts.map +1 -1
  112. package/lib/node/nodejs.js +2 -22
  113. package/lib/node/nodejs.js.map +1 -1
  114. package/lib/sync/interface.d.ts +1 -2
  115. package/lib/sync/interface.d.ts.map +1 -1
  116. package/lib/sync/options.d.ts +0 -6
  117. package/lib/sync/options.d.ts.map +1 -1
  118. package/lib/sync/options.js +0 -2
  119. package/lib/sync/options.js.map +1 -1
  120. package/lib/sync/types.d.ts +39 -0
  121. package/lib/sync/types.d.ts.map +1 -1
  122. package/lib/sync/types.js +42 -0
  123. package/lib/sync/types.js.map +1 -1
  124. package/lib/sync/unknownBlock.d.ts +20 -0
  125. package/lib/sync/unknownBlock.d.ts.map +1 -1
  126. package/lib/sync/unknownBlock.js +190 -13
  127. package/lib/sync/unknownBlock.js.map +1 -1
  128. package/lib/util/shuffle.d.ts +0 -4
  129. package/lib/util/shuffle.d.ts.map +1 -1
  130. package/lib/util/shuffle.js +0 -8
  131. package/lib/util/shuffle.js.map +1 -1
  132. package/lib/util/sszBytes.d.ts +5 -0
  133. package/lib/util/sszBytes.d.ts.map +1 -1
  134. package/lib/util/sszBytes.js +13 -1
  135. package/lib/util/sszBytes.js.map +1 -1
  136. package/package.json +14 -14
  137. package/src/api/impl/beacon/blocks/index.ts +2 -2
  138. package/src/api/impl/beacon/pool/index.ts +6 -2
  139. package/src/api/impl/validator/index.ts +9 -7
  140. package/src/chain/archiveStore/archiveStore.ts +0 -6
  141. package/src/chain/archiveStore/historicalState/metrics.ts +4 -0
  142. package/src/chain/archiveStore/utils/pruneHistory.ts +14 -4
  143. package/src/chain/blocks/index.ts +2 -2
  144. package/src/chain/blocks/payloadEnvelopeInput/types.ts +1 -1
  145. package/src/chain/emitter.ts +7 -2
  146. package/src/chain/errors/attesterSlashingError.ts +3 -1
  147. package/src/chain/errors/payloadAttestation.ts +2 -0
  148. package/src/chain/errors/proposerSlashingError.ts +3 -1
  149. package/src/chain/options.ts +0 -5
  150. package/src/chain/produceBlock/produceBlockBody.ts +17 -6
  151. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +3 -2
  152. package/src/chain/validation/attesterSlashing.ts +1 -2
  153. package/src/chain/validation/payloadAttestationMessage.ts +9 -0
  154. package/src/chain/validation/proposerSlashing.ts +1 -2
  155. package/src/chain/validatorMonitor.ts +12 -2
  156. package/src/db/beacon.ts +0 -5
  157. package/src/db/buckets.ts +1 -1
  158. package/src/db/interface.ts +0 -3
  159. package/src/db/repositories/blockArchive.ts +38 -1
  160. package/src/db/repositories/index.ts +0 -1
  161. package/src/metrics/metrics/lodestar.ts +46 -28
  162. package/src/network/gossip/encoding.ts +5 -8
  163. package/src/network/gossip/gossipsub.ts +19 -2
  164. package/src/network/gossip/topic.ts +25 -7
  165. package/src/network/processor/gossipHandlers.ts +18 -5
  166. package/src/network/processor/gossipValidatorFn.ts +111 -7
  167. package/src/network/processor/index.ts +81 -24
  168. package/src/network/reqresp/protocols.ts +31 -6
  169. package/src/node/nodejs.ts +0 -27
  170. package/src/sync/interface.ts +1 -2
  171. package/src/sync/options.ts +0 -8
  172. package/src/sync/types.ts +44 -3
  173. package/src/sync/unknownBlock.ts +213 -13
  174. package/src/util/shuffle.ts +0 -9
  175. package/src/util/sszBytes.ts +18 -0
  176. package/lib/chain/archiveStore/utils/updateBackfillRange.d.ts +0 -20
  177. package/lib/chain/archiveStore/utils/updateBackfillRange.d.ts.map +0 -1
  178. package/lib/chain/archiveStore/utils/updateBackfillRange.js +0 -40
  179. package/lib/chain/archiveStore/utils/updateBackfillRange.js.map +0 -1
  180. package/lib/db/repositories/backfilledRanges.d.ts +0 -18
  181. package/lib/db/repositories/backfilledRanges.d.ts.map +0 -1
  182. package/lib/db/repositories/backfilledRanges.js +0 -26
  183. package/lib/db/repositories/backfilledRanges.js.map +0 -1
  184. package/lib/sync/backfill/backfill.d.ts +0 -169
  185. package/lib/sync/backfill/backfill.d.ts.map +0 -1
  186. package/lib/sync/backfill/backfill.js +0 -686
  187. package/lib/sync/backfill/backfill.js.map +0 -1
  188. package/lib/sync/backfill/errors.d.ts +0 -30
  189. package/lib/sync/backfill/errors.d.ts.map +0 -1
  190. package/lib/sync/backfill/errors.js +0 -15
  191. package/lib/sync/backfill/errors.js.map +0 -1
  192. package/lib/sync/backfill/index.d.ts +0 -2
  193. package/lib/sync/backfill/index.d.ts.map +0 -1
  194. package/lib/sync/backfill/index.js +0 -2
  195. package/lib/sync/backfill/index.js.map +0 -1
  196. package/lib/sync/backfill/verify.d.ts +0 -18
  197. package/lib/sync/backfill/verify.d.ts.map +0 -1
  198. package/lib/sync/backfill/verify.js +0 -36
  199. package/lib/sync/backfill/verify.js.map +0 -1
  200. package/src/chain/archiveStore/utils/updateBackfillRange.ts +0 -50
  201. package/src/db/repositories/backfilledRanges.ts +0 -29
  202. package/src/sync/backfill/backfill.ts +0 -916
  203. package/src/sync/backfill/errors.ts +0 -23
  204. package/src/sync/backfill/index.ts +0 -1
  205. package/src/sync/backfill/verify.ts +0 -58
@@ -8,7 +8,6 @@ import {BeaconConfig} from "@lodestar/config";
8
8
  import type {LoggerNode} from "@lodestar/logger/node";
9
9
  import {ZERO_HASH_HEX} from "@lodestar/params";
10
10
  import {IBeaconStateView, isStatePostBellatrix, isStatePostGloas} from "@lodestar/state-transition";
11
- import {phase0} from "@lodestar/types";
12
11
  import {sleep, toRootHex} from "@lodestar/utils";
13
12
  import {ProcessShutdownCallback} from "@lodestar/validator";
14
13
  import {BeaconRestApiServer, getApi} from "../api/index.js";
@@ -19,7 +18,6 @@ import {initializeExecutionBuilder, initializeExecutionEngine} from "../executio
19
18
  import {HttpMetricsServer, Metrics, createMetrics, getHttpMetricsServer} from "../metrics/index.js";
20
19
  import {MonitoringService} from "../monitoring/index.js";
21
20
  import {Network, getReqRespHandlers} from "../network/index.js";
22
- import {BackfillSync} from "../sync/backfill/index.js";
23
21
  import {BeaconSync, IBeaconSync} from "../sync/index.js";
24
22
  import {Clock} from "../util/clock.js";
25
23
  import {startDeferredVoluntaryExitPublisher} from "./deferredVoluntaryExitPublisher.js";
@@ -38,7 +36,6 @@ export type BeaconNodeModules = {
38
36
  chain: IBeaconChain;
39
37
  api: BeaconApiMethods;
40
38
  sync: IBeaconSync;
41
- backfillSync: BackfillSync | null;
42
39
  metricsServer: HttpMetricsServer | null;
43
40
  monitoring: MonitoringService | null;
44
41
  restApi?: BeaconRestApiServer;
@@ -58,7 +55,6 @@ export type BeaconNodeInitModules = {
58
55
  peerStoreDir?: string;
59
56
  anchorState: IBeaconStateView;
60
57
  isAnchorStateFinalized: boolean;
61
- wsCheckpoint?: phase0.Checkpoint;
62
58
  metricsRegistries?: Registry[];
63
59
  };
64
60
 
@@ -70,7 +66,6 @@ export enum BeaconNodeStatus {
70
66
 
71
67
  enum LoggerModule {
72
68
  api = "api",
73
- backfill = "backfill",
74
69
  chain = "chain",
75
70
  execution = "execution",
76
71
  metrics = "metrics",
@@ -105,7 +100,6 @@ export class BeaconNode {
105
100
  api: BeaconApiMethods;
106
101
  restApi?: BeaconRestApiServer;
107
102
  sync: IBeaconSync;
108
- backfillSync: BackfillSync | null;
109
103
 
110
104
  status: BeaconNodeStatus;
111
105
  private controller?: AbortController;
@@ -123,7 +117,6 @@ export class BeaconNode {
123
117
  api,
124
118
  restApi,
125
119
  sync,
126
- backfillSync,
127
120
  controller,
128
121
  }: BeaconNodeModules) {
129
122
  this.opts = opts;
@@ -138,7 +131,6 @@ export class BeaconNode {
138
131
  this.restApi = restApi;
139
132
  this.network = network;
140
133
  this.sync = sync;
141
- this.backfillSync = backfillSync;
142
134
  this.controller = controller;
143
135
 
144
136
  this.status = BeaconNodeStatus.started;
@@ -161,7 +153,6 @@ export class BeaconNode {
161
153
  peerStoreDir,
162
154
  anchorState,
163
155
  isAnchorStateFinalized,
164
- wsCheckpoint,
165
156
  metricsRegistries = [],
166
157
  }: BeaconNodeInitModules): Promise<T> {
167
158
  if (hasher.name !== "hashtree") {
@@ -295,25 +286,9 @@ export class BeaconNode {
295
286
  chain,
296
287
  metrics,
297
288
  network,
298
- wsCheckpoint,
299
289
  logger: logger.child({module: LoggerModule.sync}),
300
290
  });
301
291
 
302
- const backfillSync =
303
- opts.sync.backfillBatchSize > 0
304
- ? await BackfillSync.init(opts.sync, {
305
- config,
306
- db,
307
- chain,
308
- metrics,
309
- network,
310
- wsCheckpoint,
311
- anchorState,
312
- logger: logger.child({module: LoggerModule.backfill}),
313
- signal,
314
- })
315
- : null;
316
-
317
292
  const api = getApi(opts.api, {
318
293
  config,
319
294
  logger: logger.child({module: LoggerModule.api}),
@@ -361,7 +336,6 @@ export class BeaconNode {
361
336
  api,
362
337
  restApi,
363
338
  sync,
364
- backfillSync,
365
339
  controller,
366
340
  }) as T;
367
341
  }
@@ -373,7 +347,6 @@ export class BeaconNode {
373
347
  if (this.status === BeaconNodeStatus.started) {
374
348
  this.status = BeaconNodeStatus.closing;
375
349
  this.sync.close();
376
- this.backfillSync?.close();
377
350
  if (this.restApi) await this.restApi.close();
378
351
  await this.network.close();
379
352
  if (this.metricsServer) await this.metricsServer.close();
@@ -1,6 +1,6 @@
1
1
  import {routes} from "@lodestar/api";
2
2
  import {BeaconConfig} from "@lodestar/config";
3
- import {Slot, phase0} from "@lodestar/types";
3
+ import {Slot} from "@lodestar/types";
4
4
  import {Logger} from "@lodestar/utils";
5
5
  import {IBeaconChain} from "../chain/index.js";
6
6
  import {IBeaconDb} from "../db/index.js";
@@ -51,5 +51,4 @@ export interface SyncModules {
51
51
  metrics: Metrics | null;
52
52
  logger: Logger;
53
53
  chain: IBeaconChain;
54
- wsCheckpoint?: phase0.Checkpoint;
55
54
  }
@@ -16,12 +16,6 @@ export type SyncOptions = {
16
16
  disableRangeSync?: boolean;
17
17
  /** USE FOR TESTING ONLY. Disable unknown block sync completely */
18
18
  disableBlockInputSync?: boolean;
19
- /**
20
- * The batch size of slots for backfill sync can attempt to sync/process before yielding
21
- * to sync loop. This number can be increased or decreased to make a suitable resource
22
- * allocation to backfill sync. The default of 0 would mean backfill sync will be skipped
23
- */
24
- backfillBatchSize: number;
25
19
  /** For testing only, MAX_PENDING_BLOCKS by default */
26
20
  maxPendingBlocks?: number;
27
21
 
@@ -39,7 +33,5 @@ export type SyncOptions = {
39
33
  export const defaultSyncOptions: SyncOptions = {
40
34
  isSingleNode: false,
41
35
  disableProcessAsChainSegment: false,
42
- /** By default skip the backfill sync */
43
- backfillBatchSize: 0,
44
36
  slotImportTolerance: SLOTS_PER_EPOCH,
45
37
  };
package/src/sync/types.ts CHANGED
@@ -23,12 +23,54 @@ export enum PendingBlockType {
23
23
  * Payload analog of UNKNOWN_BLOCK_ROOT: we have a beacon block root but not its execution payload envelope.
24
24
  */
25
25
  UNKNOWN_PAYLOAD_BLOCK_ROOT = "unknown_payload_block_root",
26
+ /**
27
+ * Same as UNKNOWN_PAYLOAD_BLOCK_ROOT, but the trigger also carries the payload's slot
28
+ */
29
+ UNKNOWN_PAYLOAD_BLOCK_ROOT_SLOT = "unknown_payload_block_root_slot",
30
+ /**
31
+ * Same as UNKNOWN_PAYLOAD_BLOCK_ROOT_SLOT for the current slot
32
+ */
33
+ DEFERRED_PAYLOAD_BLOCK_ROOT = "deferred_payload_block_root",
26
34
  /**
27
35
  * Payload analog of INCOMPLETE_BLOCK_INPUT: we have a partial payload input that did not complete in time.
28
36
  */
29
37
  INCOMPLETE_PAYLOAD_ENVELOPE = "incomplete_payload_envelope",
30
38
  }
31
39
 
40
+ export enum DownloadResult {
41
+ /** payload fully downloaded, ready to process */
42
+ Resolved = "resolved",
43
+ /** payload fully downloaded, but it was already imported (via gossip) while we were downloading */
44
+ Late = "late",
45
+ /** envelope downloaded, held until the block lands in fork choice */
46
+ WaitingForBlock = "waiting_for_block",
47
+ /** fetch failed, the pending entry is retained for retry */
48
+ Failed = "failed",
49
+ }
50
+
51
+ export enum FetchResult {
52
+ SuccessResolved = "success_resolved",
53
+ SuccessMissingParent = "success_missing_parent",
54
+ SuccessLate = "success_late",
55
+ SuccessWaitingForBlock = "success_waiting_for_block",
56
+ FailureTriedAllPeers = "failure_tried_all_peers",
57
+ FailureMaxAttempts = "failure_max_attempts",
58
+ }
59
+
60
+ /**
61
+ * Outcome of a slot's deferred optimistic payload searches, recorded once when its poll loop ends.
62
+ */
63
+ export enum DeferredPayloadResult {
64
+ /** gossip delivered every watched payload before PAYLOAD_DUE, no search was needed */
65
+ ImportedBeforeSearch = "imported_before_search",
66
+ /** at least one was missing at PAYLOAD_DUE, we searched, and all were imported afterwards */
67
+ ImportedAfterSearch = "imported_after_search",
68
+ /** something was still not in fork choice when the slot ended */
69
+ Unresolved = "unresolved",
70
+ /** the slot had no optimistic search and no payload import at all, eg a skipped slot */
71
+ ResolvedNoRoot = "resolved_no_root",
72
+ }
73
+
32
74
  export enum PendingBlockInputStatus {
33
75
  pending = "pending",
34
76
  fetching = "fetching",
@@ -110,9 +152,8 @@ export type PendingPayloadInput = {
110
152
  export type PendingPayloadRootHex = {
111
153
  status: PendingPayloadInputStatus.pending | PendingPayloadInputStatus.fetching;
112
154
  rootHex: RootHex;
113
- // Trusted slot only (fork choice / validated data), may be missing until resolved. NOT the gossip
114
- // message slot from ChainEvent.unknownEnvelopeBlockRoot, which is untrusted and not necessarily the
115
- // payload/block slot. See BlockInputSync.resolvePayloadSlot.
155
+ // slot could be via fork choice or ChainEvent.unknownEnvelopeBlockRootSlot
156
+ // while ChainEvent.unknownEnvelopeBlockRoot does not provide one
116
157
  slot?: Slot;
117
158
  timeAddedSec: number;
118
159
  timeSyncedSec?: number;
@@ -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);
@@ -248,6 +264,33 @@ export class BlockInputSync {
248
264
  }
249
265
  };
250
266
 
267
+ private onUnknownEnvelopeBlockRootSlot = (data: ChainEventData[ChainEvent.unknownEnvelopeBlockRootSlot]): void => {
268
+ try {
269
+ if (data.slot === this.chain.clock.currentSlot) {
270
+ // we receive the optimistic search, the poll loop searches it at PAYLOAD_DUE or on its next
271
+ // tick. If that loop already returned - every root it watched was imported - this root waits
272
+ // for the next slot, where startPayloadPollAtSlot moves it to pendingPayloads. That is not the normal
273
+ // scenario, and in a forking condition it only delays the search of the extra root
274
+ const deferred = this.deferredPayloadRoots.get(data.rootHex);
275
+ if (deferred === undefined) {
276
+ this.deferredPayloadRoots.set(data.rootHex, {slot: data.slot, source: data.source, peer: data.peer});
277
+ } else if (deferred.peer === undefined) {
278
+ deferred.peer = data.peer;
279
+ }
280
+ return;
281
+ }
282
+
283
+ const isNewRoot = this.addByPayloadRootHex(data.rootHex, data.peer, data.slot);
284
+ if (isNewRoot) {
285
+ this.triggerUnknownBlockSearch();
286
+ this.metrics?.blockInputSync.requests.inc({type: PendingBlockType.UNKNOWN_PAYLOAD_BLOCK_ROOT_SLOT});
287
+ this.metrics?.blockInputSync.payloadSource.inc({source: data.source});
288
+ }
289
+ } catch (e) {
290
+ this.logger.debug("Error handling unknownEnvelopeBlockRootSlot event", {}, e as Error);
291
+ }
292
+ };
293
+
251
294
  private onIncompletePayloadEnvelope = (data: ChainEventData[ChainEvent.incompletePayloadEnvelope]): void => {
252
295
  try {
253
296
  this.addByPayloadInput(data.payloadInput, data.peer);
@@ -791,6 +834,122 @@ export class BlockInputSync {
791
834
  }
792
835
  }
793
836
 
837
+ /**
838
+ * Start this slot's payload poll: end the previous slot's loop, move roots it never got to
839
+ * into pendingPayloads, then poll from PAYLOAD_DUE to the end of the slot.
840
+ */
841
+ private startPayloadPollAtSlot = (slot: Slot): void => {
842
+ if (!isForkPostGloas(this.config.getForkName(slot))) {
843
+ return;
844
+ }
845
+ // end the previous slot's loop, wherever it is: its sleep is bound to this same controller
846
+ this.payloadPollAbortController?.abort();
847
+ this.payloadPollAbortController = new AbortController();
848
+ // entries from an earlier slot is not polled
849
+ for (const [rootHex, {slot: deferredSlot, source, peer}] of this.deferredPayloadRoots) {
850
+ if (deferredSlot < slot) {
851
+ if (!this.chain.forkChoice.hasPayloadHexUnsafe(rootHex)) {
852
+ this.addDeferredPayloadRoot(rootHex, deferredSlot, source, peer);
853
+ }
854
+ this.deferredPayloadRoots.delete(rootHex);
855
+ }
856
+ }
857
+ this.pollPayloadsAtSlot(slot, this.payloadPollAbortController.signal).catch((e) => {
858
+ if (!isErrorAborted(e)) {
859
+ this.logger.debug("Error polling payloads", {slot}, e as Error);
860
+ }
861
+ });
862
+ };
863
+
864
+ /**
865
+ * Poll unknown payloads of the current slot.
866
+ */
867
+ private async pollPayloadsAtSlot(slot: Slot, signal: AbortSignal): Promise<void> {
868
+ // fixed tick count so the loop cannot outlive its slot: for mainnet, it's 6 ticks
869
+ const tickCount = Math.floor(
870
+ (this.config.SLOT_DURATION_MS - this.config.getPayloadDueMs()) / PAYLOAD_POLL_INTERVAL_MS
871
+ );
872
+ // a root still missing on several ticks is searched on each of them, recorded once
873
+ const searchedRoots = new Set<RootHex>();
874
+ let polls = 0;
875
+
876
+ try {
877
+ await sleep(Math.max(0, this.config.getPayloadDueMs() - this.chain.clock.msFromSlot(slot)), signal);
878
+
879
+ for (polls = 0; polls < tickCount; polls++) {
880
+ let importedCount = 0;
881
+ for (const [rootHex, {slot: deferredSlot, source, peer}] of this.deferredPayloadRoots) {
882
+ if (this.chain.forkChoice.hasPayloadHexUnsafe(rootHex)) {
883
+ importedCount++;
884
+ continue;
885
+ }
886
+ // copy to the regular pendingPayloads so that we can search
887
+ this.addDeferredPayloadRoot(rootHex, deferredSlot, source, peer);
888
+ searchedRoots.add(rootHex);
889
+ }
890
+
891
+ // an empty deferredPayloadRoots means there is no optimistic search comes before PAYLOAD_DUE
892
+ // we have to poll until the payload of current slot is imported or slot end
893
+ if (this.deferredPayloadRoots.size > 0 && importedCount === this.deferredPayloadRoots.size) {
894
+ if (searchedRoots.size > 0) {
895
+ // the backup search was needed
896
+ this.metrics?.blockInputSync.deferredPayloadResult.inc({
897
+ result: DeferredPayloadResult.ImportedAfterSearch,
898
+ });
899
+ this.metrics?.blockInputSync.deferredPayloadPolls.observe(polls);
900
+ this.logger.verbose("Payload imported after unknown sync search", {
901
+ slot,
902
+ roots: Array.from(searchedRoots).join(","),
903
+ polls,
904
+ });
905
+ } else {
906
+ // this happens most of the time on devnet
907
+ // gossip delivered everything before PAYLOAD_DUE
908
+ this.metrics?.blockInputSync.deferredPayloadResult.inc({
909
+ result: DeferredPayloadResult.ImportedBeforeSearch,
910
+ });
911
+ }
912
+ return;
913
+ }
914
+
915
+ this.triggerUnknownBlockSearch();
916
+ if (polls < tickCount - 1) {
917
+ // no sleep after the last tick: the loop would otherwise end right at the slot boundary,
918
+ // where startPayloadPollAtSlot aborts it
919
+ await sleep(PAYLOAD_POLL_INTERVAL_MS, signal);
920
+ }
921
+ }
922
+
923
+ // reaching here means the early return never fired
924
+ if (this.deferredPayloadRoots.size > 0) {
925
+ this.metrics?.blockInputSync.deferredPayloadResult.inc({result: DeferredPayloadResult.Unresolved});
926
+ this.logger.debug("Deferred payloads still missing at end of slot", {
927
+ slot,
928
+ roots: Array.from(this.deferredPayloadRoots.keys()).join(","),
929
+ });
930
+ } else {
931
+ // no optimistic search and no payload import ended the loop, eg a skipped slot
932
+ this.metrics?.blockInputSync.deferredPayloadResult.inc({result: DeferredPayloadResult.ResolvedNoRoot});
933
+ this.logger.debug("No deferred payloads at slot", {
934
+ slot,
935
+ });
936
+ }
937
+ } catch (e) {
938
+ if (!isErrorAborted(e)) {
939
+ throw e;
940
+ }
941
+ this.logger.verbose("Payload poll aborted", {slot, polls, msIntoSlot: this.chain.clock.msFromSlot(slot)});
942
+ }
943
+ }
944
+
945
+ private addDeferredPayloadRoot(rootHex: RootHex, slot: Slot, source: BlockInputSource, peer?: PeerIdStr): void {
946
+ const isNewRoot = this.addByPayloadRootHex(rootHex, peer, slot);
947
+ if (isNewRoot) {
948
+ this.metrics?.blockInputSync.requests.inc({type: PendingBlockType.DEFERRED_PAYLOAD_BLOCK_ROOT});
949
+ this.metrics?.blockInputSync.payloadSource.inc({source});
950
+ }
951
+ }
952
+
794
953
  private async downloadBlock(block: BlockInputSyncCacheItem): Promise<void> {
795
954
  if (block.status !== PendingBlockInputStatus.pending) {
796
955
  return;
@@ -1125,15 +1284,25 @@ export class BlockInputSync {
1125
1284
  return;
1126
1285
  }
1127
1286
  this.pendingPayloads.set(resultRootHex, pendingPayload);
1287
+ const result = isPendingPayloadEnvelope(pendingPayload)
1288
+ ? DownloadResult.WaitingForBlock
1289
+ : this.chain.forkChoice.hasPayloadHexUnsafe(resultRootHex)
1290
+ ? DownloadResult.Late
1291
+ : DownloadResult.Resolved;
1292
+ this.metrics?.blockInputSync.downloadedPayloadsResult.inc({result});
1128
1293
 
1129
1294
  if (isPendingPayloadEnvelope(pendingPayload)) {
1130
1295
  await this.reconcilePayloadEnvelope(pendingPayload);
1131
1296
  } else if (pendingPayload.status === PendingPayloadInputStatus.downloaded) {
1297
+ this.metrics?.blockInputSync.elapsedTimeTillPayloadReceived.observe(
1298
+ Date.now() / 1000 - computeTimeAtSlot(this.config, pendingPayload.payloadInput.slot, this.chain.genesisTime)
1299
+ );
1132
1300
  await this.processPayload(pendingPayload);
1133
1301
  }
1134
1302
  return;
1135
1303
  }
1136
1304
 
1305
+ this.metrics?.blockInputSync.downloadedPayloadsResult.inc({result: DownloadResult.Failed});
1137
1306
  this.logger.debug("Ignoring unknown payload root after failed download", logCtx, res.err);
1138
1307
  if (!isPendingPayloadEnvelope(payload)) {
1139
1308
  payload.status = PendingPayloadInputStatus.pending;
@@ -1248,6 +1417,11 @@ export class BlockInputSync {
1248
1417
  : await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
1249
1418
  let envelope = payloadInput?.hasPayloadEnvelope() ? payloadInput.getPayloadEnvelope() : undefined;
1250
1419
 
1420
+ const fetchStartSec = Date.now() / 1000;
1421
+ if (typeof slot === "number") {
1422
+ this.metrics?.blockInputSync.payloadFetchBegin.observe(this.chain.clock.secFromSlot(slot, fetchStartSec));
1423
+ }
1424
+
1251
1425
  let i = 0;
1252
1426
  let deferredByRateLimit = false;
1253
1427
  while (i++ < this.getMaxDownloadAttempts()) {
@@ -1271,6 +1445,11 @@ export class BlockInputSync {
1271
1445
  pendingColumns.size > 0
1272
1446
  ? `cannot find peer with needed columns=${prettyPrintIndices(Array.from(pendingColumns))}`
1273
1447
  : "no peer available to download pending payload";
1448
+ this.metrics?.blockInputSync.payloadFetchTime.observe(
1449
+ {result: FetchResult.FailureTriedAllPeers},
1450
+ Date.now() / 1000 - fetchStartSec
1451
+ );
1452
+ this.metrics?.blockInputSync.payloadFetchPeers.set({result: FetchResult.FailureTriedAllPeers}, i);
1274
1453
  throw Error(`Error fetching payload by root slot=${slot} root=${rootHex} after ${i}: ${reason}`);
1275
1454
  }
1276
1455
 
@@ -1280,7 +1459,12 @@ export class BlockInputSync {
1280
1459
  try {
1281
1460
  if (!envelope) {
1282
1461
  envelope = await this.fetchExecutionPayloadEnvelope(peerId, blockRoot, rootHex);
1462
+ const slotWasUnknown = typeof slot !== "number";
1283
1463
  slot = envelope.message.payload.slotNumber;
1464
+ if (slotWasUnknown) {
1465
+ // we were not able to observe the time into slot when starting the fetch, do it now
1466
+ this.metrics?.blockInputSync.payloadFetchBegin.observe(this.chain.clock.secFromSlot(slot, fetchStartSec));
1467
+ }
1284
1468
  }
1285
1469
 
1286
1470
  payloadInput ??= await this.chain.seenPayloadEnvelopeInputCache.getOrReload(rootHex);
@@ -1289,6 +1473,11 @@ export class BlockInputSync {
1289
1473
  // envelope and wait for the block body; reconcilePayloadEnvelope validates once the block lands.
1290
1474
  // payloadInput may be seeded from the block body during download, so a non-null payloadInput does not
1291
1475
  // imply the block is imported.
1476
+ this.metrics?.blockInputSync.payloadFetchTime.observe(
1477
+ {result: FetchResult.SuccessWaitingForBlock},
1478
+ Date.now() / 1000 - fetchStartSec
1479
+ );
1480
+ this.metrics?.blockInputSync.payloadFetchPeers.set({result: FetchResult.SuccessWaitingForBlock}, i);
1292
1481
  return {
1293
1482
  status: PendingPayloadInputStatus.waitingForBlock,
1294
1483
  envelope,
@@ -1339,6 +1528,12 @@ export class BlockInputSync {
1339
1528
  });
1340
1529
 
1341
1530
  if (pendingPayload.status === PendingPayloadInputStatus.downloaded) {
1531
+ // late = the payload got imported (via gossip) while we were downloading, same as the block path
1532
+ const result = this.chain.forkChoice.hasPayloadHexUnsafe(rootHex)
1533
+ ? FetchResult.SuccessLate
1534
+ : FetchResult.SuccessResolved;
1535
+ this.metrics?.blockInputSync.payloadFetchTime.observe({result}, Date.now() / 1000 - fetchStartSec);
1536
+ this.metrics?.blockInputSync.payloadFetchPeers.set({result}, i);
1342
1537
  return pendingPayload;
1343
1538
  }
1344
1539
 
@@ -1373,12 +1568,17 @@ export class BlockInputSync {
1373
1568
  }
1374
1569
  }
1375
1570
 
1571
+ this.metrics?.blockInputSync.payloadFetchTime.observe(
1572
+ {result: FetchResult.FailureMaxAttempts},
1573
+ Date.now() / 1000 - fetchStartSec
1574
+ );
1575
+ this.metrics?.blockInputSync.payloadFetchPeers.set({result: FetchResult.FailureMaxAttempts}, i - 1);
1576
+
1376
1577
  if (deferredByRateLimit && this.peerBalancer.getNextRateLimitRetryAt() !== null) {
1377
1578
  throw new UnknownBlockRateLimitedError(
1378
1579
  `Error fetching payload with slot=${slot} root=${rootHex} after ${i - 1} attempts: peers are rate-limited`
1379
1580
  );
1380
1581
  }
1381
-
1382
1582
  throw Error(`Error fetching payload with slot=${slot} root=${rootHex} after ${i - 1} attempts.`);
1383
1583
  }
1384
1584
 
@@ -1483,7 +1683,7 @@ export class BlockInputSync {
1483
1683
 
1484
1684
  // no more peer with needed columns to try, throw error
1485
1685
  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(
1686
+ this.metrics?.blockInputSync.fetchTime.observe(
1487
1687
  {result: FetchResult.FailureTriedAllPeers},
1488
1688
  Date.now() / 1000 - fetchStartSec
1489
1689
  );
@@ -1572,7 +1772,7 @@ export class BlockInputSync {
1572
1772
  : this.chain.forkChoice.hasBlockHex(cacheItem.blockInput.parentRootHex)
1573
1773
  ? FetchResult.SuccessResolved
1574
1774
  : FetchResult.SuccessMissingParent;
1575
- this.metrics?.blockInputSync.fetchTimeSec.observe({result}, Date.now() / 1000 - fetchStartSec);
1775
+ this.metrics?.blockInputSync.fetchTime.observe({result}, Date.now() / 1000 - fetchStartSec);
1576
1776
  this.metrics?.blockInputSync.fetchPeers.set({result}, i);
1577
1777
  return cacheItem;
1578
1778
  }
@@ -1606,7 +1806,7 @@ export class BlockInputSync {
1606
1806
  }
1607
1807
  }
1608
1808
 
1609
- this.metrics?.blockInputSync.fetchTimeSec.observe(
1809
+ this.metrics?.blockInputSync.fetchTime.observe(
1610
1810
  {result: FetchResult.FailureMaxAttempts},
1611
1811
  Date.now() / 1000 - fetchStartSec
1612
1812
  );
@@ -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"}