@lodestar/beacon-node 1.42.0-rc.0 → 1.43.0-dev.0bc48d3b54

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 (268) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +20 -0
  3. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  4. package/lib/api/impl/beacon/pool/index.d.ts.map +1 -1
  5. package/lib/api/impl/beacon/pool/index.js +4 -0
  6. package/lib/api/impl/beacon/pool/index.js.map +1 -1
  7. package/lib/api/impl/beacon/state/index.d.ts.map +1 -1
  8. package/lib/api/impl/beacon/state/index.js +13 -10
  9. package/lib/api/impl/beacon/state/index.js.map +1 -1
  10. package/lib/api/impl/lodestar/attesterSlashing.d.ts +8 -0
  11. package/lib/api/impl/lodestar/attesterSlashing.d.ts.map +1 -0
  12. package/lib/api/impl/lodestar/attesterSlashing.js +29 -0
  13. package/lib/api/impl/lodestar/attesterSlashing.js.map +1 -0
  14. package/lib/api/impl/lodestar/index.d.ts.map +1 -1
  15. package/lib/api/impl/lodestar/index.js +39 -0
  16. package/lib/api/impl/lodestar/index.js.map +1 -1
  17. package/lib/api/impl/validator/index.d.ts.map +1 -1
  18. package/lib/api/impl/validator/index.js +11 -4
  19. package/lib/api/impl/validator/index.js.map +1 -1
  20. package/lib/chain/GetBlobsTracker.d.ts +1 -1
  21. package/lib/chain/GetBlobsTracker.d.ts.map +1 -1
  22. package/lib/chain/GetBlobsTracker.js +1 -2
  23. package/lib/chain/GetBlobsTracker.js.map +1 -1
  24. package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.d.ts.map +1 -1
  25. package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.js +2 -4
  26. package/lib/chain/archiveStore/strategies/frequencyStateArchiveStrategy.js.map +1 -1
  27. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  28. package/lib/chain/blocks/importBlock.js +29 -35
  29. package/lib/chain/blocks/importBlock.js.map +1 -1
  30. package/lib/chain/blocks/importExecutionPayload.d.ts +1 -1
  31. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  32. package/lib/chain/blocks/importExecutionPayload.js +24 -13
  33. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  34. package/lib/chain/blocks/index.js +2 -2
  35. package/lib/chain/blocks/index.js.map +1 -1
  36. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +3 -0
  37. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
  38. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +20 -0
  39. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
  40. package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts +5 -0
  41. package/lib/chain/blocks/payloadEnvelopeProcessor.d.ts.map +1 -1
  42. package/lib/chain/blocks/payloadEnvelopeProcessor.js +6 -4
  43. package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
  44. package/lib/chain/blocks/types.d.ts +4 -4
  45. package/lib/chain/blocks/types.d.ts.map +1 -1
  46. package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts.map +1 -1
  47. package/lib/chain/blocks/verifyBlocksExecutionPayloads.js +3 -2
  48. package/lib/chain/blocks/verifyBlocksExecutionPayloads.js.map +1 -1
  49. package/lib/chain/blocks/verifyBlocksSignatures.d.ts.map +1 -1
  50. package/lib/chain/blocks/verifyBlocksSignatures.js +4 -2
  51. package/lib/chain/blocks/verifyBlocksSignatures.js.map +1 -1
  52. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts +14 -0
  53. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts.map +1 -0
  54. package/lib/chain/blocks/verifyPayloadsDataAvailability.js +25 -0
  55. package/lib/chain/blocks/verifyPayloadsDataAvailability.js.map +1 -0
  56. package/lib/chain/chain.d.ts +2 -1
  57. package/lib/chain/chain.d.ts.map +1 -1
  58. package/lib/chain/chain.js +30 -36
  59. package/lib/chain/chain.js.map +1 -1
  60. package/lib/chain/emitter.d.ts +13 -1
  61. package/lib/chain/emitter.d.ts.map +1 -1
  62. package/lib/chain/emitter.js +5 -0
  63. package/lib/chain/emitter.js.map +1 -1
  64. package/lib/chain/errors/attestationError.d.ts +8 -1
  65. package/lib/chain/errors/attestationError.d.ts.map +1 -1
  66. package/lib/chain/errors/attestationError.js +4 -0
  67. package/lib/chain/errors/attestationError.js.map +1 -1
  68. package/lib/chain/errors/blockError.d.ts +11 -1
  69. package/lib/chain/errors/blockError.d.ts.map +1 -1
  70. package/lib/chain/errors/blockError.js +4 -0
  71. package/lib/chain/errors/blockError.js.map +1 -1
  72. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  73. package/lib/chain/forkChoice/index.js +22 -12
  74. package/lib/chain/forkChoice/index.js.map +1 -1
  75. package/lib/chain/interface.d.ts +2 -1
  76. package/lib/chain/interface.d.ts.map +1 -1
  77. package/lib/chain/interface.js.map +1 -1
  78. package/lib/chain/lightClient/index.d.ts +2 -2
  79. package/lib/chain/lightClient/index.d.ts.map +1 -1
  80. package/lib/chain/lightClient/index.js +7 -0
  81. package/lib/chain/lightClient/index.js.map +1 -1
  82. package/lib/chain/opPools/aggregatedAttestationPool.d.ts.map +1 -1
  83. package/lib/chain/opPools/aggregatedAttestationPool.js +5 -2
  84. package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
  85. package/lib/chain/opPools/executionPayloadBidPool.d.ts +2 -2
  86. package/lib/chain/opPools/executionPayloadBidPool.d.ts.map +1 -1
  87. package/lib/chain/opPools/executionPayloadBidPool.js +2 -2
  88. package/lib/chain/opPools/executionPayloadBidPool.js.map +1 -1
  89. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  90. package/lib/chain/prepareNextSlot.js +22 -10
  91. package/lib/chain/prepareNextSlot.js.map +1 -1
  92. package/lib/chain/produceBlock/computeNewStateRoot.d.ts +1 -7
  93. package/lib/chain/produceBlock/computeNewStateRoot.d.ts.map +1 -1
  94. package/lib/chain/produceBlock/computeNewStateRoot.js +1 -28
  95. package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
  96. package/lib/chain/produceBlock/produceBlockBody.d.ts +5 -10
  97. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  98. package/lib/chain/produceBlock/produceBlockBody.js +46 -19
  99. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  100. package/lib/chain/regen/errors.d.ts +1 -11
  101. package/lib/chain/regen/errors.d.ts.map +1 -1
  102. package/lib/chain/regen/errors.js +0 -2
  103. package/lib/chain/regen/errors.js.map +1 -1
  104. package/lib/chain/regen/interface.d.ts +6 -12
  105. package/lib/chain/regen/interface.d.ts.map +1 -1
  106. package/lib/chain/regen/queued.d.ts +6 -11
  107. package/lib/chain/regen/queued.d.ts.map +1 -1
  108. package/lib/chain/regen/queued.js +8 -40
  109. package/lib/chain/regen/queued.js.map +1 -1
  110. package/lib/chain/regen/regen.d.ts +0 -5
  111. package/lib/chain/regen/regen.d.ts.map +1 -1
  112. package/lib/chain/regen/regen.js +7 -34
  113. package/lib/chain/regen/regen.js.map +1 -1
  114. package/lib/chain/stateCache/datastore/db.d.ts +5 -4
  115. package/lib/chain/stateCache/datastore/db.d.ts.map +1 -1
  116. package/lib/chain/stateCache/datastore/db.js +10 -32
  117. package/lib/chain/stateCache/datastore/db.js.map +1 -1
  118. package/lib/chain/stateCache/datastore/file.d.ts +1 -1
  119. package/lib/chain/stateCache/datastore/file.d.ts.map +1 -1
  120. package/lib/chain/stateCache/datastore/file.js +5 -5
  121. package/lib/chain/stateCache/datastore/file.js.map +1 -1
  122. package/lib/chain/stateCache/datastore/types.d.ts +1 -1
  123. package/lib/chain/stateCache/datastore/types.d.ts.map +1 -1
  124. package/lib/chain/stateCache/fifoBlockStateCache.d.ts +1 -7
  125. package/lib/chain/stateCache/fifoBlockStateCache.d.ts.map +1 -1
  126. package/lib/chain/stateCache/fifoBlockStateCache.js +0 -8
  127. package/lib/chain/stateCache/fifoBlockStateCache.js.map +1 -1
  128. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts +13 -30
  129. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
  130. package/lib/chain/stateCache/persistentCheckpointsCache.js +120 -216
  131. package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
  132. package/lib/chain/stateCache/types.d.ts +8 -15
  133. package/lib/chain/stateCache/types.d.ts.map +1 -1
  134. package/lib/chain/stateCache/types.js.map +1 -1
  135. package/lib/chain/validation/aggregateAndProof.js +12 -0
  136. package/lib/chain/validation/aggregateAndProof.js.map +1 -1
  137. package/lib/chain/validation/attestation.d.ts.map +1 -1
  138. package/lib/chain/validation/attestation.js +12 -0
  139. package/lib/chain/validation/attestation.js.map +1 -1
  140. package/lib/chain/validation/block.d.ts.map +1 -1
  141. package/lib/chain/validation/block.js +27 -5
  142. package/lib/chain/validation/block.js.map +1 -1
  143. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  144. package/lib/chain/validation/executionPayloadBid.js +7 -4
  145. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  146. package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -1
  147. package/lib/chain/validation/executionPayloadEnvelope.js +8 -3
  148. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  149. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
  150. package/lib/chain/validation/payloadAttestationMessage.js +8 -4
  151. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
  152. package/lib/chain/validation/syncCommittee.d.ts.map +1 -1
  153. package/lib/chain/validation/syncCommittee.js +4 -0
  154. package/lib/chain/validation/syncCommittee.js.map +1 -1
  155. package/lib/chain/validation/syncCommitteeContributionAndProof.js +4 -1
  156. package/lib/chain/validation/syncCommitteeContributionAndProof.js.map +1 -1
  157. package/lib/chain/validatorMonitor.d.ts.map +1 -1
  158. package/lib/chain/validatorMonitor.js +3 -3
  159. package/lib/chain/validatorMonitor.js.map +1 -1
  160. package/lib/execution/engine/http.d.ts.map +1 -1
  161. package/lib/execution/engine/http.js +21 -14
  162. package/lib/execution/engine/http.js.map +1 -1
  163. package/lib/execution/engine/interface.d.ts +1 -0
  164. package/lib/execution/engine/interface.d.ts.map +1 -1
  165. package/lib/execution/engine/mock.d.ts.map +1 -1
  166. package/lib/execution/engine/mock.js +3 -0
  167. package/lib/execution/engine/mock.js.map +1 -1
  168. package/lib/execution/engine/types.d.ts +20 -0
  169. package/lib/execution/engine/types.d.ts.map +1 -1
  170. package/lib/execution/engine/types.js +18 -0
  171. package/lib/execution/engine/types.js.map +1 -1
  172. package/lib/network/gossip/topic.d.ts +729 -0
  173. package/lib/network/gossip/topic.d.ts.map +1 -1
  174. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  175. package/lib/network/processor/gossipHandlers.js +23 -3
  176. package/lib/network/processor/gossipHandlers.js.map +1 -1
  177. package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
  178. package/lib/network/reqresp/handlers/beaconBlocksByRange.js +2 -1
  179. package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
  180. package/lib/network/reqresp/handlers/beaconBlocksByRoot.d.ts.map +1 -1
  181. package/lib/network/reqresp/handlers/beaconBlocksByRoot.js +2 -0
  182. package/lib/network/reqresp/handlers/beaconBlocksByRoot.js.map +1 -1
  183. package/lib/network/reqresp/handlers/blobSidecarsByRange.d.ts +2 -2
  184. package/lib/network/reqresp/handlers/blobSidecarsByRange.d.ts.map +1 -1
  185. package/lib/network/reqresp/handlers/blobSidecarsByRange.js +7 -3
  186. package/lib/network/reqresp/handlers/blobSidecarsByRange.js.map +1 -1
  187. package/lib/network/reqresp/handlers/blobSidecarsByRoot.d.ts.map +1 -1
  188. package/lib/network/reqresp/handlers/blobSidecarsByRoot.js +6 -0
  189. package/lib/network/reqresp/handlers/blobSidecarsByRoot.js.map +1 -1
  190. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts +2 -2
  191. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
  192. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +7 -3
  193. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
  194. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts.map +1 -1
  195. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js +2 -1
  196. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
  197. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.d.ts.map +1 -1
  198. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js +3 -8
  199. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js.map +1 -1
  200. package/lib/node/nodejs.d.ts.map +1 -1
  201. package/lib/node/nodejs.js +6 -1
  202. package/lib/node/nodejs.js.map +1 -1
  203. package/lib/node/notifier.d.ts.map +1 -1
  204. package/lib/node/notifier.js +2 -2
  205. package/lib/node/notifier.js.map +1 -1
  206. package/package.json +16 -16
  207. package/src/api/impl/beacon/blocks/index.ts +29 -0
  208. package/src/api/impl/beacon/pool/index.ts +4 -0
  209. package/src/api/impl/beacon/state/index.ts +15 -15
  210. package/src/api/impl/lodestar/attesterSlashing.ts +43 -0
  211. package/src/api/impl/lodestar/index.ts +51 -1
  212. package/src/api/impl/validator/index.ts +13 -5
  213. package/src/chain/GetBlobsTracker.ts +1 -2
  214. package/src/chain/archiveStore/strategies/frequencyStateArchiveStrategy.ts +2 -4
  215. package/src/chain/blocks/importBlock.ts +33 -42
  216. package/src/chain/blocks/importExecutionPayload.ts +26 -12
  217. package/src/chain/blocks/index.ts +2 -2
  218. package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +27 -0
  219. package/src/chain/blocks/payloadEnvelopeProcessor.ts +6 -5
  220. package/src/chain/blocks/types.ts +4 -4
  221. package/src/chain/blocks/verifyBlocksExecutionPayloads.ts +2 -1
  222. package/src/chain/blocks/verifyBlocksSignatures.ts +9 -2
  223. package/src/chain/blocks/verifyPayloadsDataAvailability.ts +38 -0
  224. package/src/chain/chain.ts +38 -47
  225. package/src/chain/emitter.ts +12 -0
  226. package/src/chain/errors/attestationError.ts +6 -1
  227. package/src/chain/errors/blockError.ts +7 -1
  228. package/src/chain/forkChoice/index.ts +23 -12
  229. package/src/chain/interface.ts +5 -0
  230. package/src/chain/lightClient/index.ts +15 -3
  231. package/src/chain/opPools/aggregatedAttestationPool.ts +6 -1
  232. package/src/chain/opPools/executionPayloadBidPool.ts +3 -3
  233. package/src/chain/prepareNextSlot.ts +26 -9
  234. package/src/chain/produceBlock/computeNewStateRoot.ts +1 -37
  235. package/src/chain/produceBlock/produceBlockBody.ts +71 -23
  236. package/src/chain/regen/errors.ts +1 -6
  237. package/src/chain/regen/interface.ts +6 -12
  238. package/src/chain/regen/queued.ts +12 -48
  239. package/src/chain/regen/regen.ts +8 -36
  240. package/src/chain/stateCache/datastore/db.ts +10 -33
  241. package/src/chain/stateCache/datastore/file.ts +5 -6
  242. package/src/chain/stateCache/datastore/types.ts +2 -3
  243. package/src/chain/stateCache/fifoBlockStateCache.ts +1 -10
  244. package/src/chain/stateCache/persistentCheckpointsCache.ts +139 -247
  245. package/src/chain/stateCache/types.ts +8 -14
  246. package/src/chain/validation/aggregateAndProof.ts +13 -0
  247. package/src/chain/validation/attestation.ts +13 -0
  248. package/src/chain/validation/block.ts +30 -7
  249. package/src/chain/validation/executionPayloadBid.ts +7 -3
  250. package/src/chain/validation/executionPayloadEnvelope.ts +12 -3
  251. package/src/chain/validation/payloadAttestationMessage.ts +9 -3
  252. package/src/chain/validation/syncCommittee.ts +5 -1
  253. package/src/chain/validation/syncCommitteeContributionAndProof.ts +5 -1
  254. package/src/chain/validatorMonitor.ts +3 -2
  255. package/src/execution/engine/http.ts +21 -14
  256. package/src/execution/engine/interface.ts +1 -0
  257. package/src/execution/engine/mock.ts +3 -0
  258. package/src/execution/engine/types.ts +41 -0
  259. package/src/network/processor/gossipHandlers.ts +28 -7
  260. package/src/network/reqresp/handlers/beaconBlocksByRange.ts +3 -1
  261. package/src/network/reqresp/handlers/beaconBlocksByRoot.ts +3 -0
  262. package/src/network/reqresp/handlers/blobSidecarsByRange.ts +15 -3
  263. package/src/network/reqresp/handlers/blobSidecarsByRoot.ts +11 -0
  264. package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +19 -3
  265. package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +3 -1
  266. package/src/network/reqresp/handlers/executionPayloadEnvelopesByRoot.ts +3 -12
  267. package/src/node/nodejs.ts +7 -2
  268. package/src/node/notifier.ts +7 -2
@@ -14,7 +14,15 @@ import {
14
14
  isForkPostBellatrix,
15
15
  isForkPostGloas,
16
16
  } from "@lodestar/params";
17
- import {G2_POINT_AT_INFINITY, IBeaconStateView, computeTimeAtSlot} from "@lodestar/state-transition";
17
+ import {
18
+ G2_POINT_AT_INFINITY,
19
+ IBeaconStateView,
20
+ type IBeaconStateViewBellatrix,
21
+ computeTimeAtSlot,
22
+ isStatePostBellatrix,
23
+ isStatePostCapella,
24
+ isStatePostGloas,
25
+ } from "@lodestar/state-transition";
18
26
  import {
19
27
  BLSPubkey,
20
28
  BLSSignature,
@@ -39,7 +47,7 @@ import {
39
47
  fulu,
40
48
  gloas,
41
49
  } from "@lodestar/types";
42
- import {Logger, fromHex, sleep, toHex, toPubkeyHex, toRootHex} from "@lodestar/utils";
50
+ import {Logger, byteArrayEquals, fromHex, sleep, toHex, toPubkeyHex, toRootHex} from "@lodestar/utils";
43
51
  import {ZERO_HASH_HEX} from "../../constants/index.js";
44
52
  import {numToQuantity} from "../../execution/engine/utils.js";
45
53
  import {
@@ -102,12 +110,6 @@ export type ProduceFullGloas = {
102
110
  executionRequests: electra.ExecutionRequests;
103
111
  blobsBundle: BlobsBundle<ForkPostGloas>;
104
112
  cells: fulu.Cell[][];
105
- /**
106
- * Cached envelope state root computed during block production.
107
- * This is the state root after running `processExecutionPayloadEnvelope` on the
108
- * post-block state, and later used to construct the `ExecutionPayloadEnvelope`.
109
- */
110
- envelopeStateRoot: Root;
111
113
  };
112
114
  export type ProduceFullFulu = {
113
115
  type: BlockType.Full;
@@ -191,6 +193,10 @@ export async function produceBlockBody<T extends BlockType>(
191
193
  this.logger.verbose("Producing beacon block body", logMeta);
192
194
 
193
195
  if (isForkPostGloas(fork)) {
196
+ if (!isStatePostGloas(currentState)) {
197
+ throw new Error("Expected Gloas state for Gloas block production");
198
+ }
199
+
194
200
  // TODO GLOAS: support non self-building here, the block type differentiation between
195
201
  // full and blinded no longer makes sense in gloas, it might be a good idea to move
196
202
  // this into a completely separate function and have pre/post gloas more separated
@@ -207,11 +213,15 @@ export async function produceBlockBody<T extends BlockType>(
207
213
  });
208
214
 
209
215
  // Get execution payload from EL
216
+ const parentBlockHash = this.forkChoice.shouldExtendPayload(toRootHex(parentBlockRoot))
217
+ ? currentState.latestExecutionPayloadBid.blockHash
218
+ : currentState.latestExecutionPayloadBid.parentBlockHash;
210
219
  const prepareRes = await prepareExecutionPayload(
211
220
  this,
212
221
  this.logger,
213
222
  fork,
214
223
  parentBlockRoot,
224
+ parentBlockHash,
215
225
  safeBlockHash,
216
226
  finalizedBlockHash ?? ZERO_HASH_HEX,
217
227
  currentState,
@@ -248,8 +258,8 @@ export async function produceBlockBody<T extends BlockType>(
248
258
 
249
259
  // Create self-build execution payload bid
250
260
  const bid: gloas.ExecutionPayloadBid = {
251
- parentBlockHash: currentState.latestBlockHash,
252
- parentBlockRoot: parentBlockRoot,
261
+ parentBlockHash,
262
+ parentBlockRoot,
253
263
  blockHash: executionPayload.blockHash,
254
264
  prevRandao: currentState.getRandaoMix(currentState.epoch),
255
265
  feeRecipient: executionPayload.feeRecipient,
@@ -297,6 +307,10 @@ export async function produceBlockBody<T extends BlockType>(
297
307
  shouldOverrideBuilder,
298
308
  });
299
309
  } else if (isForkPostBellatrix(fork)) {
310
+ if (!isStatePostBellatrix(currentState)) {
311
+ throw new Error("Expected Bellatrix state for execution block production");
312
+ }
313
+
300
314
  const safeBlockHash = getSafeExecutionBlockHash(this.forkChoice);
301
315
  const finalizedBlockHash = this.forkChoice.getFinalizedBlock().executionPayloadBlockHash ?? ZERO_HASH_HEX;
302
316
  const feeRecipient = requestedFeeRecipient ?? this.beaconProposerCache.getOrDefault(proposerIndex);
@@ -323,6 +337,7 @@ export async function produceBlockBody<T extends BlockType>(
323
337
  this.logger,
324
338
  fork,
325
339
  parentBlockRoot,
340
+ currentState.latestExecutionPayloadHeader.blockHash,
326
341
  safeBlockHash,
327
342
  finalizedBlockHash ?? ZERO_HASH_HEX,
328
343
  currentState,
@@ -431,6 +446,7 @@ export async function produceBlockBody<T extends BlockType>(
431
446
  this.logger,
432
447
  fork,
433
448
  parentBlockRoot,
449
+ currentState.latestExecutionPayloadHeader.blockHash,
434
450
  safeBlockHash,
435
451
  finalizedBlockHash ?? ZERO_HASH_HEX,
436
452
  currentState,
@@ -596,17 +612,17 @@ export async function prepareExecutionPayload(
596
612
  logger: Logger,
597
613
  fork: ForkPostBellatrix,
598
614
  parentBlockRoot: Root,
615
+ parentBlockHash: Bytes32,
599
616
  safeBlockHash: RootHex,
600
617
  finalizedBlockHash: RootHex,
601
- state: IBeaconStateView,
618
+ state: IBeaconStateViewBellatrix,
602
619
  suggestedFeeRecipient: string
603
620
  ): Promise<{prepType: PayloadPreparationType; payloadId: PayloadId}> {
604
- const parentHash = state.latestBlockHash;
605
621
  const timestamp = computeTimeAtSlot(chain.config, state.slot, state.genesisTime);
606
622
  const prevRandao = state.getRandaoMix(state.epoch);
607
623
 
608
624
  const payloadIdCached = chain.executionEngine.payloadIdCache.get({
609
- headBlockHash: toRootHex(parentHash),
625
+ headBlockHash: toRootHex(parentBlockHash),
610
626
  finalizedBlockHash,
611
627
  timestamp: numToQuantity(timestamp),
612
628
  prevRandao: toHex(prevRandao),
@@ -635,12 +651,13 @@ export async function prepareExecutionPayload(
635
651
  prepareState: state,
636
652
  prepareSlot: state.slot,
637
653
  parentBlockRoot,
654
+ parentBlockHash,
638
655
  feeRecipient: suggestedFeeRecipient,
639
656
  });
640
657
 
641
658
  payloadId = await chain.executionEngine.notifyForkchoiceUpdate(
642
659
  fork,
643
- toRootHex(parentHash),
660
+ toRootHex(parentBlockHash),
644
661
  safeBlockHash,
645
662
  finalizedBlockHash,
646
663
  attributes
@@ -666,7 +683,7 @@ async function prepareExecutionPayloadHeader(
666
683
  config: ChainForkConfig;
667
684
  },
668
685
  fork: ForkPostBellatrix,
669
- state: IBeaconStateView,
686
+ state: IBeaconStateViewBellatrix,
670
687
  proposerPubKey: BLSPubkey
671
688
  ): Promise<{
672
689
  header: ExecutionPayloadHeader;
@@ -692,20 +709,30 @@ export function getPayloadAttributesForSSE(
692
709
  prepareState,
693
710
  prepareSlot,
694
711
  parentBlockRoot,
712
+ parentBlockHash,
695
713
  feeRecipient,
696
- }: {prepareState: IBeaconStateView; prepareSlot: Slot; parentBlockRoot: Root; feeRecipient: string}
714
+ }: {
715
+ prepareState: IBeaconStateViewBellatrix;
716
+ prepareSlot: Slot;
717
+ parentBlockRoot: Root;
718
+ parentBlockHash: Bytes32;
719
+ feeRecipient: string;
720
+ }
697
721
  ): SSEPayloadAttributes {
698
- const parentHash = prepareState.latestBlockHash;
699
722
  const payloadAttributes = preparePayloadAttributes(fork, chain, {
700
723
  prepareState,
701
724
  prepareSlot,
702
725
  parentBlockRoot,
726
+ parentBlockHash,
703
727
  feeRecipient,
704
728
  });
705
729
 
706
730
  let parentBlockNumber: number;
707
731
  if (isForkPostGloas(fork)) {
708
- const parentBlock = chain.forkChoice.getBlockHexAndBlockHash(toRootHex(parentBlockRoot), toRootHex(parentHash));
732
+ const parentBlock = chain.forkChoice.getBlockHexAndBlockHash(
733
+ toRootHex(parentBlockRoot),
734
+ toRootHex(parentBlockHash)
735
+ );
709
736
  if (parentBlock?.executionPayloadBlockHash == null) {
710
737
  throw Error(`Parent block not found in fork choice root=${toRootHex(parentBlockRoot)}`);
711
738
  }
@@ -719,7 +746,7 @@ export function getPayloadAttributesForSSE(
719
746
  proposalSlot: prepareSlot,
720
747
  parentBlockNumber,
721
748
  parentBlockRoot,
722
- parentBlockHash: parentHash,
749
+ parentBlockHash,
723
750
  payloadAttributes,
724
751
  };
725
752
  return ssePayloadAttributes;
@@ -734,11 +761,13 @@ function preparePayloadAttributes(
734
761
  prepareState,
735
762
  prepareSlot,
736
763
  parentBlockRoot,
764
+ parentBlockHash,
737
765
  feeRecipient,
738
766
  }: {
739
- prepareState: IBeaconStateView;
767
+ prepareState: IBeaconStateViewBellatrix;
740
768
  prepareSlot: Slot;
741
769
  parentBlockRoot: Root;
770
+ parentBlockHash: Bytes32;
742
771
  feeRecipient: string;
743
772
  }
744
773
  ): SSEPayloadAttributes["payloadAttributes"] {
@@ -751,15 +780,34 @@ function preparePayloadAttributes(
751
780
  };
752
781
 
753
782
  if (ForkSeq[fork] >= ForkSeq.capella) {
754
- // withdrawals logic is now fork aware as it changes on electra fork post capella
755
- (payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
756
- prepareState.getExpectedWithdrawals().expectedWithdrawals;
783
+ if (!isStatePostCapella(prepareState)) {
784
+ throw new Error("Expected Capella state for withdrawals");
785
+ }
786
+
787
+ if (isStatePostGloas(prepareState)) {
788
+ const isExtendingPayload = byteArrayEquals(parentBlockHash, prepareState.latestExecutionPayloadBid.blockHash);
789
+ // When the parent block is empty, state.payloadExpectedWithdrawals holds a batch
790
+ // already deducted from CL balances but never credited on the EL (the envelope
791
+ // was not delivered). The next payload must carry those same withdrawals to
792
+ // restore CL/EL consistency, otherwise validators permanently lose that balance.
793
+ (payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals = isExtendingPayload
794
+ ? prepareState.getExpectedWithdrawals().expectedWithdrawals
795
+ : prepareState.payloadExpectedWithdrawals;
796
+ } else {
797
+ // withdrawals logic is now fork aware as it changes on electra fork post capella
798
+ (payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals =
799
+ prepareState.getExpectedWithdrawals().expectedWithdrawals;
800
+ }
757
801
  }
758
802
 
759
803
  if (ForkSeq[fork] >= ForkSeq.deneb) {
760
804
  (payloadAttributes as deneb.SSEPayloadAttributes["payloadAttributes"]).parentBeaconBlockRoot = parentBlockRoot;
761
805
  }
762
806
 
807
+ if (ForkSeq[fork] >= ForkSeq.gloas) {
808
+ (payloadAttributes as gloas.SSEPayloadAttributes["payloadAttributes"]).slotNumber = prepareSlot;
809
+ }
810
+
763
811
  return payloadAttributes;
764
812
  }
765
813
 
@@ -1,4 +1,3 @@
1
- import {PayloadStatus} from "@lodestar/fork-choice";
2
1
  import {Root, RootHex, Slot} from "@lodestar/types";
3
2
 
4
3
  export enum RegenErrorCode {
@@ -10,8 +9,6 @@ export enum RegenErrorCode {
10
9
  BLOCK_NOT_IN_DB = "REGEN_ERROR_BLOCK_NOT_IN_DB",
11
10
  STATE_TRANSITION_ERROR = "REGEN_ERROR_STATE_TRANSITION_ERROR",
12
11
  INVALID_STATE_ROOT = "REGEN_ERROR_INVALID_STATE_ROOT",
13
- UNEXPECTED_PAYLOAD_STATUS = "REGEN_ERROR_UNEXPECTED_PAYLOAD_STATUS",
14
- INTERNAL_ERROR = "REGEN_ERROR_INTERNAL_ERROR",
15
12
  }
16
13
 
17
14
  export type RegenErrorType =
@@ -22,9 +19,7 @@ export type RegenErrorType =
22
19
  | {code: RegenErrorCode.TOO_MANY_BLOCK_PROCESSED; stateRoot: RootHex | Root}
23
20
  | {code: RegenErrorCode.BLOCK_NOT_IN_DB; blockRoot: RootHex | Root}
24
21
  | {code: RegenErrorCode.STATE_TRANSITION_ERROR; error: Error}
25
- | {code: RegenErrorCode.INVALID_STATE_ROOT; slot: Slot; expected: RootHex; actual: RootHex}
26
- | {code: RegenErrorCode.UNEXPECTED_PAYLOAD_STATUS; blockRoot: RootHex | Root; payloadStatus: PayloadStatus}
27
- | {code: RegenErrorCode.INTERNAL_ERROR; message: string};
22
+ | {code: RegenErrorCode.INVALID_STATE_ROOT; slot: Slot; expected: RootHex; actual: RootHex};
28
23
 
29
24
  export class RegenError extends Error {
30
25
  type: RegenErrorType;
@@ -2,7 +2,7 @@ import {routes} from "@lodestar/api";
2
2
  import {ProtoBlock} from "@lodestar/fork-choice";
3
3
  import {IBeaconStateView} from "@lodestar/state-transition";
4
4
  import {BeaconBlock, Epoch, RootHex, Slot, phase0} from "@lodestar/types";
5
- import {CheckpointHexPayload} from "../stateCache/types.js";
5
+ import {CheckpointHex} from "../stateCache/types.js";
6
6
 
7
7
  export enum RegenCaller {
8
8
  getDuties = "getDuties",
@@ -40,21 +40,15 @@ export interface IStateRegenerator extends IStateRegeneratorInternal {
40
40
  dumpCacheSummary(): routes.lodestar.StateCacheItem[];
41
41
  getStateSync(stateRoot: RootHex): IBeaconStateView | null;
42
42
  getPreStateSync(block: BeaconBlock): IBeaconStateView | null;
43
- getCheckpointStateOrBytes(cp: CheckpointHexPayload): Promise<IBeaconStateView | Uint8Array | null>;
44
- getCheckpointStateSync(cp: CheckpointHexPayload): IBeaconStateView | null;
43
+ getCheckpointStateOrBytes(cp: CheckpointHex): Promise<IBeaconStateView | Uint8Array | null>;
44
+ getCheckpointStateSync(cp: CheckpointHex): IBeaconStateView | null;
45
45
  getClosestHeadState(head: ProtoBlock): IBeaconStateView | null;
46
46
  pruneOnCheckpoint(finalizedEpoch: Epoch, justifiedEpoch: Epoch, headStateRoot: RootHex): void;
47
47
  pruneOnFinalized(finalizedEpoch: Epoch): void;
48
- processBlockState(blockRootHex: RootHex, postState: IBeaconStateView): void;
49
- processPayloadState(payloadState: IBeaconStateView): void;
50
- /**
51
- * payloadPresent is true if this is payload state, false if block state.
52
- * payloadPresent is always true for pre-gloas.
53
- */
54
- addCheckpointState(cp: phase0.Checkpoint, item: IBeaconStateView, payloadPresent: boolean): void;
48
+ processState(blockRootHex: RootHex, postState: IBeaconStateView): void;
49
+ addCheckpointState(cp: phase0.Checkpoint, item: IBeaconStateView): void;
55
50
  updateHeadState(newHead: ProtoBlock, maybeHeadState: IBeaconStateView): void;
56
- updatePreComputedCheckpoint(rootHex: RootHex, epoch: Epoch, payloadPresent: boolean): number | null;
57
- upgradeForGloas(epoch: Epoch): void;
51
+ updatePreComputedCheckpoint(rootHex: RootHex, epoch: Epoch): number | null;
58
52
  }
59
53
 
60
54
  /**
@@ -1,11 +1,11 @@
1
1
  import {routes} from "@lodestar/api";
2
- import {IForkChoice, PayloadStatus, ProtoBlock} from "@lodestar/fork-choice";
2
+ import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice";
3
3
  import {IBeaconStateView, computeEpochAtSlot} from "@lodestar/state-transition";
4
4
  import {BeaconBlock, Epoch, RootHex, Slot, isGloasBeaconBlock, phase0} from "@lodestar/types";
5
- import {Logger, fromHex, toRootHex} from "@lodestar/utils";
5
+ import {Logger, toRootHex} from "@lodestar/utils";
6
6
  import {Metrics} from "../../metrics/index.js";
7
7
  import {JobItemQueue} from "../../util/queue/index.js";
8
- import {BlockStateCache, CheckpointHexPayload, CheckpointStateCache} from "../stateCache/types.js";
8
+ import {BlockStateCache, CheckpointHex, CheckpointStateCache} from "../stateCache/types.js";
9
9
  import {RegenError, RegenErrorCode} from "./errors.js";
10
10
  import {
11
11
  IStateRegenerator,
@@ -104,19 +104,9 @@ export class QueuedStateRegenerator implements IStateRegenerator {
104
104
  const parentEpoch = computeEpochAtSlot(parentBlock.slot);
105
105
  const blockEpoch = computeEpochAtSlot(block.slot);
106
106
 
107
- // Convert PayloadStatus to payloadPresent boolean
108
- if (parentBlock.payloadStatus === PayloadStatus.PENDING) {
109
- throw new RegenError({
110
- code: RegenErrorCode.UNEXPECTED_PAYLOAD_STATUS,
111
- blockRoot: block.parentRoot,
112
- payloadStatus: parentBlock.payloadStatus,
113
- });
114
- }
115
- const payloadPresent = parentBlock.payloadStatus === PayloadStatus.FULL;
116
-
117
107
  // Check the checkpoint cache (if the pre-state is a checkpoint state)
118
108
  if (parentEpoch < blockEpoch) {
119
- const checkpointState = this.checkpointStateCache.getLatest(parentRoot, blockEpoch, payloadPresent);
109
+ const checkpointState = this.checkpointStateCache.getLatest(parentRoot, blockEpoch);
120
110
  if (checkpointState && computeEpochAtSlot(checkpointState.slot) === blockEpoch) {
121
111
  return checkpointState;
122
112
  }
@@ -135,14 +125,14 @@ export class QueuedStateRegenerator implements IStateRegenerator {
135
125
  return null;
136
126
  }
137
127
 
138
- async getCheckpointStateOrBytes(cp: CheckpointHexPayload): Promise<IBeaconStateView | Uint8Array | null> {
128
+ async getCheckpointStateOrBytes(cp: CheckpointHex): Promise<IBeaconStateView | Uint8Array | null> {
139
129
  return this.checkpointStateCache.getStateOrBytes(cp);
140
130
  }
141
131
 
142
132
  /**
143
133
  * Get checkpoint state from cache
144
134
  */
145
- getCheckpointStateSync(cp: CheckpointHexPayload): IBeaconStateView | null {
135
+ getCheckpointStateSync(cp: CheckpointHex): IBeaconStateView | null {
146
136
  return this.checkpointStateCache.get(cp);
147
137
  }
148
138
 
@@ -150,19 +140,7 @@ export class QueuedStateRegenerator implements IStateRegenerator {
150
140
  * Get state closest to head
151
141
  */
152
142
  getClosestHeadState(head: ProtoBlock): IBeaconStateView | null {
153
- // Convert PayloadStatus to payloadPresent boolean
154
- if (head.payloadStatus === PayloadStatus.PENDING) {
155
- throw new RegenError({
156
- code: RegenErrorCode.UNEXPECTED_PAYLOAD_STATUS,
157
- blockRoot: fromHex(head.blockRoot),
158
- payloadStatus: head.payloadStatus,
159
- });
160
- }
161
- const payloadPresent = head.payloadStatus === PayloadStatus.FULL;
162
- return (
163
- this.checkpointStateCache.getLatest(head.blockRoot, Infinity, payloadPresent) ||
164
- this.blockStateCache.get(head.stateRoot)
165
- );
143
+ return this.checkpointStateCache.getLatest(head.blockRoot, Infinity) || this.blockStateCache.get(head.stateRoot);
166
144
  }
167
145
 
168
146
  pruneOnCheckpoint(finalizedEpoch: Epoch, justifiedEpoch: Epoch, headStateRoot: RootHex): void {
@@ -175,24 +153,15 @@ export class QueuedStateRegenerator implements IStateRegenerator {
175
153
  this.blockStateCache.deleteAllBeforeEpoch(finalizedEpoch);
176
154
  }
177
155
 
178
- processBlockState(blockRootHex: RootHex, postState: IBeaconStateView): void {
156
+ processState(blockRootHex: RootHex, postState: IBeaconStateView): void {
179
157
  this.blockStateCache.add(postState);
180
158
  this.checkpointStateCache.processState(blockRootHex, postState).catch((e) => {
181
159
  this.logger.debug("Error processing block state", {blockRootHex, slot: postState.slot}, e);
182
160
  });
183
161
  }
184
162
 
185
- /**
186
- * Process payload state for caching after importing execution payload.
187
- */
188
- processPayloadState(payloadState: IBeaconStateView): void {
189
- // Add payload state to block state cache (keyed by payload state root)
190
- this.blockStateCache.add(payloadState);
191
- }
192
-
193
- // TODO GLOAS: This should also be called when importing execution payload after we implement it
194
- addCheckpointState(cp: phase0.Checkpoint, item: IBeaconStateView, payloadPresent: boolean): void {
195
- this.checkpointStateCache.add(cp, item, payloadPresent);
163
+ addCheckpointState(cp: phase0.Checkpoint, item: IBeaconStateView): void {
164
+ this.checkpointStateCache.add(cp, item);
196
165
  }
197
166
 
198
167
  updateHeadState(newHead: ProtoBlock, maybeHeadState: IBeaconStateView): void {
@@ -228,13 +197,8 @@ export class QueuedStateRegenerator implements IStateRegenerator {
228
197
  }
229
198
  }
230
199
 
231
- updatePreComputedCheckpoint(rootHex: RootHex, epoch: Epoch, payloadPresent: boolean): number | null {
232
- return this.checkpointStateCache.updatePreComputedCheckpoint(rootHex, epoch, payloadPresent);
233
- }
234
-
235
- upgradeForGloas(epoch: Epoch): void {
236
- this.logger.verbose("Upgrading block state cache for Gloas fork", {epoch});
237
- this.blockStateCache.upgradeToGloas();
200
+ updatePreComputedCheckpoint(rootHex: RootHex, epoch: Epoch): number | null {
201
+ return this.checkpointStateCache.updatePreComputedCheckpoint(rootHex, epoch);
238
202
  }
239
203
 
240
204
  /**
@@ -1,6 +1,6 @@
1
1
  import {ChainForkConfig} from "@lodestar/config";
2
- import {IForkChoice, PayloadStatus, ProtoBlock} from "@lodestar/fork-choice";
3
- import {ForkSeq, SLOTS_PER_EPOCH} from "@lodestar/params";
2
+ import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice";
3
+ import {SLOTS_PER_EPOCH} from "@lodestar/params";
4
4
  import {
5
5
  DataAvailabilityStatus,
6
6
  ExecutionPayloadStatus,
@@ -110,19 +110,9 @@ export class StateRegenerator implements IStateRegeneratorInternal {
110
110
  const {checkpointStateCache} = this.modules;
111
111
  const epoch = computeEpochAtSlot(slot);
112
112
 
113
- // Convert PayloadStatus to payloadPresent boolean
114
- if (block.payloadStatus === PayloadStatus.PENDING) {
115
- throw new RegenError({
116
- code: RegenErrorCode.UNEXPECTED_PAYLOAD_STATUS,
117
- blockRoot: fromHex(blockRoot),
118
- payloadStatus: block.payloadStatus,
119
- });
120
- }
121
- const payloadPresent = block.payloadStatus === PayloadStatus.FULL;
122
-
123
113
  const latestCheckpointStateCtx = allowDiskReload
124
- ? await checkpointStateCache.getOrReloadLatest(blockRoot, epoch, payloadPresent)
125
- : checkpointStateCache.getLatest(blockRoot, epoch, payloadPresent);
114
+ ? await checkpointStateCache.getOrReloadLatest(blockRoot, epoch)
115
+ : checkpointStateCache.getLatest(blockRoot, epoch);
126
116
 
127
117
  // If a checkpoint state exists with the given checkpoint root, it either is in requested epoch
128
118
  // or needs to have empty slots processed until the requested epoch
@@ -176,18 +166,9 @@ export class StateRegenerator implements IStateRegeneratorInternal {
176
166
  if (!lastBlockToReplay) continue;
177
167
  const epoch = computeEpochAtSlot(lastBlockToReplay.slot - 1);
178
168
 
179
- // Convert PayloadStatus to payloadPresent boolean
180
- if (b.payloadStatus === PayloadStatus.PENDING) {
181
- throw new RegenError({
182
- code: RegenErrorCode.INTERNAL_ERROR,
183
- message: `Unexpected PENDING payloadStatus for ancestor block ${b.blockRoot} at slot ${b.slot}`,
184
- });
185
- }
186
- const payloadPresent = b.payloadStatus === PayloadStatus.FULL;
187
-
188
169
  state = allowDiskReload
189
- ? await checkpointStateCache.getOrReloadLatest(b.blockRoot, epoch, payloadPresent)
190
- : checkpointStateCache.getLatest(b.blockRoot, epoch, payloadPresent);
170
+ ? await checkpointStateCache.getOrReloadLatest(b.blockRoot, epoch)
171
+ : checkpointStateCache.getLatest(b.blockRoot, epoch);
191
172
  if (state) {
192
173
  break;
193
174
  }
@@ -351,11 +332,6 @@ async function processSlotsByCheckpoint(
351
332
  * emitting "checkpoint" events after every epoch processed.
352
333
  *
353
334
  * Stops processing after no more full epochs can be processed.
354
- *
355
- * Output state variant:
356
- * - Post-Gloas: If slots are processed, returns block state (payloadPresent=false).
357
- * If no slots processed, returns preState as-is (preserves variant).
358
- * - Pre-Gloas: Always payloadPresent=true (no block/payload distinction).
359
335
  */
360
336
  export async function processSlotsToNearestCheckpoint(
361
337
  modules: {
@@ -375,7 +351,7 @@ export async function processSlotsToNearestCheckpoint(
375
351
  const postSlot = slot;
376
352
  const preEpoch = computeEpochAtSlot(preSlot);
377
353
  let postState = preState;
378
- const {config, checkpointStateCache, emitter, metrics, logger} = modules;
354
+ const {checkpointStateCache, emitter, metrics, logger} = modules;
379
355
  let count = 0;
380
356
 
381
357
  for (
@@ -399,11 +375,7 @@ export async function processSlotsToNearestCheckpoint(
399
375
  // This may becomes the "official" checkpoint state if the 1st block of epoch is skipped
400
376
  const checkpointState = postState;
401
377
  const cp = getCheckpointFromState(checkpointState);
402
- // processSlots() only does epoch transitions, never processes payloads
403
- // Pre-Gloas: payloadPresent is always true (execution payload embedded in block)
404
- // Post-Gloas: result is a block state (payloadPresent=false)
405
- const isPayloadPresent = config.getForkSeq(checkpointState.slot) < ForkSeq.gloas;
406
- checkpointStateCache.add(cp, checkpointState, isPayloadPresent);
378
+ checkpointStateCache.add(cp, checkpointState);
407
379
  // consumers should not mutate state ever
408
380
  emitter?.emit(ChainEvent.checkpoint, cp, checkpointState);
409
381
 
@@ -1,6 +1,6 @@
1
1
  import {SLOTS_PER_EPOCH} from "@lodestar/params";
2
2
  import {Epoch, phase0, ssz} from "@lodestar/types";
3
- import {MapDef, byteArrayEquals} from "@lodestar/utils";
3
+ import {MapDef} from "@lodestar/utils";
4
4
  import {IBeaconDb} from "../../../db/interface.js";
5
5
  import {
6
6
  getLastProcessedSlotFromBeaconStateSerialized,
@@ -14,8 +14,8 @@ import {CPStateDatastore, DatastoreKey} from "./types.js";
14
14
  export class DbCPStateDatastore implements CPStateDatastore {
15
15
  constructor(private readonly db: IBeaconDb) {}
16
16
 
17
- async write(cpKey: phase0.Checkpoint, stateBytes: Uint8Array, payloadPresent: boolean): Promise<DatastoreKey> {
18
- const serializedCheckpoint = checkpointToDatastoreKey(cpKey, payloadPresent);
17
+ async write(cpKey: phase0.Checkpoint, stateBytes: Uint8Array): Promise<DatastoreKey> {
18
+ const serializedCheckpoint = checkpointToDatastoreKey(cpKey);
19
19
  await this.db.checkpointState.putBinary(serializedCheckpoint, stateBytes);
20
20
  return serializedCheckpoint;
21
21
  }
@@ -40,30 +40,18 @@ export class DbCPStateDatastore implements CPStateDatastore {
40
40
  }
41
41
  }
42
42
 
43
- function extractCheckpointBytes(key: DatastoreKey): Uint8Array {
44
- const fixedSize = ssz.phase0.Checkpoint.minSize;
45
- return key.subarray(0, fixedSize);
46
- }
47
-
48
43
  export function datastoreKeyToCheckpoint(key: DatastoreKey): phase0.Checkpoint {
49
- return ssz.phase0.Checkpoint.deserialize(extractCheckpointBytes(key));
50
- }
51
-
52
- export function checkpointToDatastoreKey(cp: phase0.Checkpoint, payloadPresent: boolean): DatastoreKey {
53
- const cpBytes = ssz.phase0.Checkpoint.serialize(cp);
54
- const key = new Uint8Array(cpBytes.length + 1);
55
- key.set(cpBytes);
56
- key[cpBytes.length] = payloadPresent ? 1 : 0;
57
- return key;
44
+ return ssz.phase0.Checkpoint.deserialize(key);
58
45
  }
59
46
 
60
- function isPayloadCheckpointState(key: DatastoreKey): boolean {
61
- return key.at(-1) === 1;
47
+ export function checkpointToDatastoreKey(cp: phase0.Checkpoint): DatastoreKey {
48
+ return ssz.phase0.Checkpoint.serialize(cp);
62
49
  }
63
50
 
64
51
  /**
65
- * Get the latest "safe" checkpoint state the node can use to boot from
66
- * - its last processed block slot should be at epoch boundary (CRCS) or last slot of previous epoch (PRCS)
52
+ * Get the latest safe checkpoint state the node can use to boot from
53
+ * - it should be the checkpoint state that's unique in its epoch
54
+ * - its last processed block slot should be at epoch boundary or last slot of previous epoch
67
55
  * - state slot should be at epoch boundary
68
56
  * - state slot should be equal to epoch * SLOTS_PER_EPOCH
69
57
  *
@@ -82,20 +70,9 @@ export async function getLatestSafeDatastoreKey(
82
70
 
83
71
  const dataStoreKeyByEpoch: Map<Epoch, DatastoreKey> = new Map();
84
72
  for (const [epoch, keys] of checkpointsByEpoch.entries()) {
73
+ // only consider epochs with a single checkpoint to avoid ambiguity from forks
85
74
  if (keys.length === 1) {
86
- // PRCS (skipped slot) or CRCS and no payloadPresent
87
- // Pre-gloas always fall into this case
88
75
  dataStoreKeyByEpoch.set(epoch, keys[0]);
89
- } else if (keys.length === 2) {
90
- // CRCS without payload and CRCS with payload
91
- // ie Two keys for the same checkpoint with different payloadPresent suffix (FULL/EMPTY)
92
- // TODO GLOAS: Here we pick FULL key, there is a chance that payload is orphaned hence we not be able to sync
93
- const cp0 = extractCheckpointBytes(keys[0]);
94
- const cp1 = extractCheckpointBytes(keys[1]);
95
- if (byteArrayEquals(cp0, cp1)) {
96
- const fullKey = isPayloadCheckpointState(keys[0]) ? keys[0] : keys[1];
97
- dataStoreKeyByEpoch.set(epoch, fullKey);
98
- }
99
76
  }
100
77
  }
101
78
 
@@ -1,13 +1,12 @@
1
1
  import path from "node:path";
2
- import {phase0} from "@lodestar/types";
2
+ import {phase0, ssz} from "@lodestar/types";
3
3
  import {fromHex, toHex} from "@lodestar/utils";
4
4
  import {ensureDir, readFile, readFileNames, removeFile, writeIfNotExist} from "../../../util/file.js";
5
- import {checkpointToDatastoreKey, getLatestSafeDatastoreKey} from "./db.js";
5
+ import {getLatestSafeDatastoreKey} from "./db.js";
6
6
  import {CPStateDatastore, DatastoreKey} from "./types.js";
7
7
 
8
8
  const CHECKPOINT_STATES_FOLDER = "checkpoint_states";
9
- /** 41 bytes (40 checkpoint + 1 payloadPresent) = 82 hex chars + "0x" prefix = 84 */
10
- const CHECKPOINT_FILE_NAME_LENGTH = 84;
9
+ const CHECKPOINT_FILE_NAME_LENGTH = 82;
11
10
 
12
11
  /**
13
12
  * Implementation of CPStateDatastore using file system, this is beneficial for debugging.
@@ -29,8 +28,8 @@ export class FileCPStateDatastore implements CPStateDatastore {
29
28
  }
30
29
  }
31
30
 
32
- async write(cpKey: phase0.Checkpoint, stateBytes: Uint8Array, payloadPresent: boolean): Promise<DatastoreKey> {
33
- const serializedCheckpoint = checkpointToDatastoreKey(cpKey, payloadPresent);
31
+ async write(cpKey: phase0.Checkpoint, stateBytes: Uint8Array): Promise<DatastoreKey> {
32
+ const serializedCheckpoint = ssz.phase0.Checkpoint.serialize(cpKey);
34
33
  const filePath = path.join(this.folderPath, toHex(serializedCheckpoint));
35
34
  await writeIfNotExist(filePath, stateBytes);
36
35
  return serializedCheckpoint;
@@ -1,12 +1,11 @@
1
1
  import {phase0} from "@lodestar/types";
2
2
 
3
- // With db implementation, persistedKey is serialized data of a checkpoint + 1
4
- // ie a fixed size of `ssz.phase0.Checkpoint.minSize + 1`
3
+ // With db implementation, persistedKey is serialized data of a checkpoint
5
4
  export type DatastoreKey = Uint8Array;
6
5
 
7
6
  // Make this generic to support testing
8
7
  export interface CPStateDatastore {
9
- write: (cpKey: phase0.Checkpoint, stateBytes: Uint8Array, payloadPresent: boolean) => Promise<DatastoreKey>;
8
+ write: (cpKey: phase0.Checkpoint, stateBytes: Uint8Array) => Promise<DatastoreKey>;
10
9
  remove: (key: DatastoreKey) => Promise<void>;
11
10
  read: (key: DatastoreKey) => Promise<Uint8Array | null>;
12
11
  readLatestSafe: () => Promise<Uint8Array | null>;
@@ -20,11 +20,6 @@ export type FIFOBlockStateCacheOpts = {
20
20
  * clock slot
21
21
  */
22
22
  export const DEFAULT_MAX_BLOCK_STATES = 64;
23
- /**
24
- * For Gloas (ePBS), each block can have two states: block state and payload state.
25
- * Double the cache size to maintain the same effective block depth.
26
- */
27
- export const DEFAULT_MAX_BLOCK_STATES_GLOAS = 128;
28
23
 
29
24
  /**
30
25
  * New implementation of BlockStateCache that keeps the most recent n states consistently
@@ -46,7 +41,7 @@ export const DEFAULT_MAX_BLOCK_STATES_GLOAS = 128;
46
41
  * The maintained key order would be: 11 -> 13 -> 12 -> 10, and state 10 will be pruned first.
47
42
  */
48
43
  export class FIFOBlockStateCache implements BlockStateCache {
49
- private maxStates: number;
44
+ readonly maxStates: number;
50
45
 
51
46
  private readonly cache: MapTracker<string, IBeaconStateView>;
52
47
  /**
@@ -172,10 +167,6 @@ export class FIFOBlockStateCache implements BlockStateCache {
172
167
  }
173
168
  }
174
169
 
175
- upgradeToGloas(): void {
176
- this.maxStates = DEFAULT_MAX_BLOCK_STATES_GLOAS;
177
- }
178
-
179
170
  /**
180
171
  * No need for this implementation
181
172
  * This is only to conform to the old api