@lodestar/beacon-node 1.40.0-dev.9defa5c09b → 1.40.0-dev.ade3accfa0

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 (275) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +15 -9
  3. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  4. package/lib/api/impl/lodestar/index.d.ts.map +1 -1
  5. package/lib/api/impl/lodestar/index.js +24 -0
  6. package/lib/api/impl/lodestar/index.js.map +1 -1
  7. package/lib/api/impl/validator/index.d.ts.map +1 -1
  8. package/lib/api/impl/validator/index.js.map +1 -1
  9. package/lib/api/rest/base.d.ts.map +1 -1
  10. package/lib/api/rest/base.js +12 -10
  11. package/lib/api/rest/base.js.map +1 -1
  12. package/lib/chain/ColumnReconstructionTracker.d.ts +2 -0
  13. package/lib/chain/ColumnReconstructionTracker.d.ts.map +1 -1
  14. package/lib/chain/ColumnReconstructionTracker.js +7 -3
  15. package/lib/chain/ColumnReconstructionTracker.js.map +1 -1
  16. package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
  17. package/lib/chain/archiveStore/archiveStore.js +10 -4
  18. package/lib/chain/archiveStore/archiveStore.js.map +1 -1
  19. package/lib/chain/archiveStore/historicalState/getHistoricalState.d.ts.map +1 -1
  20. package/lib/chain/archiveStore/historicalState/getHistoricalState.js +2 -1
  21. package/lib/chain/archiveStore/historicalState/getHistoricalState.js.map +1 -1
  22. package/lib/chain/blocks/blockInput/blockInput.d.ts +28 -0
  23. package/lib/chain/blocks/blockInput/blockInput.d.ts.map +1 -1
  24. package/lib/chain/blocks/blockInput/blockInput.js +38 -3
  25. package/lib/chain/blocks/blockInput/blockInput.js.map +1 -1
  26. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  27. package/lib/chain/blocks/importBlock.js +10 -2
  28. package/lib/chain/blocks/importBlock.js.map +1 -1
  29. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  30. package/lib/chain/blocks/verifyBlock.js +1 -1
  31. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  32. package/lib/chain/blocks/verifyBlocksSignatures.d.ts +2 -2
  33. package/lib/chain/blocks/verifyBlocksSignatures.d.ts.map +1 -1
  34. package/lib/chain/blocks/verifyBlocksSignatures.js +2 -2
  35. package/lib/chain/blocks/verifyBlocksSignatures.js.map +1 -1
  36. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts.map +1 -1
  37. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js +1 -2
  38. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js.map +1 -1
  39. package/lib/chain/blocks/writeBlockInputToDb.d.ts.map +1 -1
  40. package/lib/chain/blocks/writeBlockInputToDb.js +8 -0
  41. package/lib/chain/blocks/writeBlockInputToDb.js.map +1 -1
  42. package/lib/chain/bls/multithread/index.d.ts +3 -1
  43. package/lib/chain/bls/multithread/index.d.ts.map +1 -1
  44. package/lib/chain/bls/multithread/index.js +5 -3
  45. package/lib/chain/bls/multithread/index.js.map +1 -1
  46. package/lib/chain/bls/multithread/jobItem.d.ts +2 -2
  47. package/lib/chain/bls/multithread/jobItem.d.ts.map +1 -1
  48. package/lib/chain/bls/multithread/jobItem.js +2 -2
  49. package/lib/chain/bls/multithread/jobItem.js.map +1 -1
  50. package/lib/chain/bls/singleThread.d.ts +4 -2
  51. package/lib/chain/bls/singleThread.d.ts.map +1 -1
  52. package/lib/chain/bls/singleThread.js +4 -2
  53. package/lib/chain/bls/singleThread.js.map +1 -1
  54. package/lib/chain/bls/utils.d.ts +2 -2
  55. package/lib/chain/bls/utils.d.ts.map +1 -1
  56. package/lib/chain/bls/utils.js +9 -6
  57. package/lib/chain/bls/utils.js.map +1 -1
  58. package/lib/chain/chain.d.ts +1 -1
  59. package/lib/chain/chain.d.ts.map +1 -1
  60. package/lib/chain/chain.js +24 -33
  61. package/lib/chain/chain.js.map +1 -1
  62. package/lib/chain/initState.d.ts.map +1 -1
  63. package/lib/chain/initState.js +2 -2
  64. package/lib/chain/initState.js.map +1 -1
  65. package/lib/chain/lightClient/index.d.ts +2 -0
  66. package/lib/chain/lightClient/index.d.ts.map +1 -1
  67. package/lib/chain/lightClient/index.js +11 -6
  68. package/lib/chain/lightClient/index.js.map +1 -1
  69. package/lib/chain/options.d.ts +0 -1
  70. package/lib/chain/options.d.ts.map +1 -1
  71. package/lib/chain/options.js +0 -1
  72. package/lib/chain/options.js.map +1 -1
  73. package/lib/chain/regen/interface.d.ts +1 -1
  74. package/lib/chain/regen/queued.d.ts +1 -1
  75. package/lib/chain/regen/queued.d.ts.map +1 -1
  76. package/lib/chain/regen/queued.js.map +1 -1
  77. package/lib/chain/regen/regen.d.ts +2 -0
  78. package/lib/chain/regen/regen.d.ts.map +1 -1
  79. package/lib/chain/regen/regen.js +4 -1
  80. package/lib/chain/regen/regen.js.map +1 -1
  81. package/lib/chain/seenCache/seenGossipBlockInput.d.ts +7 -7
  82. package/lib/chain/seenCache/seenGossipBlockInput.d.ts.map +1 -1
  83. package/lib/chain/seenCache/seenGossipBlockInput.js +23 -12
  84. package/lib/chain/seenCache/seenGossipBlockInput.js.map +1 -1
  85. package/lib/chain/serializeState.d.ts.map +1 -1
  86. package/lib/chain/serializeState.js +2 -1
  87. package/lib/chain/serializeState.js.map +1 -1
  88. package/lib/chain/stateCache/index.d.ts +0 -2
  89. package/lib/chain/stateCache/index.d.ts.map +1 -1
  90. package/lib/chain/stateCache/index.js +0 -2
  91. package/lib/chain/stateCache/index.js.map +1 -1
  92. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts +2 -1
  93. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
  94. package/lib/chain/stateCache/persistentCheckpointsCache.js +3 -0
  95. package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
  96. package/lib/chain/validation/aggregateAndProof.js +3 -4
  97. package/lib/chain/validation/aggregateAndProof.js.map +1 -1
  98. package/lib/chain/validation/attestation.d.ts +2 -2
  99. package/lib/chain/validation/attestation.d.ts.map +1 -1
  100. package/lib/chain/validation/attestation.js +4 -4
  101. package/lib/chain/validation/attestation.js.map +1 -1
  102. package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
  103. package/lib/chain/validation/attesterSlashing.js +1 -1
  104. package/lib/chain/validation/attesterSlashing.js.map +1 -1
  105. package/lib/chain/validation/blobSidecar.d.ts.map +1 -1
  106. package/lib/chain/validation/blobSidecar.js +4 -4
  107. package/lib/chain/validation/blobSidecar.js.map +1 -1
  108. package/lib/chain/validation/block.d.ts.map +1 -1
  109. package/lib/chain/validation/block.js +2 -3
  110. package/lib/chain/validation/block.js.map +1 -1
  111. package/lib/chain/validation/dataColumnSidecar.d.ts.map +1 -1
  112. package/lib/chain/validation/dataColumnSidecar.js +4 -4
  113. package/lib/chain/validation/dataColumnSidecar.js.map +1 -1
  114. package/lib/chain/validation/executionPayloadBid.js +4 -3
  115. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  116. package/lib/chain/validation/payloadAttestationMessage.js +1 -1
  117. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
  118. package/lib/chain/validation/proposerSlashing.js +1 -1
  119. package/lib/chain/validation/proposerSlashing.js.map +1 -1
  120. package/lib/chain/validation/signatureSets/aggregateAndProof.d.ts +2 -3
  121. package/lib/chain/validation/signatureSets/aggregateAndProof.d.ts.map +1 -1
  122. package/lib/chain/validation/signatureSets/aggregateAndProof.js +8 -3
  123. package/lib/chain/validation/signatureSets/aggregateAndProof.js.map +1 -1
  124. package/lib/chain/validation/signatureSets/contributionAndProof.d.ts +2 -2
  125. package/lib/chain/validation/signatureSets/contributionAndProof.d.ts.map +1 -1
  126. package/lib/chain/validation/signatureSets/contributionAndProof.js +3 -3
  127. package/lib/chain/validation/signatureSets/contributionAndProof.js.map +1 -1
  128. package/lib/chain/validation/signatureSets/selectionProof.d.ts +2 -3
  129. package/lib/chain/validation/signatureSets/selectionProof.d.ts.map +1 -1
  130. package/lib/chain/validation/signatureSets/selectionProof.js +8 -3
  131. package/lib/chain/validation/signatureSets/selectionProof.js.map +1 -1
  132. package/lib/chain/validation/signatureSets/syncCommittee.d.ts +2 -2
  133. package/lib/chain/validation/signatureSets/syncCommittee.d.ts.map +1 -1
  134. package/lib/chain/validation/signatureSets/syncCommittee.js +3 -3
  135. package/lib/chain/validation/signatureSets/syncCommittee.js.map +1 -1
  136. package/lib/chain/validation/signatureSets/syncCommitteeContribution.d.ts +1 -2
  137. package/lib/chain/validation/signatureSets/syncCommitteeContribution.d.ts.map +1 -1
  138. package/lib/chain/validation/signatureSets/syncCommitteeContribution.js +2 -2
  139. package/lib/chain/validation/signatureSets/syncCommitteeContribution.js.map +1 -1
  140. package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.d.ts +2 -2
  141. package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.d.ts.map +1 -1
  142. package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.js +3 -3
  143. package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.js.map +1 -1
  144. package/lib/chain/validation/syncCommittee.js +1 -1
  145. package/lib/chain/validation/syncCommittee.js.map +1 -1
  146. package/lib/chain/validation/syncCommitteeContributionAndProof.d.ts.map +1 -1
  147. package/lib/chain/validation/syncCommitteeContributionAndProof.js +3 -5
  148. package/lib/chain/validation/syncCommitteeContributionAndProof.js.map +1 -1
  149. package/lib/chain/validation/voluntaryExit.js +1 -1
  150. package/lib/chain/validation/voluntaryExit.js.map +1 -1
  151. package/lib/chain/validatorMonitor.d.ts.map +1 -1
  152. package/lib/chain/validatorMonitor.js +7 -4
  153. package/lib/chain/validatorMonitor.js.map +1 -1
  154. package/lib/network/core/networkCore.d.ts +3 -0
  155. package/lib/network/core/networkCore.d.ts.map +1 -1
  156. package/lib/network/core/networkCore.js +9 -0
  157. package/lib/network/core/networkCore.js.map +1 -1
  158. package/lib/network/core/networkCoreWorker.js +3 -0
  159. package/lib/network/core/networkCoreWorker.js.map +1 -1
  160. package/lib/network/core/networkCoreWorkerHandler.d.ts +3 -0
  161. package/lib/network/core/networkCoreWorkerHandler.d.ts.map +1 -1
  162. package/lib/network/core/networkCoreWorkerHandler.js +9 -0
  163. package/lib/network/core/networkCoreWorkerHandler.js.map +1 -1
  164. package/lib/network/core/types.d.ts +3 -0
  165. package/lib/network/core/types.d.ts.map +1 -1
  166. package/lib/network/gossip/gossipsub.d.ts +34 -0
  167. package/lib/network/gossip/gossipsub.d.ts.map +1 -1
  168. package/lib/network/gossip/gossipsub.js +123 -0
  169. package/lib/network/gossip/gossipsub.js.map +1 -1
  170. package/lib/network/network.d.ts +3 -0
  171. package/lib/network/network.d.ts.map +1 -1
  172. package/lib/network/network.js +9 -0
  173. package/lib/network/network.js.map +1 -1
  174. package/lib/network/options.d.ts +6 -0
  175. package/lib/network/options.d.ts.map +1 -1
  176. package/lib/network/options.js.map +1 -1
  177. package/lib/network/peers/peerManager.d.ts.map +1 -1
  178. package/lib/network/peers/peerManager.js +9 -0
  179. package/lib/network/peers/peerManager.js.map +1 -1
  180. package/lib/network/processor/gossipHandlers.js +1 -1
  181. package/lib/network/processor/gossipHandlers.js.map +1 -1
  182. package/lib/sync/backfill/backfill.d.ts.map +1 -1
  183. package/lib/sync/backfill/backfill.js +3 -4
  184. package/lib/sync/backfill/backfill.js.map +1 -1
  185. package/lib/sync/backfill/verify.d.ts +1 -2
  186. package/lib/sync/backfill/verify.d.ts.map +1 -1
  187. package/lib/sync/backfill/verify.js +2 -2
  188. package/lib/sync/backfill/verify.js.map +1 -1
  189. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  190. package/lib/sync/utils/downloadByRange.js +2 -2
  191. package/lib/sync/utils/downloadByRange.js.map +1 -1
  192. package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
  193. package/lib/sync/utils/downloadByRoot.js +1 -2
  194. package/lib/sync/utils/downloadByRoot.js.map +1 -1
  195. package/lib/util/queue/itemQueue.d.ts +10 -0
  196. package/lib/util/queue/itemQueue.d.ts.map +1 -1
  197. package/lib/util/queue/itemQueue.js +57 -0
  198. package/lib/util/queue/itemQueue.js.map +1 -1
  199. package/package.json +16 -16
  200. package/src/api/impl/beacon/blocks/index.ts +31 -19
  201. package/src/api/impl/lodestar/index.ts +29 -0
  202. package/src/api/impl/validator/index.ts +2 -1
  203. package/src/api/rest/base.ts +15 -13
  204. package/src/chain/ColumnReconstructionTracker.ts +8 -4
  205. package/src/chain/archiveStore/archiveStore.ts +10 -4
  206. package/src/chain/archiveStore/historicalState/getHistoricalState.ts +2 -1
  207. package/src/chain/blocks/blockInput/blockInput.ts +47 -4
  208. package/src/chain/blocks/importBlock.ts +10 -2
  209. package/src/chain/blocks/verifyBlock.ts +0 -1
  210. package/src/chain/blocks/verifyBlocksSignatures.ts +4 -12
  211. package/src/chain/blocks/verifyBlocksStateTransitionOnly.ts +1 -2
  212. package/src/chain/blocks/writeBlockInputToDb.ts +9 -0
  213. package/src/chain/bls/multithread/index.ts +7 -4
  214. package/src/chain/bls/multithread/jobItem.ts +7 -3
  215. package/src/chain/bls/singleThread.ts +5 -3
  216. package/src/chain/bls/utils.ts +15 -7
  217. package/src/chain/chain.ts +29 -37
  218. package/src/chain/initState.ts +2 -2
  219. package/src/chain/lightClient/index.ts +12 -6
  220. package/src/chain/options.ts +0 -2
  221. package/src/chain/regen/interface.ts +1 -1
  222. package/src/chain/regen/queued.ts +1 -2
  223. package/src/chain/regen/regen.ts +6 -1
  224. package/src/chain/seenCache/seenGossipBlockInput.ts +31 -12
  225. package/src/chain/serializeState.ts +2 -1
  226. package/src/chain/stateCache/index.ts +0 -2
  227. package/src/chain/stateCache/persistentCheckpointsCache.ts +6 -2
  228. package/src/chain/validation/aggregateAndProof.ts +3 -4
  229. package/src/chain/validation/attestation.ts +9 -13
  230. package/src/chain/validation/attesterSlashing.ts +1 -6
  231. package/src/chain/validation/blobSidecar.ts +3 -8
  232. package/src/chain/validation/block.ts +2 -3
  233. package/src/chain/validation/dataColumnSidecar.ts +3 -8
  234. package/src/chain/validation/executionPayloadBid.ts +5 -4
  235. package/src/chain/validation/payloadAttestationMessage.ts +1 -1
  236. package/src/chain/validation/proposerSlashing.ts +1 -6
  237. package/src/chain/validation/signatureSets/aggregateAndProof.ts +9 -14
  238. package/src/chain/validation/signatureSets/contributionAndProof.ts +2 -4
  239. package/src/chain/validation/signatureSets/selectionProof.ts +9 -9
  240. package/src/chain/validation/signatureSets/syncCommittee.ts +2 -4
  241. package/src/chain/validation/signatureSets/syncCommitteeContribution.ts +2 -3
  242. package/src/chain/validation/signatureSets/syncCommitteeSelectionProof.ts +2 -4
  243. package/src/chain/validation/syncCommittee.ts +1 -1
  244. package/src/chain/validation/syncCommitteeContributionAndProof.ts +3 -5
  245. package/src/chain/validation/voluntaryExit.ts +1 -1
  246. package/src/chain/validatorMonitor.ts +10 -5
  247. package/src/network/core/networkCore.ts +12 -0
  248. package/src/network/core/networkCoreWorker.ts +3 -0
  249. package/src/network/core/networkCoreWorkerHandler.ts +9 -0
  250. package/src/network/core/types.ts +6 -0
  251. package/src/network/gossip/gossipsub.ts +147 -1
  252. package/src/network/network.ts +12 -0
  253. package/src/network/options.ts +6 -0
  254. package/src/network/peers/peerManager.ts +11 -0
  255. package/src/network/processor/gossipHandlers.ts +1 -1
  256. package/src/sync/backfill/backfill.ts +3 -4
  257. package/src/sync/backfill/verify.ts +2 -3
  258. package/src/sync/utils/downloadByRange.ts +2 -2
  259. package/src/sync/utils/downloadByRoot.ts +1 -2
  260. package/src/util/queue/itemQueue.ts +62 -0
  261. package/lib/chain/stateCache/blockStateCacheImpl.d.ts +0 -54
  262. package/lib/chain/stateCache/blockStateCacheImpl.d.ts.map +0 -1
  263. package/lib/chain/stateCache/blockStateCacheImpl.js +0 -130
  264. package/lib/chain/stateCache/blockStateCacheImpl.js.map +0 -1
  265. package/lib/chain/stateCache/inMemoryCheckpointsCache.d.ts +0 -60
  266. package/lib/chain/stateCache/inMemoryCheckpointsCache.d.ts.map +0 -1
  267. package/lib/chain/stateCache/inMemoryCheckpointsCache.js +0 -156
  268. package/lib/chain/stateCache/inMemoryCheckpointsCache.js.map +0 -1
  269. package/lib/util/bytes.d.ts +0 -3
  270. package/lib/util/bytes.d.ts.map +0 -1
  271. package/lib/util/bytes.js +0 -11
  272. package/lib/util/bytes.js.map +0 -1
  273. package/src/chain/stateCache/blockStateCacheImpl.ts +0 -149
  274. package/src/chain/stateCache/inMemoryCheckpointsCache.ts +0 -192
  275. package/src/util/bytes.ts +0 -11
@@ -107,12 +107,10 @@ import {SeenAttestationDatas} from "./seenCache/seenAttestationData.js";
107
107
  import {SeenBlockAttesters} from "./seenCache/seenBlockAttesters.js";
108
108
  import {SeenBlockInput} from "./seenCache/seenGossipBlockInput.js";
109
109
  import {ShufflingCache} from "./shufflingCache.js";
110
- import {BlockStateCacheImpl} from "./stateCache/blockStateCacheImpl.js";
111
110
  import {DbCPStateDatastore, checkpointToDatastoreKey} from "./stateCache/datastore/db.js";
112
111
  import {FileCPStateDatastore} from "./stateCache/datastore/file.js";
113
112
  import {CPStateDatastore} from "./stateCache/datastore/types.js";
114
113
  import {FIFOBlockStateCache} from "./stateCache/fifoBlockStateCache.js";
115
- import {InMemoryCheckpointStateCache} from "./stateCache/inMemoryCheckpointsCache.js";
116
114
  import {PersistentCheckpointStateCache} from "./stateCache/persistentCheckpointsCache.js";
117
115
  import {CheckpointStateCache} from "./stateCache/types.js";
118
116
  import {ValidatorMonitor} from "./validatorMonitor.js";
@@ -128,8 +126,11 @@ const DEFAULT_MAX_CACHED_PRODUCED_RESULTS = 4;
128
126
 
129
127
  /**
130
128
  * The maximum number of pending unfinalized block writes to the database before backpressure is applied.
129
+ * Write queue entries hold references to block inputs, keeping them in memory even after cache eviction.
130
+ * This is especially important for supernodes which store all 128 columns per block — each pending
131
+ * write can hold significant memory. Keep moderate to avoid OOM during sync.
131
132
  */
132
- const DEFAULT_MAX_PENDING_UNFINALIZED_BLOCK_WRITES = 32;
133
+ const DEFAULT_MAX_PENDING_UNFINALIZED_BLOCK_WRITES = 16;
133
134
 
134
135
  export class BeaconChain implements IBeaconChain {
135
136
  readonly genesisTime: UintNum64;
@@ -142,7 +143,7 @@ export class BeaconChain implements IBeaconChain {
142
143
  readonly logger: Logger;
143
144
  readonly metrics: Metrics | null;
144
145
  readonly validatorMonitor: ValidatorMonitor | null;
145
- readonly bufferPool: BufferPool | null;
146
+ readonly bufferPool: BufferPool;
146
147
 
147
148
  readonly anchorStateLatestBlockSlot: Slot;
148
149
 
@@ -278,8 +279,8 @@ export class BeaconChain implements IBeaconChain {
278
279
  const emitter = new ChainEventEmitter();
279
280
  // by default, verify signatures on both main threads and worker threads
280
281
  const bls = opts.blsVerifyAllMainThread
281
- ? new BlsSingleThreadVerifier({metrics})
282
- : new BlsMultiThreadWorkerPool(opts, {logger, metrics});
282
+ ? new BlsSingleThreadVerifier({metrics, index2pubkey})
283
+ : new BlsMultiThreadWorkerPool(opts, {logger, metrics, index2pubkey});
283
284
 
284
285
  if (!clock) clock = new Clock({config, genesisTime: this.genesisTime, signal});
285
286
 
@@ -339,32 +340,22 @@ export class BeaconChain implements IBeaconChain {
339
340
  this.index2pubkey = index2pubkey;
340
341
 
341
342
  const fileDataStore = opts.nHistoricalStatesFileDataStore ?? true;
342
- const blockStateCache = this.opts.nHistoricalStates
343
- ? new FIFOBlockStateCache(this.opts, {metrics})
344
- : new BlockStateCacheImpl({metrics});
345
- this.bufferPool = this.opts.nHistoricalStates
346
- ? new BufferPool(anchorState.type.tree_serializedSize(anchorState.node), metrics)
347
- : null;
348
-
349
- let checkpointStateCache: CheckpointStateCache;
350
- this.cpStateDatastore = undefined;
351
- if (this.opts.nHistoricalStates) {
352
- this.cpStateDatastore = fileDataStore ? new FileCPStateDatastore(dataDir) : new DbCPStateDatastore(this.db);
353
- checkpointStateCache = new PersistentCheckpointStateCache(
354
- {
355
- config,
356
- metrics,
357
- logger,
358
- clock,
359
- blockStateCache,
360
- bufferPool: this.bufferPool,
361
- datastore: this.cpStateDatastore,
362
- },
363
- this.opts
364
- );
365
- } else {
366
- checkpointStateCache = new InMemoryCheckpointStateCache({metrics});
367
- }
343
+ const blockStateCache = new FIFOBlockStateCache(this.opts, {metrics});
344
+ this.bufferPool = new BufferPool(anchorState.type.tree_serializedSize(anchorState.node), metrics);
345
+
346
+ this.cpStateDatastore = fileDataStore ? new FileCPStateDatastore(dataDir) : new DbCPStateDatastore(this.db);
347
+ const checkpointStateCache: CheckpointStateCache = new PersistentCheckpointStateCache(
348
+ {
349
+ config,
350
+ metrics,
351
+ logger,
352
+ clock,
353
+ blockStateCache,
354
+ bufferPool: this.bufferPool,
355
+ datastore: this.cpStateDatastore,
356
+ },
357
+ this.opts
358
+ );
368
359
 
369
360
  const {checkpoint} = computeAnchorCheckpoint(config, anchorState);
370
361
  blockStateCache.add(anchorState);
@@ -387,6 +378,7 @@ export class BeaconChain implements IBeaconChain {
387
378
  forkChoice,
388
379
  blockStateCache,
389
380
  checkpointStateCache,
381
+ seenBlockInputCache: this.seenBlockInputCache,
390
382
  db,
391
383
  metrics,
392
384
  validatorMonitor,
@@ -396,7 +388,7 @@ export class BeaconChain implements IBeaconChain {
396
388
  });
397
389
 
398
390
  if (!opts.disableLightClientServer) {
399
- this.lightClientServer = new LightClientServer(opts, {config, clock, db, metrics, emitter, logger});
391
+ this.lightClientServer = new LightClientServer(opts, {config, clock, db, metrics, emitter, logger, signal});
400
392
  }
401
393
 
402
394
  this.reprocessController = new ReprocessController(this.metrics);
@@ -1368,13 +1360,13 @@ export class BeaconChain implements IBeaconChain {
1368
1360
  // TODO: Improve using regen here
1369
1361
  const {blockRoot, stateRoot, slot} = this.forkChoice.getHead();
1370
1362
  const headState = this.regen.getStateSync(stateRoot);
1371
- const headBlock = await this.db.block.get(fromHex(blockRoot));
1372
- if (headBlock == null) {
1373
- throw Error(`Head block ${slot} ${headBlock} is not available in database`);
1363
+ const blockResult = await this.getBlockByRoot(blockRoot);
1364
+ if (blockResult == null) {
1365
+ throw Error(`Head block for ${slot} is not available in cache or database`);
1374
1366
  }
1375
1367
 
1376
1368
  if (headState) {
1377
- this.opPool.pruneAll(headBlock, headState);
1369
+ this.opPool.pruneAll(blockResult.block, headState);
1378
1370
  }
1379
1371
 
1380
1372
  if (headState === null) {
@@ -2,7 +2,7 @@ import {ChainForkConfig} from "@lodestar/config";
2
2
  import {ZERO_HASH} from "@lodestar/params";
3
3
  import {BeaconStateAllForks, computeEpochAtSlot, computeStartSlotAtEpoch} from "@lodestar/state-transition";
4
4
  import {SignedBeaconBlock, ssz} from "@lodestar/types";
5
- import {Logger, toHex, toRootHex} from "@lodestar/utils";
5
+ import {Logger, byteArrayEquals, toHex, toRootHex} from "@lodestar/utils";
6
6
  import {GENESIS_SLOT} from "../constants/index.js";
7
7
  import {IBeaconDb} from "../db/index.js";
8
8
  import {Metrics} from "../metrics/index.js";
@@ -26,7 +26,7 @@ export async function persistAnchorState(
26
26
 
27
27
  const latestBlockRoot = ssz.phase0.BeaconBlockHeader.hashTreeRoot(latestBlockHeader);
28
28
 
29
- if (Buffer.compare(blockRoot, latestBlockRoot) !== 0) {
29
+ if (!byteArrayEquals(blockRoot, latestBlockRoot)) {
30
30
  throw Error(
31
31
  `Genesis block root ${toRootHex(blockRoot)} does not match genesis state latest block root ${toRootHex(latestBlockRoot)}`
32
32
  );
@@ -46,12 +46,11 @@ import {
46
46
  ssz,
47
47
  sszTypesFor,
48
48
  } from "@lodestar/types";
49
- import {Logger, MapDef, pruneSetToMax, toRootHex} from "@lodestar/utils";
49
+ import {Logger, MapDef, byteArrayEquals, pruneSetToMax, toRootHex} from "@lodestar/utils";
50
50
  import {ZERO_HASH} from "../../constants/index.js";
51
51
  import {IBeaconDb} from "../../db/index.js";
52
52
  import {NUM_WITNESS, NUM_WITNESS_ELECTRA} from "../../db/repositories/lightclientSyncCommitteeWitness.js";
53
53
  import {Metrics} from "../../metrics/index.js";
54
- import {byteArrayEquals} from "../../util/bytes.js";
55
54
  import {IClock} from "../../util/clock.js";
56
55
  import {ChainEventEmitter} from "../emitter.js";
57
56
  import {LightClientServerError, LightClientServerErrorCode} from "../errors/lightClientError.js";
@@ -93,6 +92,7 @@ type LightClientServerModules = {
93
92
  metrics: Metrics | null;
94
93
  emitter: ChainEventEmitter;
95
94
  logger: Logger;
95
+ signal: AbortSignal;
96
96
  };
97
97
 
98
98
  const MAX_CACHED_FINALIZED_HEADERS = 3;
@@ -205,6 +205,7 @@ export class LightClientServer {
205
205
  private readonly emitter: ChainEventEmitter;
206
206
  private readonly logger: Logger;
207
207
  private readonly clock: IClock;
208
+ private readonly signal: AbortSignal;
208
209
  private readonly knownSyncCommittee = new MapDef<SyncPeriod, Set<DependentRootHex>>(() => new Set());
209
210
  private storedCurrentSyncCommittee = false;
210
211
 
@@ -225,13 +226,14 @@ export class LightClientServer {
225
226
  private readonly opts: LightClientServerOpts,
226
227
  modules: LightClientServerModules
227
228
  ) {
228
- const {config, clock, db, metrics, emitter, logger} = modules;
229
+ const {config, clock, db, metrics, emitter, logger, signal} = modules;
229
230
  this.config = config;
230
231
  this.clock = clock;
231
232
  this.db = db;
232
233
  this.metrics = metrics;
233
234
  this.emitter = emitter;
234
235
  this.logger = logger;
236
+ this.signal = signal;
235
237
 
236
238
  this.zero = {
237
239
  // Assign the hightest fork's default value because it can always be typecasted down to correct fork
@@ -288,12 +290,16 @@ export class LightClientServer {
288
290
  const syncPeriod = computeSyncPeriodAtSlot(block.slot);
289
291
 
290
292
  this.onSyncAggregate(syncPeriod, block.body.syncAggregate, block.slot, signedBlockRoot).catch((e) => {
291
- this.logger.error("Error onSyncAggregate", {}, e);
292
- this.metrics?.lightclientServer.onSyncAggregate.inc({event: "error"});
293
+ if (!this.signal.aborted) {
294
+ this.logger.error("Error onSyncAggregate", {}, e);
295
+ this.metrics?.lightclientServer.onSyncAggregate.inc({event: "error"});
296
+ }
293
297
  });
294
298
 
295
299
  this.persistPostBlockImportData(block, postState, parentBlockSlot).catch((e) => {
296
- this.logger.error("Error persistPostBlockImportData", {}, e);
300
+ if (!this.signal.aborted) {
301
+ this.logger.error("Error persistPostBlockImportData", {}, e);
302
+ }
297
303
  });
298
304
  }
299
305
 
@@ -45,7 +45,6 @@ export type IChainOptions = BlockProcessOpts &
45
45
  broadcastValidationStrictness?: string;
46
46
  minSameMessageSignatureSetsToBatch: number;
47
47
  archiveDateEpochs?: number;
48
- nHistoricalStates?: boolean;
49
48
  nHistoricalStatesFileDataStore?: boolean;
50
49
  };
51
50
 
@@ -119,7 +118,6 @@ export const defaultChainOptions: IChainOptions = {
119
118
  // batching too much may block the I/O thread so if useWorker=false, suggest this value to be 32
120
119
  // since this batch attestation work is designed to work with useWorker=true, make this the lowest value
121
120
  minSameMessageSignatureSetsToBatch: 2,
122
- nHistoricalStates: true,
123
121
  // as of Feb 2025, this option turned out to be very useful:
124
122
  // - it allows to share a persisted checkpoint state to other nodes
125
123
  // - users can prune the persisted checkpoint state files manually to save disc space
@@ -2,7 +2,7 @@ import {routes} from "@lodestar/api";
2
2
  import {ProtoBlock} from "@lodestar/fork-choice";
3
3
  import {CachedBeaconStateAllForks} from "@lodestar/state-transition";
4
4
  import {BeaconBlock, Epoch, RootHex, Slot, phase0} from "@lodestar/types";
5
- import {CheckpointHex} from "../stateCache/index.js";
5
+ import {CheckpointHex} from "../stateCache/types.js";
6
6
 
7
7
  export enum RegenCaller {
8
8
  getDuties = "getDuties",
@@ -5,8 +5,7 @@ import {BeaconBlock, Epoch, RootHex, Slot, phase0} from "@lodestar/types";
5
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 {CheckpointHex} from "../stateCache/index.js";
9
- import {BlockStateCache, CheckpointStateCache} from "../stateCache/types.js";
8
+ import {BlockStateCache, CheckpointHex, CheckpointStateCache} from "../stateCache/types.js";
10
9
  import {RegenError, RegenErrorCode} from "./errors.js";
11
10
  import {
12
11
  IStateRegenerator,
@@ -18,6 +18,7 @@ import {Metrics} from "../../metrics/index.js";
18
18
  import {nextEventLoop} from "../../util/eventLoop.js";
19
19
  import {getCheckpointFromState} from "../blocks/utils/checkpoint.js";
20
20
  import {ChainEvent, ChainEventEmitter} from "../emitter.js";
21
+ import {SeenBlockInput} from "../seenCache/seenGossipBlockInput.js";
21
22
  import {BlockStateCache, CheckpointStateCache} from "../stateCache/types.js";
22
23
  import {ValidatorMonitor} from "../validatorMonitor.js";
23
24
  import {RegenError, RegenErrorCode} from "./errors.js";
@@ -28,6 +29,7 @@ export type RegenModules = {
28
29
  forkChoice: IForkChoice;
29
30
  blockStateCache: BlockStateCache;
30
31
  checkpointStateCache: CheckpointStateCache;
32
+ seenBlockInputCache: SeenBlockInput;
31
33
  config: ChainForkConfig;
32
34
  emitter: ChainEventEmitter;
33
35
  logger: Logger;
@@ -191,7 +193,10 @@ export class StateRegenerator implements IStateRegeneratorInternal {
191
193
  const protoBlocksAsc = blocksToReplay.reverse();
192
194
  for (const [i, protoBlock] of protoBlocksAsc.entries()) {
193
195
  replaySlots[i] = protoBlock.slot;
194
- blockPromises[i] = this.modules.db.block.get(fromHex(protoBlock.blockRoot));
196
+ const blockInput = this.modules.seenBlockInputCache.get(protoBlock.blockRoot);
197
+ blockPromises[i] = blockInput?.hasBlock()
198
+ ? Promise.resolve(blockInput.getBlock())
199
+ : this.modules.db.block.get(fromHex(protoBlock.blockRoot));
195
200
  }
196
201
 
197
202
  const logCtx = {stateRoot, caller, replaySlots: replaySlots.join(",")};
@@ -1,10 +1,19 @@
1
1
  import {ChainForkConfig} from "@lodestar/config";
2
2
  import {CheckpointWithHex} from "@lodestar/fork-choice";
3
- import {ForkName, ForkPostFulu, ForkPreGloas, isForkPostDeneb, isForkPostFulu, isForkPostGloas} from "@lodestar/params";
3
+ import {
4
+ ForkName,
5
+ ForkPostFulu,
6
+ ForkPreGloas,
7
+ SLOTS_PER_EPOCH,
8
+ isForkPostDeneb,
9
+ isForkPostFulu,
10
+ isForkPostGloas,
11
+ } from "@lodestar/params";
4
12
  import {computeStartSlotAtEpoch} from "@lodestar/state-transition";
5
13
  import {BLSSignature, RootHex, SignedBeaconBlock, Slot, deneb, fulu} from "@lodestar/types";
6
- import {LodestarError, Logger, pruneSetToMax} from "@lodestar/utils";
14
+ import {LodestarError, Logger, byteArrayEquals, pruneSetToMax} from "@lodestar/utils";
7
15
  import {Metrics} from "../../metrics/metrics.js";
16
+ import {MAX_LOOK_AHEAD_EPOCHS} from "../../sync/constants.js";
8
17
  import {IClock} from "../../util/clock.js";
9
18
  import {CustodyConfig} from "../../util/dataColumns.js";
10
19
  import {
@@ -26,7 +35,17 @@ import {
26
35
  } from "../blocks/blockInput/index.js";
27
36
  import {ChainEvent, ChainEventEmitter} from "../emitter.js";
28
37
 
29
- const MAX_BLOCK_INPUT_CACHE_SIZE = 5;
38
+ // Target size for the block input cache, enforced by pruneToMaxSize() which runs after prune()
39
+ // and onFinalized() — NOT on insertion. The cache can temporarily exceed this during range sync
40
+ // (e.g. 32 blocks inserted per batch) but is trimmed back after blocks are processed.
41
+ //
42
+ // Must be large enough to hold blocks from all concurrently downloaded range sync batches.
43
+ // Range sync downloads up to MAX_LOOK_AHEAD_EPOCHS batches ahead of the processing head,
44
+ // so up to (MAX_LOOK_AHEAD_EPOCHS + 1) batches (current + look-ahead) of SLOTS_PER_EPOCH
45
+ // blocks can be in the cache simultaneously. If this value is too small, pruneToMaxSize()
46
+ // will evict blocks from the batch being processed before they are persisted to the database,
47
+ // causing errors when async handlers like onForkChoiceFinalized run.
48
+ const MAX_BLOCK_INPUT_CACHE_SIZE = (MAX_LOOK_AHEAD_EPOCHS + 1) * SLOTS_PER_EPOCH;
30
49
 
31
50
  export type SeenBlockInputCacheModules = {
32
51
  config: ChainForkConfig;
@@ -64,14 +83,14 @@ export type GetByBlobOptions = {
64
83
  * - onFinalized event handler will help to prune any non-canonical forks once the chain finalizes. Any block-slots that
65
84
  * are before the finalized checkpoint will be pruned.
66
85
  * - Range-sync periods. The range process uses this cache to store and sync blocks with DA data as the chain is pulled
67
- * from peers. We pull batches, by epoch, so 32 slots are pulled at a time and several batches are pulled concurrently.
68
- * It is important to set the MAX_BLOCK_INPUT_CACHE_SIZE high enough to support range sync activities. Currently the
69
- * value is set for 5 batches of 32 slots. As process block is called (similar to following head) the BlockInput and
70
- * its ancestors will be pruned.
86
+ * from peers. We pull batches, by epoch, so 32 slots are pulled at a time and several batches are downloaded
87
+ * concurrently (up to MAX_LOOK_AHEAD_EPOCHS ahead). All downloaded blocks are added to this shared cache, so it
88
+ * must be large enough to hold blocks from all concurrent batches. If pruneToMaxSize() evicts blocks from the batch
89
+ * currently being processed, those blocks may not yet be persisted to the database, causing getBlockByRoot() to fail
90
+ * when async event handlers (e.g. onForkChoiceFinalized) try to look them up.
71
91
  * - Non-Finality times. This is a bit more tricky. There can be long periods of non-finality and storing everything
72
- * will cause OOM. The pruneToMax will help ensure a hard limit on the number of stored blocks (with DA) that are held
73
- * in memory at any one time. The value for MAX_BLOCK_INPUT_CACHE_SIZE is set to accommodate range-sync but in
74
- * practice this value may need to be massaged in the future if we find issues when debugging non-finality
92
+ * will cause OOM. The pruneToMaxSize will help ensure the number of stored blocks (with DA) is trimmed back to
93
+ * MAX_BLOCK_INPUT_CACHE_SIZE after each prune() or onFinalized() call
75
94
  */
76
95
 
77
96
  export class SeenBlockInput {
@@ -344,7 +363,7 @@ export class SeenBlockInput {
344
363
  return false;
345
364
  }
346
365
  // Only consider verified if the signature matches
347
- return Buffer.compare(cachedSignature, signature) === 0;
366
+ return byteArrayEquals(cachedSignature, signature);
348
367
  }
349
368
 
350
369
  /**
@@ -379,7 +398,7 @@ export class SeenBlockInput {
379
398
  let itemsToDelete = this.blockInputs.size - MAX_BLOCK_INPUT_CACHE_SIZE;
380
399
 
381
400
  if (itemsToDelete > 0) {
382
- const sorted = [...this.blockInputs.entries()].sort((a, b) => b[1].slot - a[1].slot);
401
+ const sorted = [...this.blockInputs.entries()].sort((a, b) => a[1].slot - b[1].slot);
383
402
  for (const [rootHex] of sorted) {
384
403
  this.blockInputs.delete(rootHex);
385
404
  itemsToDelete--;
@@ -20,7 +20,8 @@ export async function serializeState<T>(
20
20
  stateBytes = bufferWithKey.buffer;
21
21
  const dataView = new DataView(stateBytes.buffer, stateBytes.byteOffset, stateBytes.byteLength);
22
22
  state.serializeToBytes({uint8Array: stateBytes, dataView}, 0);
23
- return processFn(stateBytes);
23
+ // Await to ensure buffer is not released back to pool until processFn completes
24
+ return await processFn(stateBytes);
24
25
  }
25
26
  // release the buffer back to the pool automatically
26
27
  }
@@ -1,3 +1 @@
1
- export * from "./blockStateCacheImpl.js";
2
1
  export * from "./fifoBlockStateCache.js";
3
- export * from "./inMemoryCheckpointsCache.js";
@@ -31,7 +31,7 @@ type PersistentCheckpointStateCacheModules = {
31
31
  signal?: AbortSignal;
32
32
  datastore: CPStateDatastore;
33
33
  blockStateCache: BlockStateCache;
34
- bufferPool?: BufferPool | null;
34
+ bufferPool?: BufferPool;
35
35
  };
36
36
 
37
37
  /** checkpoint serialized as a string */
@@ -119,7 +119,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache {
119
119
  private readonly maxEpochsOnDisk: number;
120
120
  private readonly datastore: CPStateDatastore;
121
121
  private readonly blockStateCache: BlockStateCache;
122
- private readonly bufferPool?: BufferPool | null;
122
+ private readonly bufferPool?: BufferPool;
123
123
 
124
124
  constructor(
125
125
  {
@@ -851,6 +851,10 @@ export function toCheckpointHex(checkpoint: phase0.Checkpoint): CheckpointHex {
851
851
  };
852
852
  }
853
853
 
854
+ export function toCheckpointKey(cp: CheckpointHex): string {
855
+ return `${cp.rootHex}:${cp.epoch}`;
856
+ }
857
+
854
858
  function toCacheKey(cp: CheckpointHex | phase0.Checkpoint): CacheKey {
855
859
  if (isCheckpointHex(cp)) {
856
860
  return `${cp.rootHex}_${cp.epoch}`;
@@ -239,16 +239,15 @@ async function validateAggregateAndProof(
239
239
  // by the validator with index aggregate_and_proof.aggregator_index.
240
240
  // [REJECT] The aggregator signature, signed_aggregate_and_proof.signature, is valid.
241
241
  // [REJECT] The signature of aggregate is valid.
242
- const aggregator = chain.index2pubkey[aggregateAndProof.aggregatorIndex];
243
242
  const signingRoot = cachedAttData ? cachedAttData.signingRoot : getAttestationDataSigningRoot(chain.config, attData);
244
243
  const indexedAttestationSignatureSet = createAggregateSignatureSetFromComponents(
245
- indexedAttestation.attestingIndices.map((i) => chain.index2pubkey[i]),
244
+ indexedAttestation.attestingIndices,
246
245
  signingRoot,
247
246
  indexedAttestation.signature
248
247
  );
249
248
  const signatureSets = [
250
- getSelectionProofSignatureSet(chain.config, attSlot, aggregator, signedAggregateAndProof),
251
- getAggregateAndProofSignatureSet(chain.config, attEpoch, aggregator, signedAggregateAndProof),
249
+ getSelectionProofSignatureSet(chain.config, attSlot, aggregatorIndex, signedAggregateAndProof),
250
+ getAggregateAndProofSignatureSet(chain.config, attEpoch, aggregatorIndex, signedAggregateAndProof),
252
251
  indexedAttestationSignatureSet,
253
252
  ];
254
253
  // no need to write to SeenAttestationDatas
@@ -14,13 +14,13 @@ import {
14
14
  } from "@lodestar/params";
15
15
  import {
16
16
  EpochShuffling,
17
+ IndexedSignatureSet,
17
18
  ShufflingError,
18
19
  ShufflingErrorCode,
19
- SingleSignatureSet,
20
20
  computeEpochAtSlot,
21
21
  computeSigningRoot,
22
22
  computeStartSlotAtEpoch,
23
- createSingleSignatureSetFromComponents,
23
+ createIndexedSignatureSetFromComponents,
24
24
  } from "@lodestar/state-transition";
25
25
  import {
26
26
  CommitteeIndex,
@@ -90,7 +90,7 @@ export type GossipAttestation = {
90
90
  };
91
91
 
92
92
  export type Step0Result = AttestationValidationResult & {
93
- signatureSet: SingleSignatureSet;
93
+ signatureSet: IndexedSignatureSet;
94
94
  validatorIndex: number;
95
95
  };
96
96
 
@@ -125,7 +125,7 @@ export async function validateGossipAttestationsSameAttData(
125
125
  // step1: verify signatures of all valid attestations
126
126
  // map new index to index in resultOrErrors
127
127
  const newIndexToOldIndex = new Map<number, number>();
128
- const signatureSets: SingleSignatureSet[] = [];
128
+ const signatureSets: IndexedSignatureSet[] = [];
129
129
  let newIndex = 0;
130
130
  const step0Results: Step0Result[] = [];
131
131
  for (const [i, resultOrError] of step0ResultOrErrors.entries()) {
@@ -143,7 +143,7 @@ export async function validateGossipAttestationsSameAttData(
143
143
  if (batchableBls) {
144
144
  // all signature sets should have same signing root since we filtered in network processor
145
145
  signatureValids = await chain.bls.verifySignatureSetsSameMessage(
146
- signatureSets.map((set) => ({publicKey: set.pubkey, signature: set.signature})),
146
+ signatureSets.map((set) => ({publicKey: chain.index2pubkey[set.index], signature: set.signature})),
147
147
  signatureSets[0].signingRoot
148
148
  );
149
149
  } else {
@@ -498,7 +498,7 @@ async function validateAttestationNoSignatureCheck(
498
498
 
499
499
  // [REJECT] The signature of attestation is valid.
500
500
  const attestingIndices = [validatorIndex];
501
- let signatureSet: SingleSignatureSet;
501
+ let signatureSet: IndexedSignatureSet;
502
502
  let attDataRootHex: RootHex;
503
503
  const signature = attestationOrCache.attestation
504
504
  ? attestationOrCache.attestation.signature
@@ -513,18 +513,14 @@ async function validateAttestationNoSignatureCheck(
513
513
 
514
514
  if (attestationOrCache.cache) {
515
515
  // there could be up to 6% of cpu time to compute signing root if we don't clone the signature set
516
- signatureSet = createSingleSignatureSetFromComponents(
517
- chain.index2pubkey[validatorIndex],
516
+ signatureSet = createIndexedSignatureSetFromComponents(
517
+ validatorIndex,
518
518
  attestationOrCache.cache.signingRoot,
519
519
  signature
520
520
  );
521
521
  attDataRootHex = attestationOrCache.cache.attDataRootHex;
522
522
  } else {
523
- signatureSet = createSingleSignatureSetFromComponents(
524
- chain.index2pubkey[validatorIndex],
525
- getSigningRoot(),
526
- signature
527
- );
523
+ signatureSet = createIndexedSignatureSetFromComponents(validatorIndex, getSigningRoot(), signature);
528
524
 
529
525
  // add cached attestation data before verifying signature
530
526
  attDataRootHex = toRootHex(ssz.phase0.AttestationData.hashTreeRoot(attData));
@@ -58,12 +58,7 @@ export async function validateAttesterSlashing(
58
58
  });
59
59
  }
60
60
 
61
- const signatureSets = getAttesterSlashingSignatureSets(
62
- chain.config,
63
- chain.index2pubkey,
64
- state.slot,
65
- attesterSlashing
66
- );
61
+ const signatureSets = getAttesterSlashingSignatureSets(chain.config, state.slot, attesterSlashing);
67
62
  if (!(await chain.bls.verifySignatureSets(signatureSets, {batchable: true, priority: prioritizeBls}))) {
68
63
  throw new AttesterSlashingError(GossipAction.REJECT, {
69
64
  code: AttesterSlashingErrorCode.INVALID,
@@ -12,7 +12,7 @@ import {
12
12
  getBlockHeaderProposerSignatureSetByParentStateSlot,
13
13
  } from "@lodestar/state-transition";
14
14
  import {BlobIndex, Root, Slot, SubnetID, deneb, ssz} from "@lodestar/types";
15
- import {toRootHex, verifyMerkleBranch} from "@lodestar/utils";
15
+ import {byteArrayEquals, toRootHex, verifyMerkleBranch} from "@lodestar/utils";
16
16
  import {kzg} from "../../util/kzg.js";
17
17
  import {BlobSidecarErrorCode, BlobSidecarGossipError, BlobSidecarValidationError} from "../errors/blobSidecarError.js";
18
18
  import {GossipAction} from "../errors/gossipValidation.js";
@@ -139,7 +139,6 @@ export async function validateGossipBlobSidecar(
139
139
  if (!chain.seenBlockInputCache.isVerifiedProposerSignature(blobSlot, blockHex, signature)) {
140
140
  const signatureSet = getBlockHeaderProposerSignatureSetByParentStateSlot(
141
141
  chain.config,
142
- chain.index2pubkey,
143
142
  blockState.slot,
144
143
  blobSidecar.signedBlockHeader
145
144
  );
@@ -227,7 +226,7 @@ export async function validateBlockBlobSidecars(
227
226
  const firstSidecarSignedBlockHeader = blobSidecars[0].signedBlockHeader;
228
227
  const firstSidecarBlockHeader = firstSidecarSignedBlockHeader.message;
229
228
  const firstBlockRoot = ssz.phase0.BeaconBlockHeader.hashTreeRoot(firstSidecarBlockHeader);
230
- if (Buffer.compare(blockRoot, firstBlockRoot) !== 0) {
229
+ if (!byteArrayEquals(blockRoot, firstBlockRoot)) {
231
230
  throw new BlobSidecarValidationError(
232
231
  {
233
232
  code: BlobSidecarErrorCode.INCORRECT_BLOCK,
@@ -244,11 +243,7 @@ export async function validateBlockBlobSidecars(
244
243
  const blockRootHex = toRootHex(blockRoot);
245
244
  const signature = firstSidecarSignedBlockHeader.signature;
246
245
  if (!chain.seenBlockInputCache.isVerifiedProposerSignature(blockSlot, blockRootHex, signature)) {
247
- const signatureSet = getBlockHeaderProposerSignatureSetByHeaderSlot(
248
- chain.config,
249
- chain.index2pubkey,
250
- firstSidecarSignedBlockHeader
251
- );
246
+ const signatureSet = getBlockHeaderProposerSignatureSetByHeaderSlot(chain.config, firstSidecarSignedBlockHeader);
252
247
 
253
248
  if (
254
249
  !(await chain.bls.verifySignatureSets([signatureSet], {
@@ -138,11 +138,10 @@ export async function validateGossipBlock(
138
138
  // in forky condition, make sure to populate ShufflingCache with regened state
139
139
  chain.shufflingCache.processState(blockState);
140
140
 
141
- // Extra conditions for merge fork blocks
142
141
  // [REJECT] The block's execution payload timestamp is correct with respect to the slot
143
142
  // -- i.e. execution_payload.timestamp == compute_timestamp_at_slot(state, block.slot).
144
143
  if (isForkPostBellatrix(fork) && !isForkPostGloas(fork)) {
145
- if (!isExecutionBlockBodyType(block.body)) throw Error("Not merge block type");
144
+ if (!isExecutionBlockBodyType(block.body)) throw Error("Not execution block body type");
146
145
  const executionPayload = block.body.executionPayload;
147
146
  if (isExecutionStateType(blockState) && isExecutionEnabled(blockState, block)) {
148
147
  const expectedTimestamp = computeTimeAtSlot(config, blockSlot, chain.genesisTime);
@@ -158,7 +157,7 @@ export async function validateGossipBlock(
158
157
 
159
158
  // [REJECT] The proposer signature, signed_beacon_block.signature, is valid with respect to the proposer_index pubkey.
160
159
  if (!chain.seenBlockInputCache.isVerifiedProposerSignature(blockSlot, blockRoot, signedBlock.signature)) {
161
- const signatureSet = getBlockProposerSignatureSet(chain.config, chain.index2pubkey, signedBlock);
160
+ const signatureSet = getBlockProposerSignatureSet(chain.config, signedBlock);
162
161
  // Don't batch so verification is not delayed
163
162
  if (!(await chain.bls.verifySignatureSets([signatureSet], {verifyOnMainThread: true}))) {
164
163
  throw new BlockGossipError(GossipAction.REJECT, {
@@ -11,7 +11,7 @@ import {
11
11
  getBlockHeaderProposerSignatureSetByParentStateSlot,
12
12
  } from "@lodestar/state-transition";
13
13
  import {Root, Slot, SubnetID, fulu, ssz} from "@lodestar/types";
14
- import {toRootHex, verifyMerkleBranch} from "@lodestar/utils";
14
+ import {byteArrayEquals, toRootHex, verifyMerkleBranch} from "@lodestar/utils";
15
15
  import {Metrics} from "../../metrics/metrics.js";
16
16
  import {kzg} from "../../util/kzg.js";
17
17
  import {
@@ -136,7 +136,6 @@ export async function validateGossipDataColumnSidecar(
136
136
  if (!chain.seenBlockInputCache.isVerifiedProposerSignature(blockHeader.slot, blockRootHex, signature)) {
137
137
  const signatureSet = getBlockHeaderProposerSignatureSetByParentStateSlot(
138
138
  chain.config,
139
- chain.index2pubkey,
140
139
  blockState.slot,
141
140
  dataColumnSidecar.signedBlockHeader
142
141
  );
@@ -319,7 +318,7 @@ export async function validateBlockDataColumnSidecars(
319
318
  const firstSidecarSignedBlockHeader = dataColumnSidecars[0].signedBlockHeader;
320
319
  const firstSidecarBlockHeader = firstSidecarSignedBlockHeader.message;
321
320
  const firstBlockRoot = ssz.phase0.BeaconBlockHeader.hashTreeRoot(firstSidecarBlockHeader);
322
- if (Buffer.compare(blockRoot, firstBlockRoot) !== 0) {
321
+ if (!byteArrayEquals(blockRoot, firstBlockRoot)) {
323
322
  throw new DataColumnSidecarValidationError(
324
323
  {
325
324
  code: DataColumnSidecarErrorCode.INCORRECT_BLOCK,
@@ -337,11 +336,7 @@ export async function validateBlockDataColumnSidecars(
337
336
  const slot = firstSidecarSignedBlockHeader.message.slot;
338
337
  const signature = firstSidecarSignedBlockHeader.signature;
339
338
  if (!chain.seenBlockInputCache.isVerifiedProposerSignature(slot, rootHex, signature)) {
340
- const signatureSet = getBlockHeaderProposerSignatureSetByHeaderSlot(
341
- chain.config,
342
- chain.index2pubkey,
343
- firstSidecarSignedBlockHeader
344
- );
339
+ const signatureSet = getBlockHeaderProposerSignatureSetByHeaderSlot(chain.config, firstSidecarSignedBlockHeader);
345
340
 
346
341
  if (
347
342
  !(await chain.bls.verifySignatureSets([signatureSet], {
@@ -53,7 +53,8 @@ async function validateExecutionPayloadBid(
53
53
 
54
54
  // [REJECT] `bid.builder_index` is a valid/active builder index -- i.e.
55
55
  // `is_active_builder(state, bid.builder_index)` returns `True`.
56
- if (!isActiveBuilder(state, bid.builderIndex)) {
56
+ const builder = state.builders.getReadonly(bid.builderIndex);
57
+ if (!isActiveBuilder(builder, state.finalizedCheckpoint.epoch)) {
57
58
  throw new ExecutionPayloadBidError(GossipAction.REJECT, {
58
59
  code: ExecutionPayloadBidErrorCode.BUILDER_NOT_ELIGIBLE,
59
60
  builderIndex: bid.builderIndex,
@@ -102,7 +103,7 @@ async function validateExecutionPayloadBid(
102
103
  throw new ExecutionPayloadBidError(GossipAction.IGNORE, {
103
104
  code: ExecutionPayloadBidErrorCode.BID_TOO_HIGH,
104
105
  bidValue: bid.value,
105
- builderBalance: state.builders.getReadonly(bid.builderIndex).balance,
106
+ builderBalance: builder.balance,
106
107
  });
107
108
  }
108
109
 
@@ -122,8 +123,8 @@ async function validateExecutionPayloadBid(
122
123
 
123
124
  // [REJECT] `signed_execution_payload_bid.signature` is valid with respect to the `bid.builder_index`.
124
125
  const signatureSet = createSingleSignatureSetFromComponents(
125
- PublicKey.fromBytes(state.builders.getReadonly(bid.builderIndex).pubkey),
126
- getExecutionPayloadBidSigningRoot(chain.config, state as CachedBeaconStateGloas, bid),
126
+ PublicKey.fromBytes(builder.pubkey),
127
+ getExecutionPayloadBidSigningRoot(chain.config, state.slot, bid),
127
128
  signedExecutionPayloadBid.signature
128
129
  );
129
130