@lodestar/beacon-node 1.39.0 → 1.40.0-dev.1c71f4299a

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 (245) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +8 -18
  3. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  4. package/lib/api/impl/beacon/state/utils.d.ts +2 -7
  5. package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
  6. package/lib/api/impl/beacon/state/utils.js +0 -12
  7. package/lib/api/impl/beacon/state/utils.js.map +1 -1
  8. package/lib/api/impl/config/constants.d.ts +3 -0
  9. package/lib/api/impl/config/constants.d.ts.map +1 -1
  10. package/lib/api/impl/config/constants.js +5 -1
  11. package/lib/api/impl/config/constants.js.map +1 -1
  12. package/lib/api/impl/debug/index.d.ts +1 -1
  13. package/lib/api/impl/debug/index.d.ts.map +1 -1
  14. package/lib/api/impl/debug/index.js +3 -6
  15. package/lib/api/impl/debug/index.js.map +1 -1
  16. package/lib/api/impl/lodestar/index.d.ts.map +1 -1
  17. package/lib/api/impl/lodestar/index.js +6 -1
  18. package/lib/api/impl/lodestar/index.js.map +1 -1
  19. package/lib/api/impl/proof/index.d.ts.map +1 -1
  20. package/lib/api/impl/proof/index.js +1 -2
  21. package/lib/api/impl/proof/index.js.map +1 -1
  22. package/lib/api/impl/validator/index.d.ts.map +1 -1
  23. package/lib/api/impl/validator/index.js +1 -3
  24. package/lib/api/impl/validator/index.js.map +1 -1
  25. package/lib/chain/archiveStore/historicalState/getHistoricalState.d.ts.map +1 -1
  26. package/lib/chain/archiveStore/historicalState/getHistoricalState.js +5 -3
  27. package/lib/chain/archiveStore/historicalState/getHistoricalState.js.map +1 -1
  28. package/lib/chain/archiveStore/utils/archiveBlocks.d.ts.map +1 -1
  29. package/lib/chain/archiveStore/utils/archiveBlocks.js +23 -14
  30. package/lib/chain/archiveStore/utils/archiveBlocks.js.map +1 -1
  31. package/lib/chain/blocks/blockInput/blockInput.d.ts +2 -0
  32. package/lib/chain/blocks/blockInput/blockInput.d.ts.map +1 -1
  33. package/lib/chain/blocks/blockInput/blockInput.js +6 -0
  34. package/lib/chain/blocks/blockInput/blockInput.js.map +1 -1
  35. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  36. package/lib/chain/blocks/importBlock.js +14 -9
  37. package/lib/chain/blocks/importBlock.js.map +1 -1
  38. package/lib/chain/blocks/index.d.ts.map +1 -1
  39. package/lib/chain/blocks/index.js +0 -14
  40. package/lib/chain/blocks/index.js.map +1 -1
  41. package/lib/chain/blocks/types.d.ts +0 -2
  42. package/lib/chain/blocks/types.d.ts.map +1 -1
  43. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  44. package/lib/chain/blocks/verifyBlock.js +8 -8
  45. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  46. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts.map +1 -1
  47. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js +1 -0
  48. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js.map +1 -1
  49. package/lib/chain/blocks/writeBlockInputToDb.d.ts +1 -4
  50. package/lib/chain/blocks/writeBlockInputToDb.d.ts.map +1 -1
  51. package/lib/chain/blocks/writeBlockInputToDb.js +20 -28
  52. package/lib/chain/blocks/writeBlockInputToDb.js.map +1 -1
  53. package/lib/chain/chain.d.ts +16 -3
  54. package/lib/chain/chain.d.ts.map +1 -1
  55. package/lib/chain/chain.js +165 -7
  56. package/lib/chain/chain.js.map +1 -1
  57. package/lib/chain/initState.d.ts +1 -1
  58. package/lib/chain/initState.d.ts.map +1 -1
  59. package/lib/chain/initState.js +5 -3
  60. package/lib/chain/initState.js.map +1 -1
  61. package/lib/chain/interface.d.ts +16 -3
  62. package/lib/chain/interface.d.ts.map +1 -1
  63. package/lib/chain/interface.js.map +1 -1
  64. package/lib/chain/lightClient/proofs.d.ts.map +1 -1
  65. package/lib/chain/lightClient/proofs.js +0 -2
  66. package/lib/chain/lightClient/proofs.js.map +1 -1
  67. package/lib/chain/opPools/aggregatedAttestationPool.d.ts +5 -9
  68. package/lib/chain/opPools/aggregatedAttestationPool.d.ts.map +1 -1
  69. package/lib/chain/opPools/aggregatedAttestationPool.js +12 -141
  70. package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
  71. package/lib/chain/opPools/opPool.js +5 -8
  72. package/lib/chain/opPools/opPool.js.map +1 -1
  73. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  74. package/lib/chain/prepareNextSlot.js +4 -7
  75. package/lib/chain/prepareNextSlot.js.map +1 -1
  76. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  77. package/lib/chain/produceBlock/produceBlockBody.js +1 -1
  78. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  79. package/lib/chain/regen/interface.d.ts +1 -5
  80. package/lib/chain/regen/interface.d.ts.map +1 -1
  81. package/lib/chain/regen/queued.d.ts +4 -7
  82. package/lib/chain/regen/queued.d.ts.map +1 -1
  83. package/lib/chain/regen/queued.js +15 -25
  84. package/lib/chain/regen/queued.js.map +1 -1
  85. package/lib/chain/regen/regen.d.ts +1 -1
  86. package/lib/chain/regen/regen.d.ts.map +1 -1
  87. package/lib/chain/regen/regen.js +13 -17
  88. package/lib/chain/regen/regen.js.map +1 -1
  89. package/lib/chain/shufflingCache.d.ts +16 -11
  90. package/lib/chain/shufflingCache.d.ts.map +1 -1
  91. package/lib/chain/shufflingCache.js +47 -41
  92. package/lib/chain/shufflingCache.js.map +1 -1
  93. package/lib/chain/stateCache/blockStateCacheImpl.d.ts +1 -2
  94. package/lib/chain/stateCache/blockStateCacheImpl.d.ts.map +1 -1
  95. package/lib/chain/stateCache/blockStateCacheImpl.js +2 -2
  96. package/lib/chain/stateCache/blockStateCacheImpl.js.map +1 -1
  97. package/lib/chain/stateCache/fifoBlockStateCache.d.ts +1 -2
  98. package/lib/chain/stateCache/fifoBlockStateCache.d.ts.map +1 -1
  99. package/lib/chain/stateCache/fifoBlockStateCache.js +4 -4
  100. package/lib/chain/stateCache/fifoBlockStateCache.js.map +1 -1
  101. package/lib/chain/stateCache/inMemoryCheckpointsCache.d.ts +4 -5
  102. package/lib/chain/stateCache/inMemoryCheckpointsCache.d.ts.map +1 -1
  103. package/lib/chain/stateCache/inMemoryCheckpointsCache.js +9 -10
  104. package/lib/chain/stateCache/inMemoryCheckpointsCache.js.map +1 -1
  105. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts +5 -6
  106. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
  107. package/lib/chain/stateCache/persistentCheckpointsCache.js +17 -17
  108. package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
  109. package/lib/chain/stateCache/types.d.ts +5 -6
  110. package/lib/chain/stateCache/types.d.ts.map +1 -1
  111. package/lib/chain/stateCache/types.js.map +1 -1
  112. package/lib/chain/validation/attestation.d.ts.map +1 -1
  113. package/lib/chain/validation/attestation.js +2 -2
  114. package/lib/chain/validation/attestation.js.map +1 -1
  115. package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
  116. package/lib/chain/validation/attesterSlashing.js +1 -1
  117. package/lib/chain/validation/attesterSlashing.js.map +1 -1
  118. package/lib/chain/validation/block.d.ts.map +1 -1
  119. package/lib/chain/validation/block.js +2 -0
  120. package/lib/chain/validation/block.js.map +1 -1
  121. package/lib/chain/validation/blsToExecutionChange.d.ts.map +1 -1
  122. package/lib/chain/validation/blsToExecutionChange.js +9 -2
  123. package/lib/chain/validation/blsToExecutionChange.js.map +1 -1
  124. package/lib/chain/validation/proposerSlashing.js +2 -1
  125. package/lib/chain/validation/proposerSlashing.js.map +1 -1
  126. package/lib/chain/validatorMonitor.d.ts +2 -0
  127. package/lib/chain/validatorMonitor.d.ts.map +1 -1
  128. package/lib/chain/validatorMonitor.js +42 -3
  129. package/lib/chain/validatorMonitor.js.map +1 -1
  130. package/lib/db/repositories/checkpointState.d.ts +2 -6
  131. package/lib/db/repositories/checkpointState.d.ts.map +1 -1
  132. package/lib/db/repositories/checkpointState.js +3 -15
  133. package/lib/db/repositories/checkpointState.js.map +1 -1
  134. package/lib/db/repositories/stateArchive.d.ts +9 -9
  135. package/lib/db/repositories/stateArchive.d.ts.map +1 -1
  136. package/lib/db/repositories/stateArchive.js +6 -21
  137. package/lib/db/repositories/stateArchive.js.map +1 -1
  138. package/lib/execution/engine/mock.d.ts +9 -6
  139. package/lib/execution/engine/mock.d.ts.map +1 -1
  140. package/lib/execution/engine/mock.js +34 -7
  141. package/lib/execution/engine/mock.js.map +1 -1
  142. package/lib/index.d.ts +1 -1
  143. package/lib/index.d.ts.map +1 -1
  144. package/lib/index.js +1 -1
  145. package/lib/index.js.map +1 -1
  146. package/lib/metrics/metrics/lodestar.d.ts +8 -6
  147. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  148. package/lib/metrics/metrics/lodestar.js +27 -17
  149. package/lib/metrics/metrics/lodestar.js.map +1 -1
  150. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  151. package/lib/network/processor/gossipHandlers.js +0 -3
  152. package/lib/network/processor/gossipHandlers.js.map +1 -1
  153. package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
  154. package/lib/network/reqresp/handlers/beaconBlocksByRange.js +2 -4
  155. package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
  156. package/lib/network/reqresp/handlers/beaconBlocksByRoot.d.ts +1 -2
  157. package/lib/network/reqresp/handlers/beaconBlocksByRoot.d.ts.map +1 -1
  158. package/lib/network/reqresp/handlers/beaconBlocksByRoot.js +5 -26
  159. package/lib/network/reqresp/handlers/beaconBlocksByRoot.js.map +1 -1
  160. package/lib/network/reqresp/handlers/blobSidecarsByRoot.d.ts +1 -2
  161. package/lib/network/reqresp/handlers/blobSidecarsByRoot.d.ts.map +1 -1
  162. package/lib/network/reqresp/handlers/blobSidecarsByRoot.js +5 -7
  163. package/lib/network/reqresp/handlers/blobSidecarsByRoot.js.map +1 -1
  164. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
  165. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +1 -2
  166. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
  167. package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.d.ts.map +1 -1
  168. package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.js +1 -5
  169. package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.js.map +1 -1
  170. package/lib/network/reqresp/handlers/index.js +2 -2
  171. package/lib/network/reqresp/handlers/index.js.map +1 -1
  172. package/lib/network/reqresp/utils/dataColumnResponseValidation.js +1 -1
  173. package/lib/network/reqresp/utils/dataColumnResponseValidation.js.map +1 -1
  174. package/lib/node/nodejs.d.ts.map +1 -1
  175. package/lib/node/nodejs.js +17 -2
  176. package/lib/node/nodejs.js.map +1 -1
  177. package/lib/sync/range/chain.d.ts.map +1 -1
  178. package/lib/sync/range/chain.js +0 -1
  179. package/lib/sync/range/chain.js.map +1 -1
  180. package/lib/sync/range/range.d.ts.map +1 -1
  181. package/lib/sync/range/range.js +0 -3
  182. package/lib/sync/range/range.js.map +1 -1
  183. package/lib/sync/unknownBlock.d.ts.map +1 -1
  184. package/lib/sync/unknownBlock.js +0 -3
  185. package/lib/sync/unknownBlock.js.map +1 -1
  186. package/lib/util/sszBytes.js +1 -1
  187. package/lib/util/sszBytes.js.map +1 -1
  188. package/package.json +15 -15
  189. package/src/api/impl/beacon/blocks/index.ts +8 -18
  190. package/src/api/impl/beacon/state/utils.ts +2 -22
  191. package/src/api/impl/config/constants.ts +8 -0
  192. package/src/api/impl/debug/index.ts +2 -6
  193. package/src/api/impl/lodestar/index.ts +7 -1
  194. package/src/api/impl/proof/index.ts +1 -2
  195. package/src/api/impl/validator/index.ts +1 -3
  196. package/src/chain/archiveStore/historicalState/getHistoricalState.ts +5 -3
  197. package/src/chain/archiveStore/utils/archiveBlocks.ts +25 -14
  198. package/src/chain/blocks/blockInput/blockInput.ts +8 -0
  199. package/src/chain/blocks/importBlock.ts +15 -9
  200. package/src/chain/blocks/index.ts +0 -19
  201. package/src/chain/blocks/types.ts +0 -2
  202. package/src/chain/blocks/verifyBlock.ts +9 -11
  203. package/src/chain/blocks/verifyBlocksStateTransitionOnly.ts +1 -0
  204. package/src/chain/blocks/writeBlockInputToDb.ts +24 -30
  205. package/src/chain/chain.ts +191 -10
  206. package/src/chain/initState.ts +5 -3
  207. package/src/chain/interface.ts +18 -2
  208. package/src/chain/lightClient/proofs.ts +0 -2
  209. package/src/chain/opPools/aggregatedAttestationPool.ts +19 -191
  210. package/src/chain/opPools/opPool.ts +5 -7
  211. package/src/chain/prepareNextSlot.ts +2 -6
  212. package/src/chain/produceBlock/produceBlockBody.ts +6 -1
  213. package/src/chain/regen/interface.ts +1 -5
  214. package/src/chain/regen/queued.ts +15 -34
  215. package/src/chain/regen/regen.ts +12 -18
  216. package/src/chain/shufflingCache.ts +67 -50
  217. package/src/chain/stateCache/blockStateCacheImpl.ts +2 -3
  218. package/src/chain/stateCache/fifoBlockStateCache.ts +4 -5
  219. package/src/chain/stateCache/inMemoryCheckpointsCache.ts +9 -15
  220. package/src/chain/stateCache/persistentCheckpointsCache.ts +17 -25
  221. package/src/chain/stateCache/types.ts +5 -10
  222. package/src/chain/validation/attestation.ts +3 -3
  223. package/src/chain/validation/attesterSlashing.ts +8 -1
  224. package/src/chain/validation/block.ts +3 -0
  225. package/src/chain/validation/blsToExecutionChange.ts +9 -7
  226. package/src/chain/validation/proposerSlashing.ts +2 -1
  227. package/src/chain/validatorMonitor.ts +52 -3
  228. package/src/db/repositories/checkpointState.ts +3 -19
  229. package/src/db/repositories/stateArchive.ts +13 -27
  230. package/src/execution/engine/mock.ts +40 -13
  231. package/src/index.ts +1 -1
  232. package/src/metrics/metrics/lodestar.ts +28 -17
  233. package/src/network/processor/gossipHandlers.ts +0 -3
  234. package/src/network/reqresp/handlers/beaconBlocksByRange.ts +2 -4
  235. package/src/network/reqresp/handlers/beaconBlocksByRoot.ts +5 -32
  236. package/src/network/reqresp/handlers/blobSidecarsByRoot.ts +5 -9
  237. package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +5 -2
  238. package/src/network/reqresp/handlers/dataColumnSidecarsByRoot.ts +1 -5
  239. package/src/network/reqresp/handlers/index.ts +2 -2
  240. package/src/network/reqresp/utils/dataColumnResponseValidation.ts +1 -1
  241. package/src/node/nodejs.ts +18 -3
  242. package/src/sync/range/chain.ts +0 -1
  243. package/src/sync/range/range.ts +0 -3
  244. package/src/sync/unknownBlock.ts +0 -3
  245. package/src/util/sszBytes.ts +1 -1
@@ -37,14 +37,19 @@ import {
37
37
  UintNum64,
38
38
  ValidatorIndex,
39
39
  Wei,
40
+ deneb,
41
+ fulu,
40
42
  isBlindedBeaconBlock,
41
43
  phase0,
42
44
  rewards,
45
+ ssz,
46
+ sszTypesFor,
43
47
  } from "@lodestar/types";
44
48
  import {Logger, fromHex, gweiToWei, isErrorAborted, pruneSetToMax, sleep, toRootHex} from "@lodestar/utils";
45
49
  import {ProcessShutdownCallback} from "@lodestar/validator";
46
50
  import {GENESIS_EPOCH, ZERO_HASH} from "../constants/index.js";
47
51
  import {IBeaconDb} from "../db/index.js";
52
+ import {BLOB_SIDECARS_IN_WRAPPER_INDEX} from "../db/repositories/blobSidecars.ts";
48
53
  import {BuilderStatus} from "../execution/builder/http.js";
49
54
  import {IExecutionBuilder, IExecutionEngine} from "../execution/index.js";
50
55
  import {Metrics} from "../metrics/index.js";
@@ -52,14 +57,18 @@ import {computeNodeIdFromPrivateKey} from "../network/subnets/interface.js";
52
57
  import {BufferPool} from "../util/bufferPool.js";
53
58
  import {Clock, ClockEvent, IClock} from "../util/clock.js";
54
59
  import {CustodyConfig, getValidatorsCustodyRequirement} from "../util/dataColumns.js";
60
+ import {callInNextEventLoop} from "../util/eventLoop.js";
55
61
  import {ensureDir, writeIfNotExist} from "../util/file.js";
56
62
  import {isOptimisticBlock} from "../util/forkChoice.js";
63
+ import {JobItemQueue} from "../util/queue/itemQueue.ts";
57
64
  import {SerializedCache} from "../util/serializedCache.js";
65
+ import {getSlotFromSignedBeaconBlockSerialized} from "../util/sszBytes.ts";
58
66
  import {ArchiveStore} from "./archiveStore/archiveStore.js";
59
67
  import {CheckpointBalancesCache} from "./balancesCache.js";
60
68
  import {BeaconProposerCache} from "./beaconProposerCache.js";
61
- import {IBlockInput} from "./blocks/blockInput/index.js";
69
+ import {IBlockInput, isBlockInputBlobs, isBlockInputColumns} from "./blocks/blockInput/index.js";
62
70
  import {BlockProcessor, ImportBlockOpts} from "./blocks/index.js";
71
+ import {persistBlockInputs} from "./blocks/writeBlockInputToDb.ts";
63
72
  import {BlsMultiThreadWorkerPool, BlsSingleThreadVerifier, IBlsVerifier} from "./bls/index.js";
64
73
  import {ColumnReconstructionTracker} from "./ColumnReconstructionTracker.js";
65
74
  import {ChainEvent, ChainEventEmitter} from "./emitter.js";
@@ -112,6 +121,11 @@ import {ValidatorMonitor} from "./validatorMonitor.js";
112
121
  */
113
122
  const DEFAULT_MAX_CACHED_PRODUCED_RESULTS = 4;
114
123
 
124
+ /**
125
+ * The maximum number of pending unfinalized block writes to the database before backpressure is applied.
126
+ */
127
+ const DEFAULT_MAX_PENDING_UNFINALIZED_BLOCK_WRITES = 32;
128
+
115
129
  export class BeaconChain implements IBeaconChain {
116
130
  readonly genesisTime: UintNum64;
117
131
  readonly genesisValidatorsRoot: Root;
@@ -135,6 +149,7 @@ export class BeaconChain implements IBeaconChain {
135
149
  readonly lightClientServer?: LightClientServer;
136
150
  readonly reprocessController: ReprocessController;
137
151
  readonly archiveStore: ArchiveStore;
152
+ readonly unfinalizedBlockWrites: JobItemQueue<[IBlockInput[]], void>;
138
153
 
139
154
  // Ops pool
140
155
  readonly attestationPool: AttestationPool;
@@ -291,7 +306,8 @@ export class BeaconChain implements IBeaconChain {
291
306
  });
292
307
 
293
308
  this._earliestAvailableSlot = anchorState.slot;
294
- this.shufflingCache = anchorState.epochCtx.shufflingCache = new ShufflingCache(metrics, logger, this.opts, [
309
+
310
+ this.shufflingCache = new ShufflingCache(metrics, logger, this.opts, [
295
311
  {
296
312
  shuffling: anchorState.epochCtx.previousShuffling,
297
313
  decisionRoot: anchorState.epochCtx.previousDecisionRoot,
@@ -403,6 +419,15 @@ export class BeaconChain implements IBeaconChain {
403
419
  signal
404
420
  );
405
421
 
422
+ this.unfinalizedBlockWrites = new JobItemQueue(
423
+ persistBlockInputs.bind(this),
424
+ {
425
+ maxLength: DEFAULT_MAX_PENDING_UNFINALIZED_BLOCK_WRITES,
426
+ signal,
427
+ },
428
+ metrics?.unfinalizedBlockWritesQueue
429
+ );
430
+
406
431
  // always run PrepareNextSlotScheduler except for fork_choice spec tests
407
432
  if (!opts?.disablePrepareNextSlot) {
408
433
  new PrepareNextSlotScheduler(this, this.config, metrics, this.logger, signal);
@@ -417,6 +442,7 @@ export class BeaconChain implements IBeaconChain {
417
442
  clock.addListener(ClockEvent.epoch, this.onClockEpoch.bind(this));
418
443
  emitter.addListener(ChainEvent.forkChoiceFinalized, this.onForkChoiceFinalized.bind(this));
419
444
  emitter.addListener(ChainEvent.forkChoiceJustified, this.onForkChoiceJustified.bind(this));
445
+ emitter.addListener(ChainEvent.checkpoint, this.onCheckpoint.bind(this));
420
446
  }
421
447
 
422
448
  async init(): Promise<void> {
@@ -427,6 +453,12 @@ export class BeaconChain implements IBeaconChain {
427
453
  async close(): Promise<void> {
428
454
  await this.archiveStore.close();
429
455
  await this.bls.close();
456
+
457
+ // Since we don't persist unfinalized fork-choice,
458
+ // we can abort any ongoing unfinalized block writes.
459
+ // TODO: persist fork choice to disk and allow unfinalized block writes to complete.
460
+ this.unfinalizedBlockWrites.dropAllJobs();
461
+
430
462
  this.abortController.abort();
431
463
  }
432
464
 
@@ -504,7 +536,7 @@ export class BeaconChain implements IBeaconChain {
504
536
  async getStateBySlot(
505
537
  slot: Slot,
506
538
  opts?: StateGetOpts
507
- ): Promise<{state: BeaconStateAllForks; executionOptimistic: boolean; finalized: boolean} | null> {
539
+ ): Promise<{state: CachedBeaconStateAllForks; executionOptimistic: boolean; finalized: boolean} | null> {
508
540
  const finalizedBlock = this.forkChoice.getFinalizedBlock();
509
541
 
510
542
  if (slot < finalizedBlock.slot) {
@@ -559,7 +591,7 @@ export class BeaconChain implements IBeaconChain {
559
591
  async getStateByStateRoot(
560
592
  stateRoot: RootHex,
561
593
  opts?: StateGetOpts
562
- ): Promise<{state: BeaconStateAllForks; executionOptimistic: boolean; finalized: boolean} | null> {
594
+ ): Promise<{state: CachedBeaconStateAllForks | Uint8Array; executionOptimistic: boolean; finalized: boolean} | null> {
563
595
  if (opts?.allowRegen) {
564
596
  const state = await this.regen.getState(stateRoot, RegenCaller.restApi);
565
597
  const block = this.forkChoice.getBlock(state.latestBlockHeader.hashTreeRoot());
@@ -587,7 +619,8 @@ export class BeaconChain implements IBeaconChain {
587
619
  };
588
620
  }
589
621
 
590
- const data = await this.db.stateArchive.getByRoot(fromHex(stateRoot));
622
+ // this is mostly useful for a node with `--chain.archiveStateEpochFrequency 1`
623
+ const data = await this.db.stateArchive.getBinaryByRoot(fromHex(stateRoot));
591
624
  return data && {state: data, executionOptimistic: false, finalized: true};
592
625
  }
593
626
 
@@ -648,6 +681,13 @@ export class BeaconChain implements IBeaconChain {
648
681
  // Unfinalized slot, attempt to find in fork-choice
649
682
  const block = this.forkChoice.getCanonicalBlockAtSlot(slot);
650
683
  if (block) {
684
+ // Block found in fork-choice.
685
+ // It may be in the block input cache, awaiting full DA reconstruction, check there first
686
+ // Otherwise (most likely), check the hot db
687
+ const blockInput = this.seenBlockInputCache.get(block.blockRoot);
688
+ if (blockInput?.hasBlock()) {
689
+ return {block: blockInput.getBlock(), executionOptimistic: isOptimisticBlock(block), finalized: false};
690
+ }
651
691
  const data = await this.db.block.get(fromHex(block.blockRoot));
652
692
  if (data) {
653
693
  return {block: data, executionOptimistic: isOptimisticBlock(block), finalized: false};
@@ -667,6 +707,13 @@ export class BeaconChain implements IBeaconChain {
667
707
  ): Promise<{block: SignedBeaconBlock; executionOptimistic: boolean; finalized: boolean} | null> {
668
708
  const block = this.forkChoice.getBlockHex(root);
669
709
  if (block) {
710
+ // Block found in fork-choice.
711
+ // It may be in the block input cache, awaiting full DA reconstruction, check there first
712
+ // Otherwise (most likely), check the hot db
713
+ const blockInput = this.seenBlockInputCache.get(block.blockRoot);
714
+ if (blockInput?.hasBlock()) {
715
+ return {block: blockInput.getBlock(), executionOptimistic: isOptimisticBlock(block), finalized: false};
716
+ }
670
717
  const data = await this.db.block.get(fromHex(root));
671
718
  if (data) {
672
719
  return {block: data, executionOptimistic: isOptimisticBlock(block), finalized: false};
@@ -679,6 +726,133 @@ export class BeaconChain implements IBeaconChain {
679
726
  return data && {block: data, executionOptimistic: false, finalized: true};
680
727
  }
681
728
 
729
+ async getSerializedBlockByRoot(
730
+ root: string
731
+ ): Promise<{block: Uint8Array; executionOptimistic: boolean; finalized: boolean; slot: Slot} | null> {
732
+ const block = this.forkChoice.getBlockHex(root);
733
+ if (block) {
734
+ // Block found in fork-choice.
735
+ // It may be in the block input cache, awaiting full DA reconstruction, check there first
736
+ // Otherwise (most likely), check the hot db
737
+ const blockInput = this.seenBlockInputCache.get(block.blockRoot);
738
+ if (blockInput?.hasBlock()) {
739
+ const signedBlock = blockInput.getBlock();
740
+ const serialized = this.serializedCache.get(signedBlock);
741
+ if (serialized) {
742
+ return {
743
+ block: serialized,
744
+ executionOptimistic: isOptimisticBlock(block),
745
+ finalized: false,
746
+ slot: blockInput.slot,
747
+ };
748
+ }
749
+ return {
750
+ block: sszTypesFor(blockInput.forkName).SignedBeaconBlock.serialize(signedBlock),
751
+ executionOptimistic: isOptimisticBlock(block),
752
+ finalized: false,
753
+ slot: blockInput.slot,
754
+ };
755
+ }
756
+ const data = await this.db.block.getBinary(fromHex(root));
757
+ if (data) {
758
+ const slot = getSlotFromSignedBeaconBlockSerialized(data);
759
+ if (slot === null) throw new Error(`Invalid block data stored in DB for root: ${root}`);
760
+ return {block: data, executionOptimistic: isOptimisticBlock(block), finalized: false, slot};
761
+ }
762
+ // If block is not found in hot db, try cold db since there could be an archive cycle happening
763
+ // TODO: Add a lock to the archiver to have deterministic behavior on where are blocks
764
+ }
765
+
766
+ const data = await this.db.blockArchive.getBinaryEntryByRoot(fromHex(root));
767
+ return data && {block: data.value, executionOptimistic: false, finalized: true, slot: data.key};
768
+ }
769
+
770
+ async getBlobSidecars(blockSlot: Slot, blockRootHex: string): Promise<deneb.BlobSidecars | null> {
771
+ const blockInput = this.seenBlockInputCache.get(blockRootHex);
772
+ if (blockInput) {
773
+ if (!isBlockInputBlobs(blockInput)) {
774
+ throw new Error(`Expected block input to have blobs: slot=${blockSlot} root=${blockRootHex}`);
775
+ }
776
+ if (!blockInput.hasAllData()) {
777
+ return null;
778
+ }
779
+ return blockInput.getBlobs();
780
+ }
781
+ const unfinalizedBlobSidecars = (await this.db.blobSidecars.get(fromHex(blockRootHex)))?.blobSidecars ?? null;
782
+ if (unfinalizedBlobSidecars) {
783
+ return unfinalizedBlobSidecars;
784
+ }
785
+ return (await this.db.blobSidecarsArchive.get(blockSlot))?.blobSidecars ?? null;
786
+ }
787
+
788
+ async getSerializedBlobSidecars(blockSlot: Slot, blockRootHex: string): Promise<Uint8Array | null> {
789
+ const blockInput = this.seenBlockInputCache.get(blockRootHex);
790
+ if (blockInput) {
791
+ if (!isBlockInputBlobs(blockInput)) {
792
+ throw new Error(`Expected block input to have blobs: slot=${blockSlot} root=${blockRootHex}`);
793
+ }
794
+ if (!blockInput.hasAllData()) {
795
+ return null;
796
+ }
797
+ return ssz.deneb.BlobSidecars.serialize(blockInput.getBlobs());
798
+ }
799
+ const unfinalizedBlobSidecarsWrapper = await this.db.blobSidecars.getBinary(fromHex(blockRootHex));
800
+ if (unfinalizedBlobSidecarsWrapper) {
801
+ return unfinalizedBlobSidecarsWrapper.slice(BLOB_SIDECARS_IN_WRAPPER_INDEX);
802
+ }
803
+ const finalizedBlobSidecarsWrapper = await this.db.blobSidecarsArchive.getBinary(blockSlot);
804
+ if (finalizedBlobSidecarsWrapper) {
805
+ return finalizedBlobSidecarsWrapper.slice(BLOB_SIDECARS_IN_WRAPPER_INDEX);
806
+ }
807
+ return null;
808
+ }
809
+
810
+ async getDataColumnSidecars(blockSlot: Slot, blockRootHex: string): Promise<fulu.DataColumnSidecars> {
811
+ const blockInput = this.seenBlockInputCache.get(blockRootHex);
812
+ if (blockInput) {
813
+ if (!isBlockInputColumns(blockInput)) {
814
+ throw new Error(`Expected block input to have columns: slot=${blockSlot} root=${blockRootHex}`);
815
+ }
816
+ return blockInput.getAllColumns();
817
+ }
818
+ const sidecarsUnfinalized = await this.db.dataColumnSidecar.values(fromHex(blockRootHex));
819
+ if (sidecarsUnfinalized.length > 0) {
820
+ return sidecarsUnfinalized;
821
+ }
822
+ const sidecarsFinalized = await this.db.dataColumnSidecarArchive.values(blockSlot);
823
+ return sidecarsFinalized;
824
+ }
825
+
826
+ async getSerializedDataColumnSidecars(
827
+ blockSlot: Slot,
828
+ blockRootHex: string,
829
+ indices: number[]
830
+ ): Promise<(Uint8Array | undefined)[]> {
831
+ const blockInput = this.seenBlockInputCache.get(blockRootHex);
832
+ if (blockInput) {
833
+ if (!isBlockInputColumns(blockInput)) {
834
+ throw new Error(`Expected block input to have columns: slot=${blockSlot} root=${blockRootHex}`);
835
+ }
836
+ return indices.map((index) => {
837
+ const sidecar = blockInput.getColumn(index);
838
+ if (!sidecar) {
839
+ return undefined;
840
+ }
841
+ const serialized = this.serializedCache.get(sidecar);
842
+ if (serialized) {
843
+ return serialized;
844
+ }
845
+ return ssz.fulu.DataColumnSidecar.serialize(sidecar);
846
+ });
847
+ }
848
+ const sidecarsUnfinalized = await this.db.dataColumnSidecar.getManyBinary(fromHex(blockRootHex), indices);
849
+ if (sidecarsUnfinalized.some((sidecar) => sidecar != null)) {
850
+ return sidecarsUnfinalized;
851
+ }
852
+ const sidecarsFinalized = await this.db.dataColumnSidecarArchive.getManyBinary(blockSlot, indices);
853
+ return sidecarsFinalized;
854
+ }
855
+
682
856
  async produceCommonBlockBody(blockAttributes: BlockAttributes): Promise<CommonBlockBody> {
683
857
  const {slot, parentBlockRoot} = blockAttributes;
684
858
  const state = await this.regen.getBlockSlotState(
@@ -980,8 +1154,8 @@ export class BeaconChain implements IBeaconChain {
980
1154
  this.metrics?.gossipAttestation.useHeadBlockState.inc({caller: regenCaller});
981
1155
  state = await this.regen.getState(attHeadBlock.stateRoot, regenCaller);
982
1156
  }
983
-
984
- // should always be the current epoch of the active context so no need to await a result from the ShufflingCache
1157
+ // resolve the promise to unblock other calls of the same epoch and dependent root
1158
+ this.shufflingCache.processState(state);
985
1159
  return state.epochCtx.getShufflingAtEpoch(attEpoch);
986
1160
  }
987
1161
 
@@ -1165,6 +1339,13 @@ export class BeaconChain implements IBeaconChain {
1165
1339
  this.logger.verbose("Fork choice justified", {epoch: cp.epoch, root: cp.rootHex});
1166
1340
  }
1167
1341
 
1342
+ private onCheckpoint(this: BeaconChain, _checkpoint: phase0.Checkpoint, state: CachedBeaconStateAllForks): void {
1343
+ // Defer to not block other checkpoint event handlers, which can cause lightclient update delays
1344
+ callInNextEventLoop(() => {
1345
+ this.shufflingCache.processState(state);
1346
+ });
1347
+ }
1348
+
1168
1349
  private async onForkChoiceFinalized(this: BeaconChain, cp: CheckpointWithHex): Promise<void> {
1169
1350
  this.logger.verbose("Fork choice finalized", {epoch: cp.epoch, root: cp.rootHex});
1170
1351
  this.seenBlockProposers.prune(computeStartSlotAtEpoch(cp.epoch));
@@ -1295,9 +1476,9 @@ export class BeaconChain implements IBeaconChain {
1295
1476
 
1296
1477
  preState = processSlots(preState, block.slot); // Dial preState's slot to block.slot
1297
1478
 
1298
- const postState = this.regen.getStateSync(toRootHex(block.stateRoot)) ?? undefined;
1479
+ const proposerRewards = this.regen.getStateSync(toRootHex(block.stateRoot))?.proposerRewards ?? undefined;
1299
1480
 
1300
- return computeBlockRewards(this.config, block, preState.clone(), postState?.clone());
1481
+ return computeBlockRewards(this.config, block, preState, proposerRewards);
1301
1482
  }
1302
1483
 
1303
1484
  async getAttestationsRewards(
@@ -1338,6 +1519,6 @@ export class BeaconChain implements IBeaconChain {
1338
1519
 
1339
1520
  preState = processSlots(preState, block.slot); // Dial preState's slot to block.slot
1340
1521
 
1341
- return computeSyncCommitteeRewards(this.config, this.index2pubkey, block, preState.clone(), validatorIds);
1522
+ return computeSyncCommitteeRewards(this.config, this.index2pubkey, block, preState, validatorIds);
1342
1523
  }
1343
1524
  }
@@ -6,6 +6,7 @@ import {Logger, toHex, toRootHex} from "@lodestar/utils";
6
6
  import {GENESIS_SLOT} from "../constants/index.js";
7
7
  import {IBeaconDb} from "../db/index.js";
8
8
  import {Metrics} from "../metrics/index.js";
9
+ import {getStateTypeFromBytes} from "../util/multifork.js";
9
10
 
10
11
  export async function persistAnchorState(
11
12
  config: ChainForkConfig,
@@ -53,14 +54,15 @@ export function createGenesisBlock(config: ChainForkConfig, genesisState: Beacon
53
54
  * Restore the latest beacon state from db
54
55
  */
55
56
  export async function initStateFromDb(
56
- _config: ChainForkConfig,
57
+ config: ChainForkConfig,
57
58
  db: IBeaconDb,
58
59
  logger: Logger
59
60
  ): Promise<BeaconStateAllForks> {
60
- const state = await db.stateArchive.lastValue();
61
- if (!state) {
61
+ const stateBytes = await db.stateArchive.lastBinary();
62
+ if (stateBytes == null) {
62
63
  throw new Error("No state exists in database");
63
64
  }
65
+ const state = getStateTypeFromBytes(config, stateBytes).deserializeToViewDU(stateBytes);
64
66
 
65
67
  logger.info("Initializing beacon state from db", {
66
68
  slot: state.slot,
@@ -22,6 +22,8 @@ import {
22
22
  Wei,
23
23
  altair,
24
24
  capella,
25
+ deneb,
26
+ fulu,
25
27
  phase0,
26
28
  rewards,
27
29
  } from "@lodestar/types";
@@ -168,12 +170,12 @@ export interface IBeaconChain {
168
170
  getStateBySlot(
169
171
  slot: Slot,
170
172
  opts?: StateGetOpts
171
- ): Promise<{state: BeaconStateAllForks; executionOptimistic: boolean; finalized: boolean} | null>;
173
+ ): Promise<{state: CachedBeaconStateAllForks; executionOptimistic: boolean; finalized: boolean} | null>;
172
174
  /** Returns a local state by state root */
173
175
  getStateByStateRoot(
174
176
  stateRoot: RootHex,
175
177
  opts?: StateGetOpts
176
- ): Promise<{state: BeaconStateAllForks; executionOptimistic: boolean; finalized: boolean} | null>;
178
+ ): Promise<{state: CachedBeaconStateAllForks | Uint8Array; executionOptimistic: boolean; finalized: boolean} | null>;
177
179
  /** Return serialized bytes of a persisted checkpoint state */
178
180
  getPersistedCheckpointState(checkpoint?: phase0.Checkpoint): Promise<Uint8Array | null>;
179
181
  /** Returns a cached state by checkpoint */
@@ -193,12 +195,26 @@ export interface IBeaconChain {
193
195
  getCanonicalBlockAtSlot(
194
196
  slot: Slot
195
197
  ): Promise<{block: SignedBeaconBlock; executionOptimistic: boolean; finalized: boolean} | null>;
198
+ /**
199
+ * Get local block by root, does not fetch from the network
200
+ */
201
+ getSerializedBlockByRoot(
202
+ root: RootHex
203
+ ): Promise<{block: Uint8Array; executionOptimistic: boolean; finalized: boolean; slot: Slot} | null>;
196
204
  /**
197
205
  * Get local block by root, does not fetch from the network
198
206
  */
199
207
  getBlockByRoot(
200
208
  root: RootHex
201
209
  ): Promise<{block: SignedBeaconBlock; executionOptimistic: boolean; finalized: boolean} | null>;
210
+ getBlobSidecars(blockSlot: Slot, blockRootHex: string): Promise<deneb.BlobSidecars | null>;
211
+ getSerializedBlobSidecars(blockSlot: Slot, blockRootHex: string): Promise<Uint8Array | null>;
212
+ getDataColumnSidecars(blockSlot: Slot, blockRootHex: string): Promise<fulu.DataColumnSidecars>;
213
+ getSerializedDataColumnSidecars(
214
+ blockSlot: Slot,
215
+ blockRootHex: string,
216
+ indices: number[]
217
+ ): Promise<(Uint8Array | undefined)[]>;
202
218
 
203
219
  produceCommonBlockBody(blockAttributes: BlockAttributes): Promise<CommonBlockBody>;
204
220
  produceBlock(blockAttributes: BlockAttributes & {commonBlockBodyPromise: Promise<CommonBlockBody>}): Promise<{
@@ -12,7 +12,6 @@ import {BeaconBlockBody, SSZTypesFor, ssz} from "@lodestar/types";
12
12
  import {SyncCommitteeWitness} from "./types.js";
13
13
 
14
14
  export function getSyncCommitteesWitness(fork: ForkName, state: BeaconStateAllForks): SyncCommitteeWitness {
15
- state.commit();
16
15
  const n1 = state.node;
17
16
  let witness: Uint8Array[];
18
17
  let currentSyncCommitteeRoot: Uint8Array;
@@ -71,7 +70,6 @@ export function getCurrentSyncCommitteeBranch(syncCommitteesWitness: SyncCommitt
71
70
  }
72
71
 
73
72
  export function getFinalizedRootProof(state: CachedBeaconStateAllForks): Uint8Array[] {
74
- state.commit();
75
73
  const finalizedRootGindex = state.epochCtx.isPostElectra() ? FINALIZED_ROOT_GINDEX_ELECTRA : FINALIZED_ROOT_GINDEX;
76
74
  return new Tree(state.node).getSingleProof(BigInt(finalizedRootGindex));
77
75
  }