@lodestar/beacon-node 1.41.0 → 1.42.0-dev.4118b5b440

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 (252) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +35 -16
  3. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  4. package/lib/api/impl/beacon/state/utils.d.ts +2 -2
  5. package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
  6. package/lib/api/impl/beacon/state/utils.js.map +1 -1
  7. package/lib/api/impl/validator/index.d.ts.map +1 -1
  8. package/lib/api/impl/validator/index.js +6 -2
  9. package/lib/api/impl/validator/index.js.map +1 -1
  10. package/lib/chain/archiveStore/archiveStore.d.ts +0 -1
  11. package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
  12. package/lib/chain/archiveStore/archiveStore.js +0 -9
  13. package/lib/chain/archiveStore/archiveStore.js.map +1 -1
  14. package/lib/chain/archiveStore/interface.d.ts +4 -4
  15. package/lib/chain/archiveStore/interface.d.ts.map +1 -1
  16. package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.d.ts +4 -4
  17. package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.d.ts.map +1 -1
  18. package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.js +4 -1
  19. package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.js.map +1 -1
  20. package/lib/chain/archiveStore/utils/archiveBlocks.d.ts.map +1 -1
  21. package/lib/chain/archiveStore/utils/archiveBlocks.js +38 -0
  22. package/lib/chain/archiveStore/utils/archiveBlocks.js.map +1 -1
  23. package/lib/chain/blocks/blockInput/types.d.ts +4 -3
  24. package/lib/chain/blocks/blockInput/types.d.ts.map +1 -1
  25. package/lib/chain/blocks/blockInput/types.js +1 -0
  26. package/lib/chain/blocks/blockInput/types.js.map +1 -1
  27. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  28. package/lib/chain/blocks/importBlock.js +29 -9
  29. package/lib/chain/blocks/importBlock.js.map +1 -1
  30. package/lib/chain/blocks/importExecutionPayload.d.ts +48 -0
  31. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -0
  32. package/lib/chain/blocks/importExecutionPayload.js +159 -0
  33. package/lib/chain/blocks/importExecutionPayload.js.map +1 -0
  34. package/lib/chain/blocks/payloadEnvelopeInput/index.d.ts +3 -0
  35. package/lib/chain/blocks/payloadEnvelopeInput/index.d.ts.map +1 -0
  36. package/lib/chain/blocks/payloadEnvelopeInput/index.js +3 -0
  37. package/lib/chain/blocks/payloadEnvelopeInput/index.js.map +1 -0
  38. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +80 -0
  39. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -0
  40. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +248 -0
  41. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -0
  42. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +29 -0
  43. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -0
  44. package/lib/chain/blocks/payloadEnvelopeInput/types.js +11 -0
  45. package/lib/chain/blocks/payloadEnvelopeInput/types.js.map +1 -0
  46. package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts +15 -0
  47. package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts.map +1 -0
  48. package/lib/chain/blocks/payloadEnvelopeProcessor.js +46 -0
  49. package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -0
  50. package/lib/chain/blocks/types.d.ts +7 -0
  51. package/lib/chain/blocks/types.d.ts.map +1 -1
  52. package/lib/chain/blocks/verifyBlocksSignatures.js +1 -1
  53. package/lib/chain/blocks/verifyBlocksSignatures.js.map +1 -1
  54. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.d.ts +12 -0
  55. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.d.ts.map +1 -0
  56. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js +40 -0
  57. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js.map +1 -0
  58. package/lib/chain/chain.d.ts +10 -5
  59. package/lib/chain/chain.d.ts.map +1 -1
  60. package/lib/chain/chain.js +44 -10
  61. package/lib/chain/chain.js.map +1 -1
  62. package/lib/chain/errors/executionPayloadEnvelope.d.ts +12 -2
  63. package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -1
  64. package/lib/chain/errors/executionPayloadEnvelope.js +3 -1
  65. package/lib/chain/errors/executionPayloadEnvelope.js.map +1 -1
  66. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  67. package/lib/chain/forkChoice/index.js +0 -10
  68. package/lib/chain/forkChoice/index.js.map +1 -1
  69. package/lib/chain/interface.d.ts +8 -5
  70. package/lib/chain/interface.d.ts.map +1 -1
  71. package/lib/chain/opPools/utils.js +1 -1
  72. package/lib/chain/opPools/utils.js.map +1 -1
  73. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  74. package/lib/chain/prepareNextSlot.js +6 -2
  75. package/lib/chain/prepareNextSlot.js.map +1 -1
  76. package/lib/chain/produceBlock/computeNewStateRoot.d.ts.map +1 -1
  77. package/lib/chain/produceBlock/computeNewStateRoot.js +6 -1
  78. package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
  79. package/lib/chain/produceBlock/produceBlockBody.js +1 -1
  80. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  81. package/lib/chain/regen/errors.d.ts +11 -1
  82. package/lib/chain/regen/errors.d.ts.map +1 -1
  83. package/lib/chain/regen/errors.js +2 -0
  84. package/lib/chain/regen/errors.js.map +1 -1
  85. package/lib/chain/regen/interface.d.ts +14 -6
  86. package/lib/chain/regen/interface.d.ts.map +1 -1
  87. package/lib/chain/regen/interface.js +2 -0
  88. package/lib/chain/regen/interface.js.map +1 -1
  89. package/lib/chain/regen/queued.d.ts +11 -6
  90. package/lib/chain/regen/queued.d.ts.map +1 -1
  91. package/lib/chain/regen/queued.js +40 -8
  92. package/lib/chain/regen/queued.js.map +1 -1
  93. package/lib/chain/regen/regen.d.ts +5 -0
  94. package/lib/chain/regen/regen.d.ts.map +1 -1
  95. package/lib/chain/regen/regen.js +33 -6
  96. package/lib/chain/regen/regen.js.map +1 -1
  97. package/lib/chain/seenCache/index.d.ts +1 -1
  98. package/lib/chain/seenCache/index.d.ts.map +1 -1
  99. package/lib/chain/seenCache/index.js +1 -1
  100. package/lib/chain/seenCache/index.js.map +1 -1
  101. package/lib/chain/seenCache/seenGossipBlockInput.js +2 -2
  102. package/lib/chain/seenCache/seenGossipBlockInput.js.map +1 -1
  103. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +38 -0
  104. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -0
  105. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +76 -0
  106. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -0
  107. package/lib/chain/stateCache/datastore/db.d.ts +4 -5
  108. package/lib/chain/stateCache/datastore/db.d.ts.map +1 -1
  109. package/lib/chain/stateCache/datastore/db.js +32 -10
  110. package/lib/chain/stateCache/datastore/db.js.map +1 -1
  111. package/lib/chain/stateCache/datastore/file.d.ts +1 -1
  112. package/lib/chain/stateCache/datastore/file.d.ts.map +1 -1
  113. package/lib/chain/stateCache/datastore/file.js +5 -5
  114. package/lib/chain/stateCache/datastore/file.js.map +1 -1
  115. package/lib/chain/stateCache/datastore/types.d.ts +1 -1
  116. package/lib/chain/stateCache/datastore/types.d.ts.map +1 -1
  117. package/lib/chain/stateCache/fifoBlockStateCache.d.ts +7 -4
  118. package/lib/chain/stateCache/fifoBlockStateCache.d.ts.map +1 -1
  119. package/lib/chain/stateCache/fifoBlockStateCache.js +8 -3
  120. package/lib/chain/stateCache/fifoBlockStateCache.js.map +1 -1
  121. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts +33 -14
  122. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
  123. package/lib/chain/stateCache/persistentCheckpointsCache.js +217 -119
  124. package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
  125. package/lib/chain/stateCache/types.d.ts +15 -8
  126. package/lib/chain/stateCache/types.d.ts.map +1 -1
  127. package/lib/chain/stateCache/types.js.map +1 -1
  128. package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -1
  129. package/lib/chain/validation/executionPayloadEnvelope.js +30 -19
  130. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  131. package/lib/chain/validation/lightClientFinalityUpdate.js +1 -1
  132. package/lib/chain/validation/lightClientFinalityUpdate.js.map +1 -1
  133. package/lib/chain/validation/lightClientOptimisticUpdate.js +1 -1
  134. package/lib/chain/validation/lightClientOptimisticUpdate.js.map +1 -1
  135. package/lib/chain/validation/syncCommittee.d.ts +2 -2
  136. package/lib/chain/validation/syncCommittee.d.ts.map +1 -1
  137. package/lib/chain/validation/syncCommittee.js +12 -11
  138. package/lib/chain/validation/syncCommittee.js.map +1 -1
  139. package/lib/chain/validation/voluntaryExit.d.ts.map +1 -1
  140. package/lib/chain/validation/voluntaryExit.js +2 -2
  141. package/lib/chain/validation/voluntaryExit.js.map +1 -1
  142. package/lib/chain/validatorMonitor.d.ts +2 -1
  143. package/lib/chain/validatorMonitor.d.ts.map +1 -1
  144. package/lib/chain/validatorMonitor.js +4 -1
  145. package/lib/chain/validatorMonitor.js.map +1 -1
  146. package/lib/execution/engine/interface.d.ts +2 -2
  147. package/lib/metrics/metrics/lodestar.d.ts +40 -4
  148. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  149. package/lib/metrics/metrics/lodestar.js +93 -15
  150. package/lib/metrics/metrics/lodestar.js.map +1 -1
  151. package/lib/network/gossip/encoding.d.ts.map +1 -1
  152. package/lib/network/gossip/encoding.js +15 -0
  153. package/lib/network/gossip/encoding.js.map +1 -1
  154. package/lib/network/interface.d.ts +1 -1
  155. package/lib/network/interface.d.ts.map +1 -1
  156. package/lib/network/network.d.ts +1 -1
  157. package/lib/network/network.d.ts.map +1 -1
  158. package/lib/network/network.js +4 -4
  159. package/lib/network/network.js.map +1 -1
  160. package/lib/network/processor/extractSlotRootFns.d.ts +1 -1
  161. package/lib/network/processor/extractSlotRootFns.d.ts.map +1 -1
  162. package/lib/network/processor/extractSlotRootFns.js +15 -5
  163. package/lib/network/processor/extractSlotRootFns.js.map +1 -1
  164. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  165. package/lib/network/processor/gossipHandlers.js +39 -9
  166. package/lib/network/processor/gossipHandlers.js.map +1 -1
  167. package/lib/network/processor/index.d.ts +12 -7
  168. package/lib/network/processor/index.d.ts.map +1 -1
  169. package/lib/network/processor/index.js +99 -78
  170. package/lib/network/processor/index.js.map +1 -1
  171. package/lib/network/reqresp/ReqRespBeaconNode.d.ts +1 -1
  172. package/lib/network/reqresp/ReqRespBeaconNode.js +1 -1
  173. package/lib/sync/backfill/backfill.d.ts +1 -1
  174. package/lib/sync/backfill/backfill.js +1 -1
  175. package/lib/sync/constants.d.ts +1 -1
  176. package/lib/sync/constants.js +1 -1
  177. package/lib/sync/unknownBlock.d.ts +3 -9
  178. package/lib/sync/unknownBlock.d.ts.map +1 -1
  179. package/lib/sync/unknownBlock.js +8 -41
  180. package/lib/sync/unknownBlock.js.map +1 -1
  181. package/lib/util/sszBytes.d.ts +4 -1
  182. package/lib/util/sszBytes.d.ts.map +1 -1
  183. package/lib/util/sszBytes.js +69 -12
  184. package/lib/util/sszBytes.js.map +1 -1
  185. package/package.json +15 -15
  186. package/src/api/impl/beacon/blocks/index.ts +36 -17
  187. package/src/api/impl/beacon/state/utils.ts +2 -2
  188. package/src/api/impl/validator/index.ts +8 -4
  189. package/src/chain/archiveStore/archiveStore.ts +0 -10
  190. package/src/chain/archiveStore/interface.ts +4 -4
  191. package/src/chain/archiveStore/strategies/frequencyStateArchiveStrategy.ts +8 -5
  192. package/src/chain/archiveStore/utils/archiveBlocks.ts +59 -1
  193. package/src/chain/blocks/blockInput/types.ts +4 -3
  194. package/src/chain/blocks/importBlock.ts +47 -8
  195. package/src/chain/blocks/importExecutionPayload.ts +241 -0
  196. package/src/chain/blocks/payloadEnvelopeInput/index.ts +2 -0
  197. package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +336 -0
  198. package/src/chain/blocks/payloadEnvelopeInput/types.ts +33 -0
  199. package/src/chain/blocks/payloadEnvelopeProcessor.ts +61 -0
  200. package/src/chain/blocks/types.ts +8 -0
  201. package/src/chain/blocks/verifyBlocksSignatures.ts +1 -1
  202. package/src/chain/blocks/writePayloadEnvelopeInputToDb.ts +55 -0
  203. package/src/chain/chain.ts +60 -15
  204. package/src/chain/errors/executionPayloadEnvelope.ts +6 -2
  205. package/src/chain/forkChoice/index.ts +0 -10
  206. package/src/chain/interface.ts +8 -5
  207. package/src/chain/opPools/utils.ts +1 -1
  208. package/src/chain/prepareNextSlot.ts +6 -2
  209. package/src/chain/produceBlock/computeNewStateRoot.ts +6 -1
  210. package/src/chain/produceBlock/produceBlockBody.ts +1 -1
  211. package/src/chain/regen/errors.ts +6 -1
  212. package/src/chain/regen/interface.ts +14 -6
  213. package/src/chain/regen/queued.ts +48 -12
  214. package/src/chain/regen/regen.ts +37 -7
  215. package/src/chain/seenCache/index.ts +1 -1
  216. package/src/chain/seenCache/seenGossipBlockInput.ts +2 -2
  217. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +106 -0
  218. package/src/chain/stateCache/datastore/db.ts +33 -10
  219. package/src/chain/stateCache/datastore/file.ts +6 -5
  220. package/src/chain/stateCache/datastore/types.ts +3 -2
  221. package/src/chain/stateCache/fifoBlockStateCache.ts +10 -4
  222. package/src/chain/stateCache/persistentCheckpointsCache.ts +248 -139
  223. package/src/chain/stateCache/types.ts +18 -8
  224. package/src/chain/validation/executionPayloadEnvelope.ts +38 -25
  225. package/src/chain/validation/lightClientFinalityUpdate.ts +1 -1
  226. package/src/chain/validation/lightClientOptimisticUpdate.ts +1 -1
  227. package/src/chain/validation/syncCommittee.ts +15 -14
  228. package/src/chain/validation/voluntaryExit.ts +2 -1
  229. package/src/chain/validatorMonitor.ts +11 -1
  230. package/src/execution/engine/interface.ts +2 -2
  231. package/src/metrics/metrics/lodestar.ts +100 -19
  232. package/src/network/gossip/encoding.ts +16 -0
  233. package/src/network/interface.ts +1 -1
  234. package/src/network/network.ts +4 -4
  235. package/src/network/processor/extractSlotRootFns.ts +19 -6
  236. package/src/network/processor/gossipHandlers.ts +45 -8
  237. package/src/network/processor/index.ts +110 -89
  238. package/src/network/reqresp/ReqRespBeaconNode.ts +1 -1
  239. package/src/sync/backfill/backfill.ts +1 -1
  240. package/src/sync/constants.ts +1 -1
  241. package/src/sync/unknownBlock.ts +10 -50
  242. package/src/util/sszBytes.ts +90 -10
  243. package/lib/chain/archiveStore/utils/archivePayloads.d.ts +0 -7
  244. package/lib/chain/archiveStore/utils/archivePayloads.d.ts.map +0 -1
  245. package/lib/chain/archiveStore/utils/archivePayloads.js +0 -10
  246. package/lib/chain/archiveStore/utils/archivePayloads.js.map +0 -1
  247. package/lib/chain/seenCache/seenExecutionPayloadEnvelope.d.ts +0 -15
  248. package/lib/chain/seenCache/seenExecutionPayloadEnvelope.d.ts.map +0 -1
  249. package/lib/chain/seenCache/seenExecutionPayloadEnvelope.js +0 -28
  250. package/lib/chain/seenCache/seenExecutionPayloadEnvelope.js.map +0 -1
  251. package/src/chain/archiveStore/utils/archivePayloads.ts +0 -15
  252. package/src/chain/seenCache/seenExecutionPayloadEnvelope.ts +0 -34
@@ -1,4 +1,4 @@
1
- import {CheckpointWithHex} from "@lodestar/fork-choice";
1
+ import {CheckpointWithPayloadStatus} from "@lodestar/fork-choice";
2
2
  import {SLOTS_PER_EPOCH} from "@lodestar/params";
3
3
  import {computeEpochAtSlot, computeStartSlotAtEpoch} from "@lodestar/state-transition";
4
4
  import {Epoch, RootHex, Slot} from "@lodestar/types";
@@ -9,6 +9,7 @@ import {AllocSource, BufferPool} from "../../../util/bufferPool.js";
9
9
  import {getStateSlotFromBytes} from "../../../util/multifork.js";
10
10
  import {IStateRegenerator} from "../../regen/interface.js";
11
11
  import {serializeState} from "../../serializeState.js";
12
+ import {fcCheckpointToHexPayload} from "../../stateCache/persistentCheckpointsCache.js";
12
13
  import {StateArchiveStrategy, StatesArchiveOpts} from "../interface.js";
13
14
 
14
15
  /**
@@ -40,7 +41,7 @@ export class FrequencyStateArchiveStrategy implements StateArchiveStrategy {
40
41
  private readonly bufferPool?: BufferPool | null
41
42
  ) {}
42
43
 
43
- async onFinalizedCheckpoint(_finalized: CheckpointWithHex, _metrics?: Metrics | null): Promise<void> {}
44
+ async onFinalizedCheckpoint(_finalized: CheckpointWithPayloadStatus, _metrics?: Metrics | null): Promise<void> {}
44
45
  async onCheckpoint(_stateRoot: RootHex, _metrics?: Metrics | null): Promise<void> {}
45
46
 
46
47
  /**
@@ -55,7 +56,7 @@ export class FrequencyStateArchiveStrategy implements StateArchiveStrategy {
55
56
  * epoch - 1024*2 epoch - 1024 epoch - 32 epoch
56
57
  * ```
57
58
  */
58
- async maybeArchiveState(finalized: CheckpointWithHex, metrics?: Metrics | null): Promise<void> {
59
+ async maybeArchiveState(finalized: CheckpointWithPayloadStatus, metrics?: Metrics | null): Promise<void> {
59
60
  let timer = metrics?.processFinalizedCheckpoint.frequencyStateArchive.startTimer();
60
61
  const lastStoredSlot = await this.db.stateArchive.lastKey();
61
62
  timer?.({step: FrequencyStateArchiveStep.LoadLastStoredSlot});
@@ -104,10 +105,12 @@ export class FrequencyStateArchiveStrategy implements StateArchiveStrategy {
104
105
  * Archives finalized states from active bucket to archive bucket.
105
106
  * Only the new finalized state is stored to disk
106
107
  */
107
- async archiveState(finalized: CheckpointWithHex, metrics?: Metrics | null): Promise<void> {
108
+ async archiveState(finalized: CheckpointWithPayloadStatus, metrics?: Metrics | null): Promise<void> {
108
109
  // starting from Mar 2024, the finalized state could be from disk or in memory
109
110
  let timer = metrics?.processFinalizedCheckpoint.frequencyStateArchive.startTimer();
110
- const finalizedStateOrBytes = await this.regen.getCheckpointStateOrBytes(finalized);
111
+ // Convert fork-choice checkpoint to beacon-node checkpoint with payloadPresent
112
+ const finalizedHexPayload = fcCheckpointToHexPayload(finalized);
113
+ const finalizedStateOrBytes = await this.regen.getCheckpointStateOrBytes(finalizedHexPayload);
111
114
  timer?.({step: FrequencyStateArchiveStep.GetFinalizedState});
112
115
 
113
116
  const {rootHex} = finalized;
@@ -1,7 +1,7 @@
1
1
  import path from "node:path";
2
2
  import {ChainForkConfig} from "@lodestar/config";
3
3
  import {KeyValue} from "@lodestar/db";
4
- import {CheckpointWithPayloadStatus, IForkChoice} from "@lodestar/fork-choice";
4
+ import {CheckpointWithPayloadStatus, IForkChoice, PayloadStatus, ProtoBlock} from "@lodestar/fork-choice";
5
5
  import {ForkSeq, SLOTS_PER_EPOCH} from "@lodestar/params";
6
6
  import {computeEpochAtSlot, computeStartSlotAtEpoch} from "@lodestar/state-transition";
7
7
  import {Epoch, Slot} from "@lodestar/types";
@@ -66,6 +66,7 @@ export async function archiveBlocks(
66
66
  // NOTE: The finalized block will be exactly the first block of `epoch` or previous
67
67
  const finalizedPostDeneb = finalizedCheckpoint.epoch >= config.DENEB_FORK_EPOCH;
68
68
  const finalizedPostFulu = finalizedCheckpoint.epoch >= config.FULU_FORK_EPOCH;
69
+ const finalizedPostGloas = finalizedCheckpoint.epoch >= config.GLOAS_FORK_EPOCH;
69
70
 
70
71
  const finalizedCanonicalBlockRoots: BlockRootSlot[] = finalizedCanonicalBlocks.map((block) => ({
71
72
  slot: block.slot,
@@ -103,6 +104,16 @@ export async function archiveBlocks(
103
104
  );
104
105
  logger.verbose("Migrated dataColumnSidecars from hot DB to cold DB", {...logCtx, migratedEntries});
105
106
  }
107
+
108
+ if (finalizedPostGloas) {
109
+ const migratedEntries = await migrateExecutionPayloadEnvelopesFromHotToColdDb(
110
+ config,
111
+ db,
112
+ logger,
113
+ finalizedCanonicalBlocks
114
+ );
115
+ logger.verbose("Migrated executionPayloadEnvelopes from hot DB to cold DB", {...logCtx, migratedEntries});
116
+ }
106
117
  }
107
118
 
108
119
  // deleteNonCanonicalBlocks
@@ -144,6 +155,11 @@ export async function archiveBlocks(
144
155
  await db.dataColumnSidecar.deleteMany(nonCanonicalBlockRoots);
145
156
  logger.verbose("Deleted non canonical dataColumnSidecars from hot DB", logCtx);
146
157
  }
158
+
159
+ if (finalizedPostGloas) {
160
+ await db.executionPayloadEnvelope.batchDelete(nonCanonicalBlockRoots);
161
+ logger.verbose("Deleted non canonical executionPayloadEnvelopes from hot DB", logCtx);
162
+ }
147
163
  }
148
164
 
149
165
  // Delete expired blobs
@@ -372,6 +388,48 @@ async function migrateDataColumnSidecarsFromHotToColdDb(
372
388
  return migratedWrappedDataColumns;
373
389
  }
374
390
 
391
+ async function migrateExecutionPayloadEnvelopesFromHotToColdDb(
392
+ config: ChainForkConfig,
393
+ db: IBeaconDb,
394
+ logger: Logger,
395
+ canonicalBlocks: ProtoBlock[]
396
+ ): Promise<number> {
397
+ let migratedEnvelopes = 0;
398
+
399
+ const payloadBlocks = canonicalBlocks.filter(
400
+ (block) => config.getForkSeq(block.slot) >= ForkSeq.gloas && block.payloadStatus === PayloadStatus.FULL
401
+ );
402
+ if (payloadBlocks.length === 0) return 0;
403
+ const blocks = payloadBlocks.map((block) => ({slot: block.slot, root: fromHex(block.blockRoot)}));
404
+
405
+ const envelopeEntries: KeyValue<Slot, Uint8Array>[] = [];
406
+ const migratedRoots: Uint8Array[] = [];
407
+
408
+ const envelopeBytesArray = await Promise.all(
409
+ blocks.map((block) => db.executionPayloadEnvelope.getBinary(block.root))
410
+ );
411
+
412
+ for (let i = 0; i < blocks.length; i++) {
413
+ const bytes = envelopeBytesArray[i];
414
+ if (bytes !== null) {
415
+ envelopeEntries.push({key: blocks[i].slot, value: bytes});
416
+ migratedRoots.push(blocks[i].root);
417
+ } else {
418
+ logger.debug("Payload in forkchoice but missing in db", {slot: blocks[i].slot, root: toRootHex(blocks[i].root)});
419
+ }
420
+ }
421
+
422
+ if (envelopeEntries.length > 0) {
423
+ await Promise.all([
424
+ db.executionPayloadEnvelopeArchive.batchPutBinary(envelopeEntries),
425
+ db.executionPayloadEnvelope.batchDelete(migratedRoots),
426
+ ]);
427
+ migratedEnvelopes = envelopeEntries.length;
428
+ }
429
+
430
+ return migratedEnvelopes;
431
+ }
432
+
375
433
  /**
376
434
  * ```
377
435
  * class SignedBeaconBlock(Container):
@@ -1,5 +1,5 @@
1
1
  import {ForkName} from "@lodestar/params";
2
- import {ColumnIndex, RootHex, SignedBeaconBlock, Slot, deneb, fulu} from "@lodestar/types";
2
+ import {ColumnIndex, DataColumnSidecars, RootHex, SignedBeaconBlock, Slot, deneb, fulu} from "@lodestar/types";
3
3
  import {VersionedHashes} from "../../../execution/index.js";
4
4
 
5
5
  export enum DAType {
@@ -16,6 +16,7 @@ export type DAData = null | deneb.BlobSidecars | fulu.DataColumnSidecars;
16
16
  * sources so each should be labelled individually.
17
17
  */
18
18
  export enum BlockInputSource {
19
+ network_processor = "network_processor",
19
20
  gossip = "gossip",
20
21
  api = "api",
21
22
  engine = "engine",
@@ -107,9 +108,9 @@ export type MissingColumnMeta = {
107
108
  export interface IDataColumnsInput {
108
109
  readonly slot: Slot;
109
110
  readonly blockRootHex: string;
110
- getCustodyColumns(): fulu.DataColumnSidecars;
111
+ getCustodyColumns(): DataColumnSidecars;
111
112
  hasComputedAllData(): boolean;
112
- waitForComputedAllData(timeout: number, signal?: AbortSignal): Promise<fulu.DataColumnSidecars>;
113
+ waitForComputedAllData(timeout: number, signal?: AbortSignal): Promise<DataColumnSidecars>;
113
114
  }
114
115
 
115
116
  /**
@@ -7,8 +7,16 @@ import {
7
7
  ForkChoiceErrorCode,
8
8
  NotReorgedReason,
9
9
  getSafeExecutionBlockHash,
10
+ isGloasBlock,
10
11
  } from "@lodestar/fork-choice";
11
- import {ForkPostAltair, ForkPostElectra, ForkSeq, MAX_SEED_LOOKAHEAD, SLOTS_PER_EPOCH} from "@lodestar/params";
12
+ import {
13
+ ForkPostAltair,
14
+ ForkPostElectra,
15
+ ForkPostGloas,
16
+ ForkSeq,
17
+ MAX_SEED_LOOKAHEAD,
18
+ SLOTS_PER_EPOCH,
19
+ } from "@lodestar/params";
12
20
  import {
13
21
  CachedBeaconStateAltair,
14
22
  EpochCache,
@@ -20,7 +28,17 @@ import {
20
28
  isStartSlotOfEpoch,
21
29
  isStateValidatorsNodesPopulated,
22
30
  } from "@lodestar/state-transition";
23
- import {Attestation, BeaconBlock, altair, capella, electra, isGloasBeaconBlock, phase0, ssz} from "@lodestar/types";
31
+ import {
32
+ Attestation,
33
+ BeaconBlock,
34
+ SignedBeaconBlock,
35
+ altair,
36
+ capella,
37
+ electra,
38
+ isGloasBeaconBlock,
39
+ phase0,
40
+ ssz,
41
+ } from "@lodestar/types";
24
42
  import {isErrorAborted, toRootHex} from "@lodestar/utils";
25
43
  import {ZERO_HASH_HEX} from "../../constants/index.js";
26
44
  import {callInNextEventLoop} from "../../util/eventLoop.js";
@@ -30,7 +48,7 @@ import type {BeaconChain} from "../chain.js";
30
48
  import {ChainEvent, ReorgEventData} from "../emitter.js";
31
49
  import {ForkchoiceCaller} from "../forkChoice/index.js";
32
50
  import {REPROCESS_MIN_TIME_TO_NEXT_SLOT_SEC} from "../reprocess.js";
33
- import {toCheckpointHex} from "../stateCache/persistentCheckpointsCache.js";
51
+ import {toCheckpointHexPayload} from "../stateCache/persistentCheckpointsCache.js";
34
52
  import {isBlockInputBlobs, isBlockInputColumns} from "./blockInput/blockInput.js";
35
53
  import {AttestationImportOpt, FullyVerifiedBlock, ImportBlockOpts} from "./types.js";
36
54
  import {getCheckpointFromState} from "./utils/checkpoint.js";
@@ -116,7 +134,28 @@ export async function importBlock(
116
134
 
117
135
  // This adds the state necessary to process the next block
118
136
  // Some block event handlers require state being in state cache so need to do this before emitting EventType.block
119
- this.regen.processState(blockRootHex, postState);
137
+ // Pre-Gloas: blockSummary.payloadStatus is always FULL, payloadPresent = true
138
+ // Post-Gloas: blockSummary.payloadStatus is always PENDING, so payloadPresent = false (block state only, no payload processing yet)
139
+ const payloadPresent = !isGloasBlock(blockSummary);
140
+ // processState manages both block state and payload state variants together for memory/disk management
141
+ this.regen.processBlockState(blockRootHex, postState);
142
+
143
+ // For Gloas blocks, create PayloadEnvelopeInput so it's available for later payload import
144
+ if (fork >= ForkSeq.gloas) {
145
+ this.seenPayloadEnvelopeInputCache.add({
146
+ blockRootHex,
147
+ block: block as SignedBeaconBlock<ForkPostGloas>,
148
+ sampledColumns: this.custodyConfig.sampledColumns,
149
+ custodyColumns: this.custodyConfig.custodyColumns,
150
+ timeCreatedSec: fullyVerifiedBlock.seenTimestampSec,
151
+ });
152
+ this.logger.debug("Created PayloadEnvelopeInput for block", {
153
+ slot: blockSlot,
154
+ root: blockRootHex,
155
+ source: source.source,
156
+ ...(opts.seenTimestampSec !== undefined ? {recvToImport: Date.now() / 1000 - opts.seenTimestampSec} : {}),
157
+ });
158
+ }
120
159
 
121
160
  this.metrics?.importBlock.bySource.inc({source: source.source});
122
161
  this.logger.verbose("Added block to forkchoice and state cache", {slot: blockSlot, root: blockRootHex});
@@ -456,12 +495,12 @@ export async function importBlock(
456
495
  // Cache state to preserve epoch transition work
457
496
  const checkpointState = postState;
458
497
  const cp = getCheckpointFromState(checkpointState);
459
- this.regen.addCheckpointState(cp, checkpointState);
498
+ this.regen.addCheckpointState(cp, checkpointState, payloadPresent);
460
499
  // consumers should not mutate state ever
461
500
  this.emitter.emit(ChainEvent.checkpoint, cp, checkpointState);
462
501
 
463
502
  // Note: in-lined code from previos handler of ChainEvent.checkpoint
464
- this.logger.verbose("Checkpoint processed", toCheckpointHex(cp));
503
+ this.logger.verbose("Checkpoint processed", toCheckpointHexPayload(cp, payloadPresent));
465
504
 
466
505
  const activeValidatorsCount = checkpointState.epochCtx.currentShuffling.activeIndices.length;
467
506
  this.metrics?.currentActiveValidators.set(activeValidatorsCount);
@@ -479,7 +518,7 @@ export async function importBlock(
479
518
  const justifiedEpoch = justifiedCheckpoint.epoch;
480
519
  const preJustifiedEpoch = parentBlockSummary.justifiedEpoch;
481
520
  if (justifiedEpoch > preJustifiedEpoch) {
482
- this.logger.verbose("Checkpoint justified", toCheckpointHex(justifiedCheckpoint));
521
+ this.logger.verbose("Checkpoint justified", toCheckpointHexPayload(justifiedCheckpoint, payloadPresent));
483
522
  this.metrics?.previousJustifiedEpoch.set(checkpointState.previousJustifiedCheckpoint.epoch);
484
523
  this.metrics?.currentJustifiedEpoch.set(justifiedCheckpoint.epoch);
485
524
  }
@@ -493,7 +532,7 @@ export async function importBlock(
493
532
  state: toRootHex(checkpointState.hashTreeRoot()),
494
533
  executionOptimistic: false,
495
534
  });
496
- this.logger.verbose("Checkpoint finalized", toCheckpointHex(finalizedCheckpoint));
535
+ this.logger.verbose("Checkpoint finalized", toCheckpointHexPayload(finalizedCheckpoint, payloadPresent));
497
536
  this.metrics?.finalizedEpoch.set(finalizedCheckpoint.epoch);
498
537
  }
499
538
  }
@@ -0,0 +1,241 @@
1
+ import {routes} from "@lodestar/api";
2
+ import {ForkName} from "@lodestar/params";
3
+ import {
4
+ BeaconStateView,
5
+ CachedBeaconStateGloas,
6
+ getExecutionPayloadEnvelopeSignatureSet,
7
+ } from "@lodestar/state-transition";
8
+ import {processExecutionPayloadEnvelope} from "@lodestar/state-transition/block";
9
+ import {byteArrayEquals, fromHex, toRootHex} from "@lodestar/utils";
10
+ import {ExecutionPayloadStatus} from "../../execution/index.js";
11
+ import {isQueueErrorAborted} from "../../util/queue/index.js";
12
+ import {BeaconChain} from "../chain.js";
13
+ import {RegenCaller} from "../regen/interface.js";
14
+ import {PayloadEnvelopeInput} from "../seenCache/seenPayloadEnvelopeInput.js";
15
+ import {ImportPayloadOpts} from "./types.js";
16
+
17
+ const EVENTSTREAM_EMIT_RECENT_EXECUTION_PAYLOAD_SLOTS = 64;
18
+
19
+ export enum PayloadErrorCode {
20
+ EXECUTION_ENGINE_INVALID = "PAYLOAD_ERROR_EXECUTION_ENGINE_INVALID",
21
+ EXECUTION_ENGINE_ERROR = "PAYLOAD_ERROR_EXECUTION_ENGINE_ERROR",
22
+ BLOCK_NOT_IN_FORK_CHOICE = "PAYLOAD_ERROR_BLOCK_NOT_IN_FORK_CHOICE",
23
+ STATE_TRANSITION_ERROR = "PAYLOAD_ERROR_STATE_TRANSITION_ERROR",
24
+ INVALID_SIGNATURE = "PAYLOAD_ERROR_INVALID_SIGNATURE",
25
+ }
26
+
27
+ export type PayloadErrorType =
28
+ | {
29
+ code: PayloadErrorCode.EXECUTION_ENGINE_INVALID;
30
+ execStatus: ExecutionPayloadStatus;
31
+ errorMessage: string;
32
+ }
33
+ | {
34
+ code: PayloadErrorCode.EXECUTION_ENGINE_ERROR;
35
+ execStatus: ExecutionPayloadStatus;
36
+ errorMessage: string;
37
+ }
38
+ | {
39
+ code: PayloadErrorCode.BLOCK_NOT_IN_FORK_CHOICE;
40
+ blockRootHex: string;
41
+ }
42
+ | {
43
+ code: PayloadErrorCode.STATE_TRANSITION_ERROR;
44
+ message: string;
45
+ }
46
+ | {
47
+ code: PayloadErrorCode.INVALID_SIGNATURE;
48
+ };
49
+
50
+ export class PayloadError extends Error {
51
+ type: PayloadErrorType;
52
+
53
+ constructor(type: PayloadErrorType, message?: string) {
54
+ super(message ?? type.code);
55
+ this.type = type;
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Import an execution payload envelope after all data is available.
61
+ *
62
+ * This function:
63
+ * 1. Gets the ProtoBlock from fork choice
64
+ * 2. Applies write-queue backpressure (waitForSpace) early, before verification
65
+ * 3. Regenerates the block state
66
+ * 4. Runs EL verification (notifyNewPayload) in parallel with signature verification and processExecutionPayloadEnvelope
67
+ * 5. Persists verified payload envelope to hot DB
68
+ * 6. Updates fork choice
69
+ * 7. Caches the post-execution payload state
70
+ * 8. Records metrics for column sources
71
+ *
72
+ */
73
+ export async function importExecutionPayload(
74
+ this: BeaconChain,
75
+ payloadInput: PayloadEnvelopeInput,
76
+ opts: ImportPayloadOpts = {}
77
+ ): Promise<void> {
78
+ const envelope = payloadInput.getPayloadEnvelope();
79
+ const blockRootHex = payloadInput.blockRootHex;
80
+
81
+ // 1. Get ProtoBlock for parent root lookup
82
+ const protoBlock = this.forkChoice.getBlockHexDefaultStatus(blockRootHex);
83
+ if (!protoBlock) {
84
+ throw new PayloadError({
85
+ code: PayloadErrorCode.BLOCK_NOT_IN_FORK_CHOICE,
86
+ blockRootHex,
87
+ });
88
+ }
89
+
90
+ // 2. Apply backpressure from the write queue early, before doing verification work.
91
+ // The actual DB write is deferred until after verification succeeds.
92
+ await this.unfinalizedPayloadEnvelopeWrites.waitForSpace();
93
+
94
+ // 3. Get pre-state for processExecutionPayloadEnvelope
95
+ // We need the block state (post-block, pre-payload) to process the envelope
96
+ const blockState = (await this.regen.getBlockSlotState(
97
+ protoBlock,
98
+ protoBlock.slot,
99
+ {dontTransferCache: true},
100
+ RegenCaller.processBlock
101
+ )) as CachedBeaconStateGloas;
102
+
103
+ // 4. Run verification steps in parallel
104
+ // Note: No data availability check needed here - importExecutionPayload is only
105
+ // called when payloadInput.isComplete() is true, so all data is already available.
106
+ const [execResult, signatureValid, postPayloadResult] = await Promise.all([
107
+ this.executionEngine.notifyNewPayload(
108
+ ForkName.gloas,
109
+ envelope.message.payload,
110
+ payloadInput.getVersionedHashes(),
111
+ fromHex(protoBlock.parentRoot),
112
+ envelope.message.executionRequests
113
+ ),
114
+
115
+ opts.validSignature === true
116
+ ? Promise.resolve(true)
117
+ : (async () => {
118
+ const signatureSet = getExecutionPayloadEnvelopeSignatureSet(
119
+ this.config,
120
+ blockState.epochCtx.pubkeyCache,
121
+ new BeaconStateView(blockState),
122
+ envelope,
123
+ payloadInput.proposerIndex
124
+ );
125
+ return this.bls.verifySignatureSets([signatureSet]);
126
+ })(),
127
+
128
+ // Signature verified separately above.
129
+ // State root check is done separately below with better error typing (matching block pipeline pattern).
130
+ (async () => {
131
+ try {
132
+ return {
133
+ postPayloadState: processExecutionPayloadEnvelope(blockState, envelope, {
134
+ verifySignature: false,
135
+ verifyStateRoot: false,
136
+ }),
137
+ };
138
+ } catch (e) {
139
+ throw new PayloadError(
140
+ {
141
+ code: PayloadErrorCode.STATE_TRANSITION_ERROR,
142
+ message: (e as Error).message,
143
+ },
144
+ `State transition error: ${(e as Error).message}`
145
+ );
146
+ }
147
+ })(),
148
+ ]);
149
+
150
+ // 4b. Check signature verification result
151
+ if (!signatureValid) {
152
+ throw new PayloadError({code: PayloadErrorCode.INVALID_SIGNATURE});
153
+ }
154
+
155
+ // 5. Handle EL response
156
+ switch (execResult.status) {
157
+ case ExecutionPayloadStatus.VALID:
158
+ break;
159
+
160
+ case ExecutionPayloadStatus.INVALID:
161
+ throw new PayloadError({
162
+ code: PayloadErrorCode.EXECUTION_ENGINE_INVALID,
163
+ execStatus: execResult.status,
164
+ errorMessage: execResult.validationError ?? "",
165
+ });
166
+
167
+ case ExecutionPayloadStatus.ACCEPTED:
168
+ case ExecutionPayloadStatus.SYNCING:
169
+ // TODO GLOAS: Handle optimistic import for payload - for now treat as error
170
+ throw new PayloadError({
171
+ code: PayloadErrorCode.EXECUTION_ENGINE_ERROR,
172
+ execStatus: execResult.status,
173
+ errorMessage: execResult.validationError ?? "EL syncing, payload not yet validated",
174
+ });
175
+
176
+ case ExecutionPayloadStatus.INVALID_BLOCK_HASH:
177
+ case ExecutionPayloadStatus.ELERROR:
178
+ case ExecutionPayloadStatus.UNAVAILABLE:
179
+ throw new PayloadError({
180
+ code: PayloadErrorCode.EXECUTION_ENGINE_ERROR,
181
+ execStatus: execResult.status,
182
+ errorMessage: execResult.validationError ?? "",
183
+ });
184
+ }
185
+
186
+ // 5b. Verify envelope state root matches post-state
187
+ const postPayloadState = postPayloadResult.postPayloadState;
188
+ const postPayloadStateRoot = postPayloadState.hashTreeRoot();
189
+ if (!byteArrayEquals(envelope.message.stateRoot, postPayloadStateRoot)) {
190
+ throw new PayloadError({
191
+ code: PayloadErrorCode.STATE_TRANSITION_ERROR,
192
+ message: `Envelope state root mismatch expected=${toRootHex(envelope.message.stateRoot)} actual=${toRootHex(postPayloadStateRoot)}`,
193
+ });
194
+ }
195
+
196
+ // 5c. Persist payload envelope to hot DB (performed asynchronously to avoid blocking)
197
+ this.unfinalizedPayloadEnvelopeWrites.push(payloadInput).catch((e) => {
198
+ if (!isQueueErrorAborted(e)) {
199
+ this.logger.error(
200
+ "Error pushing payload envelope to unfinalized write queue",
201
+ {slot: payloadInput.slot, root: blockRootHex},
202
+ e as Error
203
+ );
204
+ }
205
+ });
206
+
207
+ // 6. Update fork choice
208
+ this.forkChoice.onExecutionPayload(
209
+ blockRootHex,
210
+ payloadInput.getBlockHashHex(),
211
+ envelope.message.payload.blockNumber,
212
+ toRootHex(postPayloadStateRoot)
213
+ );
214
+
215
+ // 7. Cache payload state
216
+ // TODO GLOAS: Enable when PR #8868 merged (adds processPayloadState)
217
+ // this.regen.processPayloadState(postPayloadState);
218
+ // if epoch boundary also call
219
+ // this.regen.addCheckpointState(cp, checkpointState, true);
220
+
221
+ // 8. Record metrics for payload envelope and column sources
222
+ this.metrics?.importPayload.bySource.inc({source: payloadInput.getPayloadEnvelopeSource().source});
223
+ for (const {source} of payloadInput.getSampledColumnsWithSource()) {
224
+ this.metrics?.importPayload.columnsBySource.inc({source});
225
+ }
226
+
227
+ this.logger.verbose("Execution payload imported", {
228
+ slot: payloadInput.slot,
229
+ root: blockRootHex,
230
+ blockHash: payloadInput.getBlockHashHex(),
231
+ });
232
+
233
+ // 9. Emit event after payload is fully verified and imported to fork choice, only for recent enough payloads
234
+ const currentSlot = this.clock.currentSlot;
235
+ if (currentSlot - payloadInput.slot < EVENTSTREAM_EMIT_RECENT_EXECUTION_PAYLOAD_SLOTS) {
236
+ this.emitter.emit(routes.events.EventType.executionPayloadAvailable, {
237
+ slot: payloadInput.slot,
238
+ blockRoot: blockRootHex,
239
+ });
240
+ }
241
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./payloadEnvelopeInput.js";
2
+ export * from "./types.js";