@lodestar/beacon-node 1.39.0-dev.2fe8de2346 → 1.39.0-dev.375b1b3da7

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 (251) hide show
  1. package/README.md +1 -1
  2. package/lib/api/impl/beacon/state/utils.d.ts +2 -7
  3. package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
  4. package/lib/api/impl/beacon/state/utils.js +0 -12
  5. package/lib/api/impl/beacon/state/utils.js.map +1 -1
  6. package/lib/api/impl/lodestar/index.js +1 -1
  7. package/lib/api/impl/lodestar/index.js.map +1 -1
  8. package/lib/api/impl/proof/index.d.ts.map +1 -1
  9. package/lib/api/impl/proof/index.js +1 -2
  10. package/lib/api/impl/proof/index.js.map +1 -1
  11. package/lib/api/impl/validator/index.d.ts.map +1 -1
  12. package/lib/api/impl/validator/index.js +1 -3
  13. package/lib/api/impl/validator/index.js.map +1 -1
  14. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  15. package/lib/chain/blocks/importBlock.js +12 -3
  16. package/lib/chain/blocks/importBlock.js.map +1 -1
  17. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  18. package/lib/chain/blocks/verifyBlock.js +9 -2
  19. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  20. package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts.map +1 -1
  21. package/lib/chain/blocks/verifyBlocksExecutionPayloads.js +4 -2
  22. package/lib/chain/blocks/verifyBlocksExecutionPayloads.js.map +1 -1
  23. package/lib/chain/blocks/verifyBlocksSignatures.d.ts +2 -1
  24. package/lib/chain/blocks/verifyBlocksSignatures.d.ts.map +1 -1
  25. package/lib/chain/blocks/verifyBlocksSignatures.js +3 -2
  26. package/lib/chain/blocks/verifyBlocksSignatures.js.map +1 -1
  27. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts.map +1 -1
  28. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js +1 -0
  29. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js.map +1 -1
  30. package/lib/chain/chain.d.ts +11 -11
  31. package/lib/chain/chain.d.ts.map +1 -1
  32. package/lib/chain/chain.js +36 -40
  33. package/lib/chain/chain.js.map +1 -1
  34. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  35. package/lib/chain/forkChoice/index.js +3 -3
  36. package/lib/chain/forkChoice/index.js.map +1 -1
  37. package/lib/chain/interface.d.ts +6 -9
  38. package/lib/chain/interface.d.ts.map +1 -1
  39. package/lib/chain/interface.js.map +1 -1
  40. package/lib/chain/lightClient/proofs.d.ts.map +1 -1
  41. package/lib/chain/lightClient/proofs.js +0 -2
  42. package/lib/chain/lightClient/proofs.js.map +1 -1
  43. package/lib/chain/opPools/aggregatedAttestationPool.d.ts +8 -12
  44. package/lib/chain/opPools/aggregatedAttestationPool.d.ts.map +1 -1
  45. package/lib/chain/opPools/aggregatedAttestationPool.js +13 -142
  46. package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
  47. package/lib/chain/opPools/opPool.d.ts +3 -0
  48. package/lib/chain/opPools/opPool.d.ts.map +1 -1
  49. package/lib/chain/opPools/opPool.js +14 -16
  50. package/lib/chain/opPools/opPool.js.map +1 -1
  51. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  52. package/lib/chain/prepareNextSlot.js +4 -7
  53. package/lib/chain/prepareNextSlot.js.map +1 -1
  54. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  55. package/lib/chain/produceBlock/produceBlockBody.js +4 -4
  56. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  57. package/lib/chain/regen/interface.d.ts +1 -5
  58. package/lib/chain/regen/interface.d.ts.map +1 -1
  59. package/lib/chain/regen/queued.d.ts +4 -7
  60. package/lib/chain/regen/queued.d.ts.map +1 -1
  61. package/lib/chain/regen/queued.js +15 -25
  62. package/lib/chain/regen/queued.js.map +1 -1
  63. package/lib/chain/regen/regen.d.ts +1 -1
  64. package/lib/chain/regen/regen.d.ts.map +1 -1
  65. package/lib/chain/regen/regen.js +13 -17
  66. package/lib/chain/regen/regen.js.map +1 -1
  67. package/lib/chain/shufflingCache.d.ts +16 -11
  68. package/lib/chain/shufflingCache.d.ts.map +1 -1
  69. package/lib/chain/shufflingCache.js +47 -41
  70. package/lib/chain/shufflingCache.js.map +1 -1
  71. package/lib/chain/stateCache/blockStateCacheImpl.d.ts +1 -2
  72. package/lib/chain/stateCache/blockStateCacheImpl.d.ts.map +1 -1
  73. package/lib/chain/stateCache/blockStateCacheImpl.js +2 -2
  74. package/lib/chain/stateCache/blockStateCacheImpl.js.map +1 -1
  75. package/lib/chain/stateCache/fifoBlockStateCache.d.ts +1 -2
  76. package/lib/chain/stateCache/fifoBlockStateCache.d.ts.map +1 -1
  77. package/lib/chain/stateCache/fifoBlockStateCache.js +4 -4
  78. package/lib/chain/stateCache/fifoBlockStateCache.js.map +1 -1
  79. package/lib/chain/stateCache/inMemoryCheckpointsCache.d.ts +4 -5
  80. package/lib/chain/stateCache/inMemoryCheckpointsCache.d.ts.map +1 -1
  81. package/lib/chain/stateCache/inMemoryCheckpointsCache.js +9 -10
  82. package/lib/chain/stateCache/inMemoryCheckpointsCache.js.map +1 -1
  83. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts +9 -7
  84. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
  85. package/lib/chain/stateCache/persistentCheckpointsCache.js +21 -19
  86. package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
  87. package/lib/chain/stateCache/types.d.ts +5 -6
  88. package/lib/chain/stateCache/types.d.ts.map +1 -1
  89. package/lib/chain/stateCache/types.js.map +1 -1
  90. package/lib/chain/validation/aggregateAndProof.js +9 -0
  91. package/lib/chain/validation/aggregateAndProof.js.map +1 -1
  92. package/lib/chain/validation/attestation.d.ts.map +1 -1
  93. package/lib/chain/validation/attestation.js +2 -2
  94. package/lib/chain/validation/attestation.js.map +1 -1
  95. package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
  96. package/lib/chain/validation/attesterSlashing.js +2 -2
  97. package/lib/chain/validation/attesterSlashing.js.map +1 -1
  98. package/lib/chain/validation/blobSidecar.d.ts.map +1 -1
  99. package/lib/chain/validation/blobSidecar.js +2 -3
  100. package/lib/chain/validation/blobSidecar.js.map +1 -1
  101. package/lib/chain/validation/block.d.ts.map +1 -1
  102. package/lib/chain/validation/block.js +5 -3
  103. package/lib/chain/validation/block.js.map +1 -1
  104. package/lib/chain/validation/blsToExecutionChange.d.ts.map +1 -1
  105. package/lib/chain/validation/blsToExecutionChange.js +10 -3
  106. package/lib/chain/validation/blsToExecutionChange.js.map +1 -1
  107. package/lib/chain/validation/dataColumnSidecar.d.ts.map +1 -1
  108. package/lib/chain/validation/dataColumnSidecar.js +2 -3
  109. package/lib/chain/validation/dataColumnSidecar.js.map +1 -1
  110. package/lib/chain/validation/proposerSlashing.js +3 -2
  111. package/lib/chain/validation/proposerSlashing.js.map +1 -1
  112. package/lib/chain/validation/signatureSets/aggregateAndProof.js +1 -1
  113. package/lib/chain/validation/signatureSets/aggregateAndProof.js.map +1 -1
  114. package/lib/chain/validation/signatureSets/contributionAndProof.d.ts +2 -1
  115. package/lib/chain/validation/signatureSets/contributionAndProof.d.ts.map +1 -1
  116. package/lib/chain/validation/signatureSets/contributionAndProof.js +2 -2
  117. package/lib/chain/validation/signatureSets/contributionAndProof.js.map +1 -1
  118. package/lib/chain/validation/signatureSets/syncCommittee.d.ts +2 -1
  119. package/lib/chain/validation/signatureSets/syncCommittee.d.ts.map +1 -1
  120. package/lib/chain/validation/signatureSets/syncCommittee.js +2 -2
  121. package/lib/chain/validation/signatureSets/syncCommittee.js.map +1 -1
  122. package/lib/chain/validation/signatureSets/syncCommitteeContribution.d.ts +2 -1
  123. package/lib/chain/validation/signatureSets/syncCommitteeContribution.d.ts.map +1 -1
  124. package/lib/chain/validation/signatureSets/syncCommitteeContribution.js +2 -2
  125. package/lib/chain/validation/signatureSets/syncCommitteeContribution.js.map +1 -1
  126. package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.d.ts +2 -1
  127. package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.d.ts.map +1 -1
  128. package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.js +1 -2
  129. package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.js.map +1 -1
  130. package/lib/chain/validation/syncCommittee.js +1 -1
  131. package/lib/chain/validation/syncCommittee.js.map +1 -1
  132. package/lib/chain/validation/syncCommitteeContributionAndProof.d.ts.map +1 -1
  133. package/lib/chain/validation/syncCommitteeContributionAndProof.js +3 -3
  134. package/lib/chain/validation/syncCommitteeContributionAndProof.js.map +1 -1
  135. package/lib/chain/validation/voluntaryExit.js +1 -1
  136. package/lib/chain/validation/voluntaryExit.js.map +1 -1
  137. package/lib/db/beacon.d.ts +2 -0
  138. package/lib/db/beacon.d.ts.map +1 -1
  139. package/lib/db/beacon.js +32 -0
  140. package/lib/db/beacon.js.map +1 -1
  141. package/lib/db/buckets.d.ts +12 -0
  142. package/lib/db/buckets.d.ts.map +1 -1
  143. package/lib/db/buckets.js +12 -6
  144. package/lib/db/buckets.js.map +1 -1
  145. package/lib/db/interface.d.ts +1 -0
  146. package/lib/db/interface.d.ts.map +1 -1
  147. package/lib/db/repositories/blockArchiveIndex.d.ts +2 -2
  148. package/lib/db/repositories/blockArchiveIndex.d.ts.map +1 -1
  149. package/lib/db/repositories/stateArchive.d.ts +1 -1
  150. package/lib/db/repositories/stateArchive.d.ts.map +1 -1
  151. package/lib/db/repositories/stateArchive.js +2 -2
  152. package/lib/db/repositories/stateArchive.js.map +1 -1
  153. package/lib/execution/engine/mock.d.ts +9 -6
  154. package/lib/execution/engine/mock.d.ts.map +1 -1
  155. package/lib/execution/engine/mock.js +34 -7
  156. package/lib/execution/engine/mock.js.map +1 -1
  157. package/lib/metrics/metrics/lodestar.d.ts +1 -6
  158. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  159. package/lib/metrics/metrics/lodestar.js +3 -17
  160. package/lib/metrics/metrics/lodestar.js.map +1 -1
  161. package/lib/network/peers/discover.d.ts.map +1 -1
  162. package/lib/network/peers/discover.js.map +1 -1
  163. package/lib/network/reqresp/utils/dataColumnResponseValidation.js +1 -1
  164. package/lib/network/reqresp/utils/dataColumnResponseValidation.js.map +1 -1
  165. package/lib/node/nodejs.d.ts +6 -3
  166. package/lib/node/nodejs.d.ts.map +1 -1
  167. package/lib/node/nodejs.js +30 -3
  168. package/lib/node/nodejs.js.map +1 -1
  169. package/lib/node/notifier.d.ts.map +1 -1
  170. package/lib/node/notifier.js +9 -6
  171. package/lib/node/notifier.js.map +1 -1
  172. package/lib/sync/backfill/backfill.d.ts.map +1 -1
  173. package/lib/sync/backfill/backfill.js +2 -4
  174. package/lib/sync/backfill/backfill.js.map +1 -1
  175. package/lib/sync/backfill/verify.d.ts +2 -2
  176. package/lib/sync/backfill/verify.d.ts.map +1 -1
  177. package/lib/sync/backfill/verify.js +3 -3
  178. package/lib/sync/backfill/verify.js.map +1 -1
  179. package/lib/util/sszBytes.js +1 -1
  180. package/lib/util/sszBytes.js.map +1 -1
  181. package/package.json +28 -20
  182. package/src/api/impl/beacon/state/utils.ts +2 -22
  183. package/src/api/impl/lodestar/index.ts +1 -1
  184. package/src/api/impl/proof/index.ts +1 -2
  185. package/src/api/impl/validator/index.ts +1 -3
  186. package/src/chain/blocks/importBlock.ts +13 -3
  187. package/src/chain/blocks/verifyBlock.ts +10 -3
  188. package/src/chain/blocks/verifyBlocksExecutionPayloads.ts +9 -2
  189. package/src/chain/blocks/verifyBlocksSignatures.ts +13 -3
  190. package/src/chain/blocks/verifyBlocksStateTransitionOnly.ts +1 -0
  191. package/src/chain/chain.ts +50 -48
  192. package/src/chain/forkChoice/index.ts +3 -2
  193. package/src/chain/interface.ts +6 -8
  194. package/src/chain/lightClient/proofs.ts +0 -2
  195. package/src/chain/opPools/aggregatedAttestationPool.ts +23 -195
  196. package/src/chain/opPools/opPool.ts +13 -15
  197. package/src/chain/prepareNextSlot.ts +2 -6
  198. package/src/chain/produceBlock/produceBlockBody.ts +9 -4
  199. package/src/chain/regen/interface.ts +1 -5
  200. package/src/chain/regen/queued.ts +15 -34
  201. package/src/chain/regen/regen.ts +12 -18
  202. package/src/chain/shufflingCache.ts +67 -50
  203. package/src/chain/stateCache/blockStateCacheImpl.ts +2 -3
  204. package/src/chain/stateCache/fifoBlockStateCache.ts +4 -5
  205. package/src/chain/stateCache/inMemoryCheckpointsCache.ts +9 -15
  206. package/src/chain/stateCache/persistentCheckpointsCache.ts +32 -27
  207. package/src/chain/stateCache/types.ts +5 -10
  208. package/src/chain/validation/aggregateAndProof.ts +12 -0
  209. package/src/chain/validation/attestation.ts +3 -3
  210. package/src/chain/validation/attesterSlashing.ts +14 -2
  211. package/src/chain/validation/blobSidecar.ts +3 -3
  212. package/src/chain/validation/block.ts +6 -2
  213. package/src/chain/validation/blsToExecutionChange.ts +10 -8
  214. package/src/chain/validation/dataColumnSidecar.ts +3 -3
  215. package/src/chain/validation/proposerSlashing.ts +8 -2
  216. package/src/chain/validation/signatureSets/aggregateAndProof.ts +1 -1
  217. package/src/chain/validation/signatureSets/contributionAndProof.ts +3 -1
  218. package/src/chain/validation/signatureSets/syncCommittee.ts +3 -1
  219. package/src/chain/validation/signatureSets/syncCommitteeContribution.ts +3 -1
  220. package/src/chain/validation/signatureSets/syncCommitteeSelectionProof.ts +2 -1
  221. package/src/chain/validation/syncCommittee.ts +1 -1
  222. package/src/chain/validation/syncCommitteeContributionAndProof.ts +8 -3
  223. package/src/chain/validation/voluntaryExit.ts +1 -1
  224. package/src/db/beacon.ts +38 -1
  225. package/src/db/buckets.ts +12 -6
  226. package/src/db/interface.ts +2 -0
  227. package/src/db/repositories/stateArchive.ts +2 -2
  228. package/src/execution/engine/mock.ts +40 -13
  229. package/src/metrics/metrics/lodestar.ts +3 -17
  230. package/src/network/peers/discover.ts +3 -3
  231. package/src/network/reqresp/utils/dataColumnResponseValidation.ts +1 -1
  232. package/src/node/nodejs.ts +37 -4
  233. package/src/node/notifier.ts +13 -7
  234. package/src/sync/backfill/backfill.ts +2 -9
  235. package/src/sync/backfill/verify.ts +3 -8
  236. package/src/util/sszBytes.ts +1 -1
  237. package/lib/chain/rewards/attestationsRewards.d.ts +0 -7
  238. package/lib/chain/rewards/attestationsRewards.d.ts.map +0 -1
  239. package/lib/chain/rewards/attestationsRewards.js +0 -112
  240. package/lib/chain/rewards/attestationsRewards.js.map +0 -1
  241. package/lib/chain/rewards/blockRewards.d.ts +0 -14
  242. package/lib/chain/rewards/blockRewards.d.ts.map +0 -1
  243. package/lib/chain/rewards/blockRewards.js +0 -94
  244. package/lib/chain/rewards/blockRewards.js.map +0 -1
  245. package/lib/chain/rewards/syncCommitteeRewards.d.ts +0 -6
  246. package/lib/chain/rewards/syncCommitteeRewards.d.ts.map +0 -1
  247. package/lib/chain/rewards/syncCommitteeRewards.js +0 -36
  248. package/lib/chain/rewards/syncCommitteeRewards.js.map +0 -1
  249. package/src/chain/rewards/attestationsRewards.ts +0 -197
  250. package/src/chain/rewards/blockRewards.ts +0 -150
  251. package/src/chain/rewards/syncCommitteeRewards.ts +0 -58
@@ -78,7 +78,7 @@ export class StateRegenerator implements IStateRegeneratorInternal {
78
78
  }
79
79
 
80
80
  // Otherwise, get the state normally.
81
- return this.getState(parentBlock.stateRoot, regenCaller, opts, allowDiskReload);
81
+ return this.getState(parentBlock.stateRoot, regenCaller, allowDiskReload);
82
82
  }
83
83
 
84
84
  /**
@@ -124,8 +124,8 @@ export class StateRegenerator implements IStateRegeneratorInternal {
124
124
  const {checkpointStateCache} = this.modules;
125
125
  const epoch = computeEpochAtSlot(slot);
126
126
  const latestCheckpointStateCtx = allowDiskReload
127
- ? await checkpointStateCache.getOrReloadLatest(blockRoot, epoch, opts)
128
- : checkpointStateCache.getLatest(blockRoot, epoch, opts);
127
+ ? await checkpointStateCache.getOrReloadLatest(blockRoot, epoch)
128
+ : checkpointStateCache.getLatest(blockRoot, epoch);
129
129
 
130
130
  // If a checkpoint state exists with the given checkpoint root, it either is in requested epoch
131
131
  // or needs to have empty slots processed until the requested epoch
@@ -136,7 +136,7 @@ export class StateRegenerator implements IStateRegeneratorInternal {
136
136
  // Otherwise, use the fork choice to get the stateRoot from block at the checkpoint root
137
137
  // regenerate that state,
138
138
  // then process empty slots until the requested epoch
139
- const blockStateCtx = await this.getState(block.stateRoot, regenCaller, opts, allowDiskReload);
139
+ const blockStateCtx = await this.getState(block.stateRoot, regenCaller, allowDiskReload);
140
140
  return processSlotsByCheckpoint(this.modules, blockStateCtx, slot, regenCaller, opts);
141
141
  }
142
142
 
@@ -148,23 +148,15 @@ export class StateRegenerator implements IStateRegeneratorInternal {
148
148
  async getState(
149
149
  stateRoot: RootHex,
150
150
  caller: RegenCaller,
151
- opts?: StateRegenerationOpts,
152
151
  // internal option, don't want to expose to external caller
153
152
  allowDiskReload = false
154
153
  ): Promise<CachedBeaconStateAllForks> {
155
154
  // Trivial case, state at stateRoot is already cached
156
- const cachedStateCtx = this.modules.blockStateCache.get(stateRoot, opts);
155
+ const cachedStateCtx = this.modules.blockStateCache.get(stateRoot);
157
156
  if (cachedStateCtx) {
158
157
  return cachedStateCtx;
159
158
  }
160
159
 
161
- // in block gossip validation (getPreState() call), dontTransferCache is specified as true because we only want to transfer cache in verifyBlocksStateTransitionOnly()
162
- // but here we want to process blocks as fast as possible so force to transfer cache in this case
163
- if (opts && allowDiskReload) {
164
- // if there is no `opts` specified, it already means "false"
165
- opts.dontTransferCache = false;
166
- }
167
-
168
160
  // Otherwise we have to use the fork choice to traverse backwards, block by block,
169
161
  // searching the state caches
170
162
  // then replay blocks forward to the desired stateRoot
@@ -179,7 +171,7 @@ export class StateRegenerator implements IStateRegeneratorInternal {
179
171
  const getSeedStateTimer = this.modules.metrics?.regenGetState.getSeedState.startTimer({caller});
180
172
  // iterateAncestorBlocks only returns ancestor blocks, not the block itself
181
173
  for (const b of this.modules.forkChoice.iterateAncestorBlocks(block.blockRoot)) {
182
- state = this.modules.blockStateCache.get(b.stateRoot, opts);
174
+ state = this.modules.blockStateCache.get(b.stateRoot);
183
175
  if (state) {
184
176
  break;
185
177
  }
@@ -187,8 +179,8 @@ export class StateRegenerator implements IStateRegeneratorInternal {
187
179
  if (!lastBlockToReplay) continue;
188
180
  const epoch = computeEpochAtSlot(lastBlockToReplay.slot - 1);
189
181
  state = allowDiskReload
190
- ? await checkpointStateCache.getOrReloadLatest(b.blockRoot, epoch, opts)
191
- : checkpointStateCache.getLatest(b.blockRoot, epoch, opts);
182
+ ? await checkpointStateCache.getOrReloadLatest(b.blockRoot, epoch)
183
+ : checkpointStateCache.getLatest(b.blockRoot, epoch);
192
184
  if (state) {
193
185
  break;
194
186
  }
@@ -255,6 +247,7 @@ export class StateRegenerator implements IStateRegeneratorInternal {
255
247
  try {
256
248
  // Only advances state trusting block's signture and hashes.
257
249
  // We are only running the state transition to get a specific state's data.
250
+ // stateTransition() does the clone() inside, transfer cache to make the regen faster
258
251
  state = stateTransition(
259
252
  state,
260
253
  block,
@@ -265,6 +258,7 @@ export class StateRegenerator implements IStateRegeneratorInternal {
265
258
  verifyStateRoot: false,
266
259
  verifyProposer: false,
267
260
  verifySignatures: false,
261
+ dontTransferCache: false,
268
262
  },
269
263
  this.modules
270
264
  );
@@ -390,8 +384,8 @@ export async function processSlotsToNearestCheckpoint(
390
384
  const checkpointState = postState;
391
385
  const cp = getCheckpointFromState(checkpointState);
392
386
  checkpointStateCache.add(cp, checkpointState);
393
- // consumers should not mutate or get the transfered cache
394
- emitter?.emit(ChainEvent.checkpoint, cp, checkpointState.clone(true));
387
+ // consumers should not mutate state ever
388
+ emitter?.emit(ChainEvent.checkpoint, cp, checkpointState);
395
389
 
396
390
  if (count >= 1) {
397
391
  // in normal condition, we only process 1 epoch so never reach this
@@ -1,12 +1,12 @@
1
+ import {ForkSeq} from "@lodestar/params";
1
2
  import {
2
- BeaconStateAllForks,
3
+ CachedBeaconStateAllForks,
3
4
  EpochShuffling,
4
- IShufflingCache,
5
- ShufflingBuildProps,
6
- computeEpochShuffling,
7
- computeEpochShufflingAsync,
5
+ getAttestingIndices,
6
+ getBeaconCommittees,
7
+ getIndexedAttestation,
8
8
  } from "@lodestar/state-transition";
9
- import {Epoch, RootHex} from "@lodestar/types";
9
+ import {Attestation, CommitteeIndex, Epoch, IndexedAttestation, RootHex, Slot} from "@lodestar/types";
10
10
  import {LodestarError, Logger, MapDef, pruneSetToMax} from "@lodestar/utils";
11
11
  import {Metrics} from "../metrics/metrics.js";
12
12
 
@@ -53,7 +53,7 @@ export type ShufflingCacheOpts = {
53
53
  * - if a shuffling is not available (which does not happen with default chain option of maxSkipSlots = 32), track a promise to make sure we don't compute the same shuffling twice
54
54
  * - skip computing shuffling when loading state bytes from disk
55
55
  */
56
- export class ShufflingCache implements IShufflingCache {
56
+ export class ShufflingCache {
57
57
  /** LRU cache implemented as a map, pruned every time we add an item */
58
58
  private readonly itemsByDecisionRootByEpoch: MapDef<Epoch, Map<RootHex, CacheItem>> = new MapDef(
59
59
  () => new Map<RootHex, CacheItem>()
@@ -136,60 +136,76 @@ export class ShufflingCache implements IShufflingCache {
136
136
  }
137
137
 
138
138
  /**
139
- * Gets a cached shuffling via the epoch and decision root. If the shuffling is not
140
- * available it will build it synchronously and return the shuffling.
141
- *
142
- * NOTE: If a shuffling is already queued and not calculated it will build and resolve
143
- * the promise but the already queued build will happen at some later time
139
+ * Get a shuffling synchronously, return null if not present.
140
+ * The only time we have a promise cache item is when we regen shuffling for attestation, which never happens
141
+ * with default chain option.
144
142
  */
145
- getSync<T extends ShufflingBuildProps | undefined>(
146
- epoch: Epoch,
147
- decisionRoot: RootHex,
148
- buildProps?: T
149
- ): T extends ShufflingBuildProps ? EpochShuffling : EpochShuffling | null {
143
+ getSync(epoch: Epoch, decisionRoot: RootHex): EpochShuffling | null {
150
144
  const cacheItem = this.itemsByDecisionRootByEpoch.getOrDefault(epoch).get(decisionRoot);
151
- if (!cacheItem) {
145
+ if (cacheItem === undefined) {
152
146
  this.metrics?.shufflingCache.miss.inc();
153
- } else if (isShufflingCacheItem(cacheItem)) {
147
+ return null;
148
+ }
149
+
150
+ if (isShufflingCacheItem(cacheItem)) {
154
151
  this.metrics?.shufflingCache.hit.inc();
155
152
  return cacheItem.shuffling;
156
- } else if (buildProps) {
157
- // TODO: (@matthewkeil) This should possible log a warning??
158
- this.metrics?.shufflingCache.shufflingPromiseNotResolvedAndThrownAway.inc();
159
- } else {
160
- this.metrics?.shufflingCache.shufflingPromiseNotResolved.inc();
161
153
  }
162
154
 
163
- let shuffling: EpochShuffling | null = null;
164
- if (buildProps) {
165
- const timer = this.metrics?.shufflingCache.shufflingCalculationTime.startTimer({source: "getSync"});
166
- shuffling = computeEpochShuffling(buildProps.state, buildProps.activeIndices, epoch);
167
- timer?.();
168
- this.set(shuffling, decisionRoot);
169
- }
170
- return shuffling as T extends ShufflingBuildProps ? EpochShuffling : EpochShuffling | null;
155
+ return null;
171
156
  }
172
157
 
173
158
  /**
174
- * Queue asynchronous build for an EpochShuffling, triggered from state-transition
159
+ * Process a state to extract and cache all shufflings (previous, current, next).
160
+ * Uses the stored decision roots from epochCtx.
175
161
  */
176
- build(epoch: number, decisionRoot: string, state: BeaconStateAllForks, activeIndices: Uint32Array): void {
177
- this.insertPromise(epoch, decisionRoot);
178
- /**
179
- * TODO: (@matthewkeil) This will get replaced by a proper build queue and a worker to do calculations
180
- * on a NICE thread
181
- */
182
- const timer = this.metrics?.shufflingCache.shufflingCalculationTime.startTimer({source: "build"});
183
- computeEpochShufflingAsync(state, activeIndices, epoch)
184
- .then((shuffling) => {
185
- this.set(shuffling, decisionRoot);
186
- })
187
- .catch((err) =>
188
- this.logger?.error(`error building shuffling for epoch ${epoch} at decisionRoot ${decisionRoot}`, {}, err)
189
- )
190
- .finally(() => {
191
- timer?.();
162
+ processState(state: CachedBeaconStateAllForks): void {
163
+ const {epochCtx} = state;
164
+
165
+ // Cache previous shuffling
166
+ this.set(epochCtx.previousShuffling, epochCtx.previousDecisionRoot);
167
+
168
+ // Cache current shuffling
169
+ this.set(epochCtx.currentShuffling, epochCtx.currentDecisionRoot);
170
+
171
+ // Cache next shuffling
172
+ this.set(epochCtx.nextShuffling, epochCtx.nextDecisionRoot);
173
+ }
174
+
175
+ getIndexedAttestation(
176
+ epoch: number,
177
+ decisionRoot: string,
178
+ fork: ForkSeq,
179
+ attestation: Attestation
180
+ ): IndexedAttestation {
181
+ const shuffling = this.getShufflingOrThrow(epoch, decisionRoot);
182
+ return getIndexedAttestation(shuffling, fork, attestation);
183
+ }
184
+
185
+ getAttestingIndices(epoch: number, decisionRoot: string, fork: ForkSeq, attestation: Attestation): number[] {
186
+ const shuffling = this.getShufflingOrThrow(epoch, decisionRoot);
187
+ return getAttestingIndices(shuffling, fork, attestation);
188
+ }
189
+
190
+ getBeaconCommittee(epoch: number, decisionRoot: string, slot: Slot, index: CommitteeIndex): Uint32Array {
191
+ return this.getBeaconCommittees(epoch, decisionRoot, slot, [index])[0];
192
+ }
193
+
194
+ getBeaconCommittees(epoch: number, decisionRoot: string, slot: Slot, indices: CommitteeIndex[]): Uint32Array[] {
195
+ const shuffling = this.getShufflingOrThrow(epoch, decisionRoot);
196
+ return getBeaconCommittees(shuffling, slot, indices);
197
+ }
198
+
199
+ private getShufflingOrThrow(epoch: number, decisionRoot: string): EpochShuffling {
200
+ const shuffling = this.getSync(epoch, decisionRoot);
201
+ if (shuffling === null) {
202
+ throw new ShufflingCacheError({
203
+ code: ShufflingCacheErrorCode.NO_SHUFFLING_FOUND,
204
+ epoch,
205
+ decisionRoot,
192
206
  });
207
+ }
208
+ return shuffling;
193
209
  }
194
210
 
195
211
  /**
@@ -207,7 +223,8 @@ export class ShufflingCache implements IShufflingCache {
207
223
  (Date.now() - cacheItem.timeInsertedMs) / 1000
208
224
  );
209
225
  } else {
210
- this.metrics?.shufflingCache.shufflingBuiltMultipleTimes.inc();
226
+ this.metrics?.shufflingCache.shufflingSetMultipleTimes.inc();
227
+ return;
211
228
  }
212
229
  }
213
230
  // set the shuffling
@@ -3,7 +3,6 @@ import {CachedBeaconStateAllForks} from "@lodestar/state-transition";
3
3
  import {Epoch, RootHex} from "@lodestar/types";
4
4
  import {toRootHex} from "@lodestar/utils";
5
5
  import {Metrics} from "../../metrics/index.js";
6
- import {StateRegenerationOpts} from "../regen/interface.js";
7
6
  import {MapTracker} from "./mapMetrics.js";
8
7
  import {BlockStateCache} from "./types.js";
9
8
 
@@ -39,7 +38,7 @@ export class BlockStateCacheImpl implements BlockStateCache {
39
38
  }
40
39
  }
41
40
 
42
- get(rootHex: RootHex, opts?: StateRegenerationOpts): CachedBeaconStateAllForks | null {
41
+ get(rootHex: RootHex): CachedBeaconStateAllForks | null {
43
42
  this.metrics?.lookups.inc();
44
43
  const item = this.head?.stateRoot === rootHex ? this.head.state : this.cache.get(rootHex);
45
44
  if (!item) {
@@ -49,7 +48,7 @@ export class BlockStateCacheImpl implements BlockStateCache {
49
48
  this.metrics?.hits.inc();
50
49
  this.metrics?.stateClonedCount.observe(item.clonedCount);
51
50
 
52
- return item.clone(opts?.dontTransferCache);
51
+ return item;
53
52
  }
54
53
 
55
54
  add(item: CachedBeaconStateAllForks): void {
@@ -4,7 +4,6 @@ import {RootHex} from "@lodestar/types";
4
4
  import {toRootHex} from "@lodestar/utils";
5
5
  import {Metrics} from "../../metrics/index.js";
6
6
  import {LinkedList} from "../../util/array.js";
7
- import {StateRegenerationOpts} from "../regen/interface.js";
8
7
  import {MapTracker} from "./mapMetrics.js";
9
8
  import {BlockStateCache} from "./types.js";
10
9
 
@@ -86,14 +85,14 @@ export class FIFOBlockStateCache implements BlockStateCache {
86
85
  }
87
86
 
88
87
  const firstState = firstValue.value;
89
- // don't transfer cache because consumer only use this cache to reload another state from disc
90
- return firstState.clone(true);
88
+ // consumers should not mutate the returned state
89
+ return firstState;
91
90
  }
92
91
 
93
92
  /**
94
93
  * Get a state from this cache given a state root hex.
95
94
  */
96
- get(rootHex: RootHex, opts?: StateRegenerationOpts): CachedBeaconStateAllForks | null {
95
+ get(rootHex: RootHex): CachedBeaconStateAllForks | null {
97
96
  this.metrics?.lookups.inc();
98
97
  const item = this.cache.get(rootHex);
99
98
  if (!item) {
@@ -103,7 +102,7 @@ export class FIFOBlockStateCache implements BlockStateCache {
103
102
  this.metrics?.hits.inc();
104
103
  this.metrics?.stateClonedCount.observe(item.clonedCount);
105
104
 
106
- return item.clone(opts?.dontTransferCache);
105
+ return item;
107
106
  }
108
107
 
109
108
  /**
@@ -3,7 +3,6 @@ import {CachedBeaconStateAllForks} from "@lodestar/state-transition";
3
3
  import {Epoch, RootHex, phase0} from "@lodestar/types";
4
4
  import {MapDef, toRootHex} from "@lodestar/utils";
5
5
  import {Metrics} from "../../metrics/index.js";
6
- import {StateRegenerationOpts} from "../regen/interface.js";
7
6
  import {MapTracker} from "./mapMetrics.js";
8
7
  import {CacheItemType, CheckpointStateCache} from "./types.js";
9
8
 
@@ -42,21 +41,16 @@ export class InMemoryCheckpointStateCache implements CheckpointStateCache {
42
41
  this.maxEpochs = maxEpochs;
43
42
  }
44
43
 
45
- async getOrReload(cp: CheckpointHex, opts?: StateRegenerationOpts): Promise<CachedBeaconStateAllForks | null> {
46
- return this.get(cp, opts);
44
+ async getOrReload(cp: CheckpointHex): Promise<CachedBeaconStateAllForks | null> {
45
+ return this.get(cp);
47
46
  }
48
47
 
49
48
  async getStateOrBytes(cp: CheckpointHex): Promise<Uint8Array | CachedBeaconStateAllForks | null> {
50
- // no need to transfer cache for this api
51
- return this.get(cp, {dontTransferCache: true});
49
+ return this.get(cp);
52
50
  }
53
51
 
54
- async getOrReloadLatest(
55
- rootHex: string,
56
- maxEpoch: number,
57
- opts?: StateRegenerationOpts
58
- ): Promise<CachedBeaconStateAllForks | null> {
59
- return this.getLatest(rootHex, maxEpoch, opts);
52
+ async getOrReloadLatest(rootHex: string, maxEpoch: number): Promise<CachedBeaconStateAllForks | null> {
53
+ return this.getLatest(rootHex, maxEpoch);
60
54
  }
61
55
 
62
56
  async processState(): Promise<number> {
@@ -64,7 +58,7 @@ export class InMemoryCheckpointStateCache implements CheckpointStateCache {
64
58
  return 0;
65
59
  }
66
60
 
67
- get(cp: CheckpointHex, opts?: StateRegenerationOpts): CachedBeaconStateAllForks | null {
61
+ get(cp: CheckpointHex): CachedBeaconStateAllForks | null {
68
62
  this.metrics?.lookups.inc();
69
63
  const cpKey = toCheckpointKey(cp);
70
64
  const item = this.cache.get(cpKey);
@@ -81,7 +75,7 @@ export class InMemoryCheckpointStateCache implements CheckpointStateCache {
81
75
 
82
76
  this.metrics?.stateClonedCount.observe(item.clonedCount);
83
77
 
84
- return item.clone(opts?.dontTransferCache);
78
+ return item;
85
79
  }
86
80
 
87
81
  add(cp: phase0.Checkpoint, item: CachedBeaconStateAllForks): void {
@@ -98,14 +92,14 @@ export class InMemoryCheckpointStateCache implements CheckpointStateCache {
98
92
  /**
99
93
  * Searches for the latest cached state with a `root`, starting with `epoch` and descending
100
94
  */
101
- getLatest(rootHex: RootHex, maxEpoch: Epoch, opts?: StateRegenerationOpts): CachedBeaconStateAllForks | null {
95
+ getLatest(rootHex: RootHex, maxEpoch: Epoch): CachedBeaconStateAllForks | null {
102
96
  // sort epochs in descending order, only consider epochs lte `epoch`
103
97
  const epochs = Array.from(this.epochIndex.keys())
104
98
  .sort((a, b) => b - a)
105
99
  .filter((e) => e <= maxEpoch);
106
100
  for (const epoch of epochs) {
107
101
  if (this.epochIndex.get(epoch)?.has(rootHex)) {
108
- return this.get({rootHex, epoch}, opts);
102
+ return this.get({rootHex, epoch});
109
103
  }
110
104
  }
111
105
  return null;
@@ -1,4 +1,5 @@
1
1
  import {routes} from "@lodestar/api";
2
+ import {BeaconConfig} from "@lodestar/config";
2
3
  import {
3
4
  CachedBeaconStateAllForks,
4
5
  computeStartSlotAtEpoch,
@@ -10,7 +11,6 @@ import {Logger, MapDef, fromHex, sleep, toHex, toRootHex} from "@lodestar/utils"
10
11
  import {Metrics} from "../../metrics/index.js";
11
12
  import {AllocSource, BufferPool, BufferWithKey} from "../../util/bufferPool.js";
12
13
  import {IClock} from "../../util/clock.js";
13
- import {StateRegenerationOpts} from "../regen/interface.js";
14
14
  import {serializeState} from "../serializeState.js";
15
15
  import {CPStateDatastore, DatastoreKey} from "./datastore/index.js";
16
16
  import {MapTracker} from "./mapMetrics.js";
@@ -24,6 +24,7 @@ export type PersistentCheckpointStateCacheOpts = {
24
24
  };
25
25
 
26
26
  type PersistentCheckpointStateCacheModules = {
27
+ config: BeaconConfig;
27
28
  metrics?: Metrics | null;
28
29
  logger: Logger;
29
30
  clock?: IClock | null;
@@ -107,6 +108,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
107
108
  private readonly cache: MapTracker<CacheKey, CacheItem>;
108
109
  /** Epoch -> Set<blockRoot> */
109
110
  private readonly epochIndex = new MapDef<Epoch, Set<RootHex>>(() => new Set<string>());
111
+ private readonly config: BeaconConfig;
110
112
  private readonly metrics: Metrics | null | undefined;
111
113
  private readonly logger: Logger;
112
114
  private readonly clock: IClock | null | undefined;
@@ -120,10 +122,20 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
120
122
  private readonly bufferPool?: BufferPool | null;
121
123
 
122
124
  constructor(
123
- {metrics, logger, clock, signal, datastore, blockStateCache, bufferPool}: PersistentCheckpointStateCacheModules,
125
+ {
126
+ config,
127
+ metrics,
128
+ logger,
129
+ clock,
130
+ signal,
131
+ datastore,
132
+ blockStateCache,
133
+ bufferPool,
134
+ }: PersistentCheckpointStateCacheModules,
124
135
  opts: PersistentCheckpointStateCacheOpts
125
136
  ) {
126
137
  this.cache = new MapTracker(metrics?.cpStateCache);
138
+ this.config = config;
127
139
  if (metrics) {
128
140
  this.metrics = metrics;
129
141
  metrics.cpStateCache.size.addCollect(() => {
@@ -191,10 +203,10 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
191
203
  * - Get block for processing
192
204
  * - Regen head state
193
205
  */
194
- async getOrReload(cp: CheckpointHex, opts?: StateRegenerationOpts): Promise<CachedBeaconStateAllForks | null> {
195
- const stateOrStateBytesData = await this.getStateOrLoadDb(cp, opts);
206
+ async getOrReload(cp: CheckpointHex): Promise<CachedBeaconStateAllForks | null> {
207
+ const stateOrStateBytesData = await this.getStateOrLoadDb(cp);
196
208
  if (stateOrStateBytesData === null || isCachedBeaconState(stateOrStateBytesData)) {
197
- return stateOrStateBytesData?.clone(opts?.dontTransferCache) ?? null;
209
+ return stateOrStateBytesData ?? null;
198
210
  }
199
211
  const {persistedKey, stateBytes} = stateOrStateBytesData;
200
212
  const logMeta = {persistedKey: toHex(persistedKey)};
@@ -220,7 +232,8 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
220
232
  sszTimer?.();
221
233
  const timer = this.metrics?.cpStateCache.stateReloadDuration.startTimer();
222
234
  const newCachedState = loadCachedBeaconState(seedState, stateBytes, {}, validatorsBytes);
223
- newCachedState.commit();
235
+ // hashTreeRoot() calls the commit() inside
236
+ // there is no modification inside the state, it's just that we want to compute and cache all roots
224
237
  const stateRoot = toRootHex(newCachedState.hashTreeRoot());
225
238
  timer?.();
226
239
 
@@ -239,7 +252,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
239
252
  this.cache.set(cpKey, {type: CacheItemType.inMemory, state: newCachedState, persistedKey});
240
253
  this.epochIndex.getOrDefault(cp.epoch).add(cp.rootHex);
241
254
  // don't prune from memory here, call it at the last 1/3 of slot 0 of an epoch
242
- return newCachedState.clone(opts?.dontTransferCache);
255
+ return newCachedState;
243
256
  } catch (e) {
244
257
  this.logger.debug("Reload: error loading cached state", logMeta, e as Error);
245
258
  return null;
@@ -250,8 +263,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
250
263
  * Return either state or state bytes loaded from db.
251
264
  */
252
265
  async getStateOrBytes(cp: CheckpointHex): Promise<CachedBeaconStateAllForks | Uint8Array | null> {
253
- // don't have to transfer cache for this specific api
254
- const stateOrLoadedState = await this.getStateOrLoadDb(cp, {dontTransferCache: true});
266
+ const stateOrLoadedState = await this.getStateOrLoadDb(cp);
255
267
  if (stateOrLoadedState === null || isCachedBeaconState(stateOrLoadedState)) {
256
268
  return stateOrLoadedState;
257
269
  }
@@ -261,12 +273,9 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
261
273
  /**
262
274
  * Return either state or state bytes with persisted key loaded from db.
263
275
  */
264
- async getStateOrLoadDb(
265
- cp: CheckpointHex,
266
- opts?: StateRegenerationOpts
267
- ): Promise<CachedBeaconStateAllForks | LoadedStateBytesData | null> {
276
+ async getStateOrLoadDb(cp: CheckpointHex): Promise<CachedBeaconStateAllForks | LoadedStateBytesData | null> {
268
277
  const cpKey = toCacheKey(cp);
269
- const inMemoryState = this.get(cpKey, opts);
278
+ const inMemoryState = this.get(cpKey);
270
279
  if (inMemoryState) {
271
280
  return inMemoryState;
272
281
  }
@@ -295,7 +304,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
295
304
  /**
296
305
  * Similar to get() api without reloading from disk
297
306
  */
298
- get(cpOrKey: CheckpointHex | string, opts?: StateRegenerationOpts): CachedBeaconStateAllForks | null {
307
+ get(cpOrKey: CheckpointHex | string): CachedBeaconStateAllForks | null {
299
308
  this.metrics?.cpStateCache.lookups.inc();
300
309
  const cpKey = typeof cpOrKey === "string" ? cpOrKey : toCacheKey(cpOrKey);
301
310
  const cacheItem = this.cache.get(cpKey);
@@ -313,7 +322,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
313
322
  if (isInMemoryCacheItem(cacheItem)) {
314
323
  const {state} = cacheItem;
315
324
  this.metrics?.cpStateCache.stateClonedCount.observe(state.clonedCount);
316
- return state.clone(opts?.dontTransferCache);
325
+ return state;
317
326
  }
318
327
 
319
328
  return null;
@@ -347,14 +356,14 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
347
356
  /**
348
357
  * Searches in-memory state for the latest cached state with a `root` without reload, starting with `epoch` and descending
349
358
  */
350
- getLatest(rootHex: RootHex, maxEpoch: Epoch, opts?: StateRegenerationOpts): CachedBeaconStateAllForks | null {
359
+ getLatest(rootHex: RootHex, maxEpoch: Epoch): CachedBeaconStateAllForks | null {
351
360
  // sort epochs in descending order, only consider epochs lte `epoch`
352
361
  const epochs = Array.from(this.epochIndex.keys())
353
362
  .sort((a, b) => b - a)
354
363
  .filter((e) => e <= maxEpoch);
355
364
  for (const epoch of epochs) {
356
365
  if (this.epochIndex.get(epoch)?.has(rootHex)) {
357
- const inMemoryClonedState = this.get({rootHex, epoch}, opts);
366
+ const inMemoryClonedState = this.get({rootHex, epoch});
358
367
  if (inMemoryClonedState) {
359
368
  return inMemoryClonedState;
360
369
  }
@@ -370,11 +379,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
370
379
  * - Get block for processing
371
380
  * - Regen head state
372
381
  */
373
- async getOrReloadLatest(
374
- rootHex: RootHex,
375
- maxEpoch: Epoch,
376
- opts?: StateRegenerationOpts
377
- ): Promise<CachedBeaconStateAllForks | null> {
382
+ async getOrReloadLatest(rootHex: RootHex, maxEpoch: Epoch): Promise<CachedBeaconStateAllForks | null> {
378
383
  // sort epochs in descending order, only consider epochs lte `epoch`
379
384
  const epochs = Array.from(this.epochIndex.keys())
380
385
  .sort((a, b) => b - a)
@@ -382,9 +387,9 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
382
387
  for (const epoch of epochs) {
383
388
  if (this.epochIndex.get(epoch)?.has(rootHex)) {
384
389
  try {
385
- const clonedState = await this.getOrReload({rootHex, epoch}, opts);
386
- if (clonedState) {
387
- return clonedState;
390
+ const state = await this.getOrReload({rootHex, epoch});
391
+ if (state) {
392
+ return state;
388
393
  }
389
394
  } catch (e) {
390
395
  this.logger.debug("Error get or reload state", {epoch, rootHex}, e as Error);
@@ -484,7 +489,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
484
489
  }
485
490
 
486
491
  const blockSlot = state.slot;
487
- const processCPStatesTimeMs = state.config.getSlotComponentDurationMs(PROCESS_CHECKPOINT_STATES_BPS);
492
+ const processCPStatesTimeMs = this.config.getSlotComponentDurationMs(PROCESS_CHECKPOINT_STATES_BPS);
488
493
  // we always have clock in production, fallback value is only for test
489
494
  const msFromSlot = this.clock?.msFromSlot(blockSlot) ?? processCPStatesTimeMs;
490
495
  const msToProcessCPStates = processCPStatesTimeMs - msFromSlot;
@@ -1,7 +1,6 @@
1
1
  import {routes} from "@lodestar/api";
2
2
  import {CachedBeaconStateAllForks} from "@lodestar/state-transition";
3
3
  import {Epoch, RootHex, phase0} from "@lodestar/types";
4
- import {StateRegenerationOpts} from "../regen/interface.js";
5
4
 
6
5
  export type CheckpointHex = {epoch: Epoch; rootHex: RootHex};
7
6
 
@@ -21,7 +20,7 @@ export type CheckpointHex = {epoch: Epoch; rootHex: RootHex};
21
20
  * The cache key is state root
22
21
  */
23
22
  export interface BlockStateCache {
24
- get(rootHex: RootHex, opts?: StateRegenerationOpts): CachedBeaconStateAllForks | null;
23
+ get(rootHex: RootHex): CachedBeaconStateAllForks | null;
25
24
  add(item: CachedBeaconStateAllForks): void;
26
25
  setHeadState(item: CachedBeaconStateAllForks | null): void;
27
26
  /**
@@ -60,16 +59,12 @@ export interface BlockStateCache {
60
59
  */
61
60
  export interface CheckpointStateCache {
62
61
  init?: () => Promise<void>;
63
- getOrReload(cp: CheckpointHex, opts?: StateRegenerationOpts): Promise<CachedBeaconStateAllForks | null>;
62
+ getOrReload(cp: CheckpointHex): Promise<CachedBeaconStateAllForks | null>;
64
63
  getStateOrBytes(cp: CheckpointHex): Promise<CachedBeaconStateAllForks | Uint8Array | null>;
65
- get(cpOrKey: CheckpointHex | string, opts?: StateRegenerationOpts): CachedBeaconStateAllForks | null;
64
+ get(cpOrKey: CheckpointHex | string): CachedBeaconStateAllForks | null;
66
65
  add(cp: phase0.Checkpoint, state: CachedBeaconStateAllForks): void;
67
- getLatest(rootHex: RootHex, maxEpoch: Epoch, opts?: StateRegenerationOpts): CachedBeaconStateAllForks | null;
68
- getOrReloadLatest(
69
- rootHex: RootHex,
70
- maxEpoch: Epoch,
71
- opts?: StateRegenerationOpts
72
- ): Promise<CachedBeaconStateAllForks | null>;
66
+ getLatest(rootHex: RootHex, maxEpoch: Epoch): CachedBeaconStateAllForks | null;
67
+ getOrReloadLatest(rootHex: RootHex, maxEpoch: Epoch): Promise<CachedBeaconStateAllForks | null>;
73
68
  updatePreComputedCheckpoint(rootHex: RootHex, epoch: Epoch): number | null;
74
69
  prune(finalizedEpoch: Epoch, justifiedEpoch: Epoch): void;
75
70
  pruneFinalized(finalizedEpoch: Epoch): void;
@@ -245,6 +245,18 @@ async function validateAggregateAndProof(
245
245
  });
246
246
  }
247
247
 
248
+ // Same race-condition check as above for seen aggregators
249
+ if (
250
+ !skipValidationKnownAttesters &&
251
+ chain.seenAggregatedAttestations.isKnown(targetEpoch, attIndex, attDataRootHex, aggregationBits)
252
+ ) {
253
+ throw new AttestationError(GossipAction.IGNORE, {
254
+ code: AttestationErrorCode.ATTESTERS_ALREADY_KNOWN,
255
+ targetEpoch,
256
+ aggregateRoot: attDataRootHex,
257
+ });
258
+ }
259
+
248
260
  chain.seenAggregators.add(targetEpoch, aggregatorIndex);
249
261
  chain.seenAggregatedAttestations.add(
250
262
  targetEpoch,
@@ -12,9 +12,9 @@ import {
12
12
  isForkPostElectra,
13
13
  } from "@lodestar/params";
14
14
  import {
15
- EpochCacheError,
16
- EpochCacheErrorCode,
17
15
  EpochShuffling,
16
+ ShufflingError,
17
+ ShufflingErrorCode,
18
18
  SingleSignatureSet,
19
19
  computeEpochAtSlot,
20
20
  computeSigningRoot,
@@ -224,7 +224,7 @@ export async function validateApiAttestation(
224
224
  code: AttestationErrorCode.INVALID_SIGNATURE,
225
225
  });
226
226
  } catch (err) {
227
- if (err instanceof EpochCacheError && err.type.code === EpochCacheErrorCode.COMMITTEE_INDEX_OUT_OF_RANGE) {
227
+ if (err instanceof ShufflingError && err.type.code === ShufflingErrorCode.COMMITTEE_INDEX_OUT_OF_RANGE) {
228
228
  throw new AttestationError(GossipAction.IGNORE, {
229
229
  code: AttestationErrorCode.BAD_TARGET_EPOCH,
230
230
  });