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

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 (273) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +7 -7
  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 +10 -2
  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 +9 -8
  9. package/lib/api/impl/validator/index.js.map +1 -1
  10. package/lib/chain/ColumnReconstructionTracker.d.ts +2 -0
  11. package/lib/chain/ColumnReconstructionTracker.d.ts.map +1 -1
  12. package/lib/chain/ColumnReconstructionTracker.js +7 -3
  13. package/lib/chain/ColumnReconstructionTracker.js.map +1 -1
  14. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  15. package/lib/chain/blocks/verifyBlock.js +1 -1
  16. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  17. package/lib/chain/blocks/verifyBlocksSignatures.d.ts +2 -2
  18. package/lib/chain/blocks/verifyBlocksSignatures.d.ts.map +1 -1
  19. package/lib/chain/blocks/verifyBlocksSignatures.js +2 -2
  20. package/lib/chain/blocks/verifyBlocksSignatures.js.map +1 -1
  21. package/lib/chain/bls/multithread/index.d.ts +3 -1
  22. package/lib/chain/bls/multithread/index.d.ts.map +1 -1
  23. package/lib/chain/bls/multithread/index.js +5 -3
  24. package/lib/chain/bls/multithread/index.js.map +1 -1
  25. package/lib/chain/bls/multithread/jobItem.d.ts +2 -2
  26. package/lib/chain/bls/multithread/jobItem.d.ts.map +1 -1
  27. package/lib/chain/bls/multithread/jobItem.js +2 -2
  28. package/lib/chain/bls/multithread/jobItem.js.map +1 -1
  29. package/lib/chain/bls/singleThread.d.ts +4 -2
  30. package/lib/chain/bls/singleThread.d.ts.map +1 -1
  31. package/lib/chain/bls/singleThread.js +4 -2
  32. package/lib/chain/bls/singleThread.js.map +1 -1
  33. package/lib/chain/bls/utils.d.ts +2 -2
  34. package/lib/chain/bls/utils.d.ts.map +1 -1
  35. package/lib/chain/bls/utils.js +9 -6
  36. package/lib/chain/bls/utils.js.map +1 -1
  37. package/lib/chain/chain.d.ts +8 -3
  38. package/lib/chain/chain.d.ts.map +1 -1
  39. package/lib/chain/chain.js +36 -18
  40. package/lib/chain/chain.js.map +1 -1
  41. package/lib/chain/errors/attestationError.d.ts +14 -1
  42. package/lib/chain/errors/attestationError.d.ts.map +1 -1
  43. package/lib/chain/errors/attestationError.js +8 -0
  44. package/lib/chain/errors/attestationError.js.map +1 -1
  45. package/lib/chain/errors/executionPayloadBid.d.ts +48 -0
  46. package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -0
  47. package/lib/chain/errors/executionPayloadBid.js +15 -0
  48. package/lib/chain/errors/executionPayloadBid.js.map +1 -0
  49. package/lib/chain/errors/executionPayloadEnvelope.d.ts +48 -0
  50. package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -0
  51. package/lib/chain/errors/executionPayloadEnvelope.js +16 -0
  52. package/lib/chain/errors/executionPayloadEnvelope.js.map +1 -0
  53. package/lib/chain/errors/index.d.ts +3 -0
  54. package/lib/chain/errors/index.d.ts.map +1 -1
  55. package/lib/chain/errors/index.js +3 -0
  56. package/lib/chain/errors/index.js.map +1 -1
  57. package/lib/chain/errors/payloadAttestation.d.ts +34 -0
  58. package/lib/chain/errors/payloadAttestation.d.ts.map +1 -0
  59. package/lib/chain/errors/payloadAttestation.js +13 -0
  60. package/lib/chain/errors/payloadAttestation.js.map +1 -0
  61. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  62. package/lib/chain/forkChoice/index.js +18 -0
  63. package/lib/chain/forkChoice/index.js.map +1 -1
  64. package/lib/chain/interface.d.ts +7 -2
  65. package/lib/chain/interface.d.ts.map +1 -1
  66. package/lib/chain/interface.js.map +1 -1
  67. package/lib/chain/opPools/executionPayloadBidPool.d.ts +21 -0
  68. package/lib/chain/opPools/executionPayloadBidPool.d.ts.map +1 -0
  69. package/lib/chain/opPools/executionPayloadBidPool.js +57 -0
  70. package/lib/chain/opPools/executionPayloadBidPool.js.map +1 -0
  71. package/lib/chain/opPools/index.d.ts +2 -0
  72. package/lib/chain/opPools/index.d.ts.map +1 -1
  73. package/lib/chain/opPools/index.js +2 -0
  74. package/lib/chain/opPools/index.js.map +1 -1
  75. package/lib/chain/opPools/payloadAttestationPool.d.ts +24 -0
  76. package/lib/chain/opPools/payloadAttestationPool.d.ts.map +1 -0
  77. package/lib/chain/opPools/payloadAttestationPool.js +109 -0
  78. package/lib/chain/opPools/payloadAttestationPool.js.map +1 -0
  79. package/lib/chain/prepareNextSlot.js +6 -4
  80. package/lib/chain/prepareNextSlot.js.map +1 -1
  81. package/lib/chain/produceBlock/produceBlockBody.d.ts +3 -2
  82. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  83. package/lib/chain/produceBlock/produceBlockBody.js +5 -3
  84. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  85. package/lib/chain/regen/interface.d.ts +3 -8
  86. package/lib/chain/regen/interface.d.ts.map +1 -1
  87. package/lib/chain/regen/interface.js +1 -1
  88. package/lib/chain/regen/interface.js.map +1 -1
  89. package/lib/chain/regen/queued.d.ts +1 -2
  90. package/lib/chain/regen/queued.d.ts.map +1 -1
  91. package/lib/chain/regen/queued.js +2 -16
  92. package/lib/chain/regen/queued.js.map +1 -1
  93. package/lib/chain/regen/regen.d.ts +5 -7
  94. package/lib/chain/regen/regen.d.ts.map +1 -1
  95. package/lib/chain/regen/regen.js +7 -17
  96. package/lib/chain/regen/regen.js.map +1 -1
  97. package/lib/chain/seenCache/index.d.ts +3 -1
  98. package/lib/chain/seenCache/index.d.ts.map +1 -1
  99. package/lib/chain/seenCache/index.js +3 -1
  100. package/lib/chain/seenCache/index.js.map +1 -1
  101. package/lib/chain/seenCache/seenAttesters.d.ts +5 -0
  102. package/lib/chain/seenCache/seenAttesters.d.ts.map +1 -1
  103. package/lib/chain/seenCache/seenAttesters.js +5 -0
  104. package/lib/chain/seenCache/seenAttesters.js.map +1 -1
  105. package/lib/chain/seenCache/seenExecutionPayloadBids.d.ts +12 -0
  106. package/lib/chain/seenCache/seenExecutionPayloadBids.d.ts.map +1 -0
  107. package/lib/chain/seenCache/seenExecutionPayloadBids.js +30 -0
  108. package/lib/chain/seenCache/seenExecutionPayloadBids.js.map +1 -0
  109. package/lib/chain/seenCache/seenExecutionPayloadEnvelope.d.ts +15 -0
  110. package/lib/chain/seenCache/seenExecutionPayloadEnvelope.d.ts.map +1 -0
  111. package/lib/chain/seenCache/seenExecutionPayloadEnvelope.js +28 -0
  112. package/lib/chain/seenCache/seenExecutionPayloadEnvelope.js.map +1 -0
  113. package/lib/chain/seenCache/seenGossipBlockInput.js +1 -1
  114. package/lib/chain/validation/aggregateAndProof.js +35 -14
  115. package/lib/chain/validation/aggregateAndProof.js.map +1 -1
  116. package/lib/chain/validation/attestation.d.ts +2 -2
  117. package/lib/chain/validation/attestation.d.ts.map +1 -1
  118. package/lib/chain/validation/attestation.js +27 -8
  119. package/lib/chain/validation/attestation.js.map +1 -1
  120. package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
  121. package/lib/chain/validation/attesterSlashing.js +1 -1
  122. package/lib/chain/validation/attesterSlashing.js.map +1 -1
  123. package/lib/chain/validation/blobSidecar.d.ts.map +1 -1
  124. package/lib/chain/validation/blobSidecar.js +3 -3
  125. package/lib/chain/validation/blobSidecar.js.map +1 -1
  126. package/lib/chain/validation/block.d.ts.map +1 -1
  127. package/lib/chain/validation/block.js +5 -4
  128. package/lib/chain/validation/block.js.map +1 -1
  129. package/lib/chain/validation/dataColumnSidecar.d.ts.map +1 -1
  130. package/lib/chain/validation/dataColumnSidecar.js +3 -3
  131. package/lib/chain/validation/dataColumnSidecar.js.map +1 -1
  132. package/lib/chain/validation/executionPayloadBid.d.ts +5 -0
  133. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -0
  134. package/lib/chain/validation/executionPayloadBid.js +104 -0
  135. package/lib/chain/validation/executionPayloadBid.js.map +1 -0
  136. package/lib/chain/validation/executionPayloadEnvelope.d.ts +5 -0
  137. package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -0
  138. package/lib/chain/validation/executionPayloadEnvelope.js +89 -0
  139. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -0
  140. package/lib/chain/validation/payloadAttestationMessage.d.ts +9 -0
  141. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -0
  142. package/lib/chain/validation/payloadAttestationMessage.js +72 -0
  143. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -0
  144. package/lib/chain/validation/proposerSlashing.js +1 -1
  145. package/lib/chain/validation/proposerSlashing.js.map +1 -1
  146. package/lib/chain/validation/signatureSets/aggregateAndProof.d.ts +2 -3
  147. package/lib/chain/validation/signatureSets/aggregateAndProof.d.ts.map +1 -1
  148. package/lib/chain/validation/signatureSets/aggregateAndProof.js +8 -3
  149. package/lib/chain/validation/signatureSets/aggregateAndProof.js.map +1 -1
  150. package/lib/chain/validation/signatureSets/contributionAndProof.d.ts +2 -2
  151. package/lib/chain/validation/signatureSets/contributionAndProof.d.ts.map +1 -1
  152. package/lib/chain/validation/signatureSets/contributionAndProof.js +3 -3
  153. package/lib/chain/validation/signatureSets/contributionAndProof.js.map +1 -1
  154. package/lib/chain/validation/signatureSets/selectionProof.d.ts +2 -3
  155. package/lib/chain/validation/signatureSets/selectionProof.d.ts.map +1 -1
  156. package/lib/chain/validation/signatureSets/selectionProof.js +8 -3
  157. package/lib/chain/validation/signatureSets/selectionProof.js.map +1 -1
  158. package/lib/chain/validation/signatureSets/syncCommittee.d.ts +2 -2
  159. package/lib/chain/validation/signatureSets/syncCommittee.d.ts.map +1 -1
  160. package/lib/chain/validation/signatureSets/syncCommittee.js +3 -3
  161. package/lib/chain/validation/signatureSets/syncCommittee.js.map +1 -1
  162. package/lib/chain/validation/signatureSets/syncCommitteeContribution.d.ts +1 -2
  163. package/lib/chain/validation/signatureSets/syncCommitteeContribution.d.ts.map +1 -1
  164. package/lib/chain/validation/signatureSets/syncCommitteeContribution.js +2 -2
  165. package/lib/chain/validation/signatureSets/syncCommitteeContribution.js.map +1 -1
  166. package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.d.ts +2 -2
  167. package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.d.ts.map +1 -1
  168. package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.js +3 -3
  169. package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.js.map +1 -1
  170. package/lib/chain/validation/syncCommittee.js +1 -1
  171. package/lib/chain/validation/syncCommittee.js.map +1 -1
  172. package/lib/chain/validation/syncCommitteeContributionAndProof.d.ts.map +1 -1
  173. package/lib/chain/validation/syncCommitteeContributionAndProof.js +3 -5
  174. package/lib/chain/validation/syncCommitteeContributionAndProof.js.map +1 -1
  175. package/lib/chain/validation/voluntaryExit.js +1 -1
  176. package/lib/chain/validation/voluntaryExit.js.map +1 -1
  177. package/lib/chain/validatorMonitor.d.ts.map +1 -1
  178. package/lib/chain/validatorMonitor.js +7 -4
  179. package/lib/chain/validatorMonitor.js.map +1 -1
  180. package/lib/db/repositories/checkpointState.js +0 -1
  181. package/lib/db/repositories/checkpointState.js.map +1 -1
  182. package/lib/metrics/metrics/lodestar.d.ts +20 -0
  183. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  184. package/lib/metrics/metrics/lodestar.js +40 -0
  185. package/lib/metrics/metrics/lodestar.js.map +1 -1
  186. package/lib/network/gossip/interface.d.ts +20 -2
  187. package/lib/network/gossip/interface.d.ts.map +1 -1
  188. package/lib/network/gossip/interface.js +3 -0
  189. package/lib/network/gossip/interface.js.map +1 -1
  190. package/lib/network/gossip/scoringParameters.d.ts.map +1 -1
  191. package/lib/network/gossip/scoringParameters.js +38 -2
  192. package/lib/network/gossip/scoringParameters.js.map +1 -1
  193. package/lib/network/gossip/topic.d.ts +77 -1
  194. package/lib/network/gossip/topic.d.ts.map +1 -1
  195. package/lib/network/gossip/topic.js +20 -0
  196. package/lib/network/gossip/topic.js.map +1 -1
  197. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  198. package/lib/network/processor/gossipHandlers.js +34 -0
  199. package/lib/network/processor/gossipHandlers.js.map +1 -1
  200. package/lib/network/processor/gossipQueues/index.d.ts.map +1 -1
  201. package/lib/network/processor/gossipQueues/index.js +16 -0
  202. package/lib/network/processor/gossipQueues/index.js.map +1 -1
  203. package/lib/network/processor/index.d.ts.map +1 -1
  204. package/lib/network/processor/index.js +3 -0
  205. package/lib/network/processor/index.js.map +1 -1
  206. package/lib/sync/backfill/backfill.js +2 -2
  207. package/lib/sync/backfill/backfill.js.map +1 -1
  208. package/lib/sync/backfill/verify.d.ts +1 -2
  209. package/lib/sync/backfill/verify.d.ts.map +1 -1
  210. package/lib/sync/backfill/verify.js +2 -2
  211. package/lib/sync/backfill/verify.js.map +1 -1
  212. package/package.json +15 -15
  213. package/src/api/impl/beacon/blocks/index.ts +9 -7
  214. package/src/api/impl/lodestar/index.ts +12 -3
  215. package/src/api/impl/validator/index.ts +12 -11
  216. package/src/chain/ColumnReconstructionTracker.ts +8 -4
  217. package/src/chain/blocks/verifyBlock.ts +0 -1
  218. package/src/chain/blocks/verifyBlocksSignatures.ts +4 -12
  219. package/src/chain/bls/multithread/index.ts +7 -4
  220. package/src/chain/bls/multithread/jobItem.ts +7 -3
  221. package/src/chain/bls/singleThread.ts +5 -3
  222. package/src/chain/bls/utils.ts +15 -7
  223. package/src/chain/chain.ts +39 -26
  224. package/src/chain/errors/attestationError.ts +11 -1
  225. package/src/chain/errors/executionPayloadBid.ts +35 -0
  226. package/src/chain/errors/executionPayloadEnvelope.ts +34 -0
  227. package/src/chain/errors/index.ts +3 -0
  228. package/src/chain/errors/payloadAttestation.ts +25 -0
  229. package/src/chain/forkChoice/index.ts +19 -0
  230. package/src/chain/interface.ts +16 -1
  231. package/src/chain/opPools/executionPayloadBidPool.ts +77 -0
  232. package/src/chain/opPools/index.ts +2 -0
  233. package/src/chain/opPools/payloadAttestationPool.ts +157 -0
  234. package/src/chain/prepareNextSlot.ts +6 -6
  235. package/src/chain/produceBlock/produceBlockBody.ts +7 -5
  236. package/src/chain/regen/interface.ts +2 -12
  237. package/src/chain/regen/queued.ts +3 -23
  238. package/src/chain/regen/regen.ts +10 -25
  239. package/src/chain/seenCache/index.ts +3 -1
  240. package/src/chain/seenCache/seenAttesters.ts +5 -0
  241. package/src/chain/seenCache/seenExecutionPayloadBids.ts +35 -0
  242. package/src/chain/seenCache/seenExecutionPayloadEnvelope.ts +34 -0
  243. package/src/chain/seenCache/seenGossipBlockInput.ts +1 -1
  244. package/src/chain/validation/aggregateAndProof.ts +36 -14
  245. package/src/chain/validation/attestation.ts +33 -16
  246. package/src/chain/validation/attesterSlashing.ts +1 -6
  247. package/src/chain/validation/blobSidecar.ts +2 -7
  248. package/src/chain/validation/block.ts +5 -4
  249. package/src/chain/validation/dataColumnSidecar.ts +2 -7
  250. package/src/chain/validation/executionPayloadBid.ts +141 -0
  251. package/src/chain/validation/executionPayloadEnvelope.ts +122 -0
  252. package/src/chain/validation/payloadAttestationMessage.ts +109 -0
  253. package/src/chain/validation/proposerSlashing.ts +1 -6
  254. package/src/chain/validation/signatureSets/aggregateAndProof.ts +9 -14
  255. package/src/chain/validation/signatureSets/contributionAndProof.ts +2 -4
  256. package/src/chain/validation/signatureSets/selectionProof.ts +9 -9
  257. package/src/chain/validation/signatureSets/syncCommittee.ts +2 -4
  258. package/src/chain/validation/signatureSets/syncCommitteeContribution.ts +2 -3
  259. package/src/chain/validation/signatureSets/syncCommitteeSelectionProof.ts +2 -4
  260. package/src/chain/validation/syncCommittee.ts +1 -1
  261. package/src/chain/validation/syncCommitteeContributionAndProof.ts +3 -5
  262. package/src/chain/validation/voluntaryExit.ts +1 -1
  263. package/src/chain/validatorMonitor.ts +10 -5
  264. package/src/db/repositories/checkpointState.ts +1 -1
  265. package/src/metrics/metrics/lodestar.ts +40 -0
  266. package/src/network/gossip/interface.ts +17 -0
  267. package/src/network/gossip/scoringParameters.ts +44 -2
  268. package/src/network/gossip/topic.ts +21 -0
  269. package/src/network/processor/gossipHandlers.ts +48 -0
  270. package/src/network/processor/gossipQueues/index.ts +16 -0
  271. package/src/network/processor/index.ts +3 -0
  272. package/src/sync/backfill/backfill.ts +2 -2
  273. package/src/sync/backfill/verify.ts +2 -3
@@ -80,9 +80,8 @@ export class PrepareNextSlotScheduler {
80
80
  await sleep(this.config.getSlotComponentDurationMs(PREPARE_NEXT_SLOT_BPS), this.signal);
81
81
 
82
82
  // calling updateHead() here before we produce a block to reduce reorg possibility
83
- const {slot: headSlot, blockRoot: headRoot} = this.chain.recomputeForkChoiceHead(
84
- ForkchoiceCaller.prepareNextSlot
85
- );
83
+ const headBlock = this.chain.recomputeForkChoiceHead(ForkchoiceCaller.prepareNextSlot);
84
+ const {slot: headSlot, blockRoot: headRoot} = headBlock;
86
85
 
87
86
  // PS: previously this was comparing slots, but that gave no leway on the skipped
88
87
  // slots on epoch bounday. Making it more fluid.
@@ -112,7 +111,7 @@ export class PrepareNextSlotScheduler {
112
111
  // Pre Bellatrix: we only do precompute state transition for the last slot of epoch
113
112
  // For Bellatrix, we always do the `processSlots()` to prepare payload for the next slot
114
113
  const prepareState = await this.chain.regen.getBlockSlotState(
115
- headRoot,
114
+ headBlock,
116
115
  prepareSlot,
117
116
  // the slot 0 of next epoch will likely use this Previous Root Checkpoint state for state transition so we transfer cache here
118
117
  // the resulting state with cache will be cached in Checkpoint State Cache which is used for the upcoming block processing
@@ -129,7 +128,8 @@ export class PrepareNextSlotScheduler {
129
128
 
130
129
  if (feeRecipient) {
131
130
  // If we are proposing next slot, we need to predict if we can proposer-boost-reorg or not
132
- const {slot: proposerHeadSlot, blockRoot: proposerHeadRoot} = this.chain.predictProposerHead(clockSlot);
131
+ const proposerHead = this.chain.predictProposerHead(clockSlot);
132
+ const {slot: proposerHeadSlot, blockRoot: proposerHeadRoot} = proposerHead;
133
133
 
134
134
  // If we predict we can reorg, update prepareState with proposer head block
135
135
  if (proposerHeadRoot !== headRoot || proposerHeadSlot !== headSlot) {
@@ -141,7 +141,7 @@ export class PrepareNextSlotScheduler {
141
141
  });
142
142
  this.metrics?.weakHeadDetected.inc();
143
143
  updatedPrepareState = (await this.chain.regen.getBlockSlotState(
144
- proposerHeadRoot,
144
+ proposerHead,
145
145
  prepareSlot,
146
146
  // only transfer cache if epoch transition because that's the state we will use to stateTransition() the 1st block of epoch
147
147
  {dontTransferCache: !isEpochTransition},
@@ -1,5 +1,5 @@
1
1
  import {ChainForkConfig} from "@lodestar/config";
2
- import {getSafeExecutionBlockHash} from "@lodestar/fork-choice";
2
+ import {ProtoBlock, getSafeExecutionBlockHash} from "@lodestar/fork-choice";
3
3
  import {
4
4
  ForkName,
5
5
  ForkPostBellatrix,
@@ -43,7 +43,7 @@ import {
43
43
  electra,
44
44
  fulu,
45
45
  } from "@lodestar/types";
46
- import {Logger, sleep, toHex, toPubkeyHex, toRootHex} from "@lodestar/utils";
46
+ import {Logger, fromHex, sleep, toHex, toPubkeyHex, toRootHex} from "@lodestar/utils";
47
47
  import {ZERO_HASH_HEX} from "../../constants/index.js";
48
48
  import {numToQuantity} from "../../execution/engine/utils.js";
49
49
  import {
@@ -86,7 +86,7 @@ export type BlockAttributes = {
86
86
  randaoReveal: BLSSignature;
87
87
  graffiti: Bytes32;
88
88
  slot: Slot;
89
- parentBlockRoot: Root;
89
+ parentBlock: ProtoBlock;
90
90
  feeRecipient?: string;
91
91
  };
92
92
 
@@ -155,13 +155,14 @@ export async function produceBlockBody<T extends BlockType>(
155
155
  const {
156
156
  slot: blockSlot,
157
157
  feeRecipient: requestedFeeRecipient,
158
- parentBlockRoot,
158
+ parentBlock,
159
159
  proposerIndex,
160
160
  proposerPubKey,
161
161
  commonBlockBodyPromise,
162
162
  } = blockAttr;
163
163
  let executionPayloadValue: Wei;
164
164
  let blockBody: AssembledBodyType<T>;
165
+ const parentBlockRoot = fromHex(parentBlock.blockRoot);
165
166
  // even though shouldOverrideBuilder is relevant for the engine response, for simplicity of typing
166
167
  // we just return it undefined for the builder which anyway doesn't get consumed downstream
167
168
  let shouldOverrideBuilder: boolean | undefined;
@@ -637,7 +638,7 @@ export async function produceCommonBlockBody<T extends BlockType>(
637
638
  this: BeaconChain,
638
639
  blockType: T,
639
640
  currentState: CachedBeaconStateAllForks,
640
- {randaoReveal, graffiti, slot, parentBlockRoot}: BlockAttributes
641
+ {randaoReveal, graffiti, slot, parentBlock}: BlockAttributes
641
642
  ): Promise<CommonBlockBody> {
642
643
  const stepsMetrics =
643
644
  blockType === BlockType.Full
@@ -691,6 +692,7 @@ export async function produceCommonBlockBody<T extends BlockType>(
691
692
 
692
693
  const endSyncAggregate = stepsMetrics?.startTimer();
693
694
  if (ForkSeq[fork] >= ForkSeq.altair) {
695
+ const parentBlockRoot = fromHex(parentBlock.blockRoot);
694
696
  const previousSlot = slot - 1;
695
697
  const syncAggregate = this.syncContributionAndProofPool.getAggregate(previousSlot, parentBlockRoot);
696
698
  this.metrics?.production.producedSyncAggregateParticipants.observe(
@@ -18,6 +18,7 @@ export enum RegenCaller {
18
18
  validateGossipAggregateAndProof = "validateGossipAggregateAndProof",
19
19
  validateGossipAttestation = "validateGossipAttestation",
20
20
  validateGossipVoluntaryExit = "validateGossipVoluntaryExit",
21
+ validateGossipExecutionPayloadBid = "validateGossipExecutionPayloadBid",
21
22
  onForkChoiceFinalized = "onForkChoiceFinalized",
22
23
  restApi = "restApi",
23
24
  }
@@ -26,7 +27,6 @@ export enum RegenFnName {
26
27
  getBlockSlotState = "getBlockSlotState",
27
28
  getState = "getState",
28
29
  getPreState = "getPreState",
29
- getCheckpointState = "getCheckpointState",
30
30
  }
31
31
 
32
32
  export type StateRegenerationOpts = {
@@ -63,21 +63,11 @@ export interface IStateRegeneratorInternal {
63
63
  rCaller: RegenCaller
64
64
  ): Promise<CachedBeaconStateAllForks>;
65
65
 
66
- /**
67
- * Return a valid checkpoint state
68
- * This will always return a state with `state.slot % SLOTS_PER_EPOCH === 0`
69
- */
70
- getCheckpointState(
71
- cp: phase0.Checkpoint,
72
- opts: StateRegenerationOpts,
73
- rCaller: RegenCaller
74
- ): Promise<CachedBeaconStateAllForks>;
75
-
76
66
  /**
77
67
  * Return the state of `blockRoot` processed to slot `slot`
78
68
  */
79
69
  getBlockSlotState(
80
- blockRoot: RootHex,
70
+ block: ProtoBlock,
81
71
  slot: Slot,
82
72
  opts: StateRegenerationOpts,
83
73
  rCaller: RegenCaller
@@ -5,7 +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, toCheckpointHex} from "../stateCache/index.js";
8
+ import {CheckpointHex} from "../stateCache/index.js";
9
9
  import {BlockStateCache, CheckpointStateCache} from "../stateCache/types.js";
10
10
  import {RegenError, RegenErrorCode} from "./errors.js";
11
11
  import {
@@ -220,24 +220,6 @@ export class QueuedStateRegenerator implements IStateRegenerator {
220
220
  return this.jobQueue.push({key: "getPreState", args: [block, opts, rCaller]});
221
221
  }
222
222
 
223
- async getCheckpointState(
224
- cp: phase0.Checkpoint,
225
- opts: StateRegenerationOpts,
226
- rCaller: RegenCaller
227
- ): Promise<CachedBeaconStateAllForks> {
228
- this.metrics?.regenFnCallTotal.inc({caller: rCaller, entrypoint: RegenFnName.getCheckpointState});
229
-
230
- // First attempt to fetch the state from cache before queueing
231
- const checkpointState = this.checkpointStateCache.get(toCheckpointHex(cp));
232
- if (checkpointState) {
233
- return checkpointState;
234
- }
235
-
236
- // The state is not immediately available in the caches, enqueue the job
237
- this.metrics?.regenFnQueuedTotal.inc({caller: rCaller, entrypoint: RegenFnName.getCheckpointState});
238
- return this.jobQueue.push({key: "getCheckpointState", args: [cp, opts, rCaller]});
239
- }
240
-
241
223
  /**
242
224
  * Get state of provided `blockRoot` and dial forward to `slot`
243
225
  * Use this api with care because we don't want the queue to be busy
@@ -245,7 +227,7 @@ export class QueuedStateRegenerator implements IStateRegenerator {
245
227
  * @returns
246
228
  */
247
229
  async getBlockSlotState(
248
- blockRoot: RootHex,
230
+ block: ProtoBlock,
249
231
  slot: Slot,
250
232
  opts: StateRegenerationOpts,
251
233
  rCaller: RegenCaller
@@ -253,7 +235,7 @@ export class QueuedStateRegenerator implements IStateRegenerator {
253
235
  this.metrics?.regenFnCallTotal.inc({caller: rCaller, entrypoint: RegenFnName.getBlockSlotState});
254
236
 
255
237
  // The state is not immediately available in the caches, enqueue the job
256
- return this.jobQueue.push({key: "getBlockSlotState", args: [blockRoot, slot, opts, rCaller]});
238
+ return this.jobQueue.push({key: "getBlockSlotState", args: [block, slot, opts, rCaller]});
257
239
  }
258
240
 
259
241
  async getState(stateRoot: RootHex, rCaller: RegenCaller): Promise<CachedBeaconStateAllForks> {
@@ -281,8 +263,6 @@ export class QueuedStateRegenerator implements IStateRegenerator {
281
263
  switch (regenRequest.key) {
282
264
  case "getPreState":
283
265
  return await this.regen.getPreState(...regenRequest.args);
284
- case "getCheckpointState":
285
- return await this.regen.getCheckpointState(...regenRequest.args);
286
266
  case "getBlockSlotState":
287
267
  return await this.regen.getBlockSlotState(...regenRequest.args);
288
268
  case "getState":
@@ -11,13 +11,14 @@ import {
11
11
  processSlots,
12
12
  stateTransition,
13
13
  } from "@lodestar/state-transition";
14
- import {BeaconBlock, RootHex, SignedBeaconBlock, Slot, phase0} from "@lodestar/types";
14
+ import {BeaconBlock, RootHex, SignedBeaconBlock, Slot} from "@lodestar/types";
15
15
  import {Logger, fromHex, toRootHex} from "@lodestar/utils";
16
16
  import {IBeaconDb} from "../../db/index.js";
17
17
  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;
@@ -74,45 +76,24 @@ export class StateRegenerator implements IStateRegeneratorInternal {
74
76
  // We may have the checkpoint state with parent root inside the checkpoint state cache
75
77
  // through gossip validation.
76
78
  if (parentEpoch < blockEpoch) {
77
- return this.getCheckpointState({root: block.parentRoot, epoch: blockEpoch}, opts, regenCaller, allowDiskReload);
79
+ return this.getBlockSlotState(parentBlock, block.slot, opts, regenCaller, allowDiskReload);
78
80
  }
79
81
 
80
82
  // Otherwise, get the state normally.
81
83
  return this.getState(parentBlock.stateRoot, regenCaller, allowDiskReload);
82
84
  }
83
85
 
84
- /**
85
- * Get state after block `cp.root` dialed forward to first slot of `cp.epoch`
86
- */
87
- async getCheckpointState(
88
- cp: phase0.Checkpoint,
89
- opts: StateRegenerationOpts,
90
- regenCaller: RegenCaller,
91
- allowDiskReload = false
92
- ): Promise<CachedBeaconStateAllForks> {
93
- const checkpointStartSlot = computeStartSlotAtEpoch(cp.epoch);
94
- return this.getBlockSlotState(toRootHex(cp.root), checkpointStartSlot, opts, regenCaller, allowDiskReload);
95
- }
96
-
97
86
  /**
98
87
  * Get state after block `blockRoot` dialed forward to `slot`
99
88
  * - allowDiskReload should be used with care, as it will cause the state to be reloaded from disk
100
89
  */
101
90
  async getBlockSlotState(
102
- blockRoot: RootHex,
91
+ block: ProtoBlock,
103
92
  slot: Slot,
104
93
  opts: StateRegenerationOpts,
105
94
  regenCaller: RegenCaller,
106
95
  allowDiskReload = false
107
96
  ): Promise<CachedBeaconStateAllForks> {
108
- const block = this.modules.forkChoice.getBlockHex(blockRoot);
109
- if (!block) {
110
- throw new RegenError({
111
- code: RegenErrorCode.BLOCK_NOT_IN_FORKCHOICE,
112
- blockRoot,
113
- });
114
- }
115
-
116
97
  if (slot < block.slot) {
117
98
  throw new RegenError({
118
99
  code: RegenErrorCode.SLOT_BEFORE_BLOCK_SLOT,
@@ -121,6 +102,7 @@ export class StateRegenerator implements IStateRegeneratorInternal {
121
102
  });
122
103
  }
123
104
 
105
+ const {blockRoot} = block;
124
106
  const {checkpointStateCache} = this.modules;
125
107
  const epoch = computeEpochAtSlot(slot);
126
108
  const latestCheckpointStateCtx = allowDiskReload
@@ -211,7 +193,10 @@ export class StateRegenerator implements IStateRegeneratorInternal {
211
193
  const protoBlocksAsc = blocksToReplay.reverse();
212
194
  for (const [i, protoBlock] of protoBlocksAsc.entries()) {
213
195
  replaySlots[i] = protoBlock.slot;
214
- 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));
215
200
  }
216
201
 
217
202
  const logCtx = {stateRoot, caller, replaySlots: replaySlots.join(",")};
@@ -1,5 +1,7 @@
1
- export {SeenAggregators, SeenAttesters} from "./seenAttesters.js";
1
+ export {SeenAggregators, SeenAttesters, SeenPayloadAttesters} from "./seenAttesters.js";
2
2
  export {SeenBlockProposers} from "./seenBlockProposers.js";
3
3
  export {SeenSyncCommitteeMessages} from "./seenCommittee.js";
4
4
  export {SeenContributionAndProof} from "./seenCommitteeContribution.js";
5
+ export {SeenExecutionPayloadBids} from "./seenExecutionPayloadBids.js";
6
+ export {SeenExecutionPayloadEnvelopes} from "./seenExecutionPayloadEnvelope.js";
5
7
  export {SeenBlockInput} from "./seenGossipBlockInput.js";
@@ -56,3 +56,8 @@ export class SeenAttesters {
56
56
  * Keeps a cache to filter aggregated attestations from the same aggregators in the same epoch
57
57
  */
58
58
  export class SeenAggregators extends SeenAttesters {}
59
+
60
+ /**
61
+ * Keeps a cache to filter payload attestations from the same attesters in the same epoch
62
+ */
63
+ export class SeenPayloadAttesters extends SeenAttesters {}
@@ -0,0 +1,35 @@
1
+ import {BuilderIndex, Slot} from "@lodestar/types";
2
+ import {MapDef} from "@lodestar/utils";
3
+
4
+ /**
5
+ * TODO GLOAS: Revisit this value and add rational for choosing it
6
+ */
7
+ const SLOTS_RETAINED = 2;
8
+
9
+ /**
10
+ * Tracks execution payload bids we've already seen per (slot, builder).
11
+ */
12
+ export class SeenExecutionPayloadBids {
13
+ private readonly builderIndexesBySlot = new MapDef<Slot, Set<BuilderIndex>>(() => new Set<BuilderIndex>());
14
+ private lowestPermissibleSlot: Slot = 0;
15
+
16
+ isKnown(slot: Slot, builderIndex: BuilderIndex): boolean {
17
+ return this.builderIndexesBySlot.get(slot)?.has(builderIndex) === true;
18
+ }
19
+
20
+ add(slot: Slot, builderIndex: BuilderIndex): void {
21
+ if (slot < this.lowestPermissibleSlot) {
22
+ throw Error(`slot ${slot} < lowestPermissibleSlot ${this.lowestPermissibleSlot}`);
23
+ }
24
+ this.builderIndexesBySlot.getOrDefault(slot).add(builderIndex);
25
+ }
26
+
27
+ prune(currentSlot: Slot): void {
28
+ this.lowestPermissibleSlot = Math.max(currentSlot - SLOTS_RETAINED, 0);
29
+ for (const slot of this.builderIndexesBySlot.keys()) {
30
+ if (slot < this.lowestPermissibleSlot) {
31
+ this.builderIndexesBySlot.delete(slot);
32
+ }
33
+ }
34
+ }
35
+ }
@@ -0,0 +1,34 @@
1
+ import {RootHex, Slot} from "@lodestar/types";
2
+
3
+ /**
4
+ * Cache to prevent processing multiple execution payload envelopes for the same block root.
5
+ * Only one builder qualifies to submit an execution payload for a given slot.
6
+ * We only keep track of envelopes of unfinalized slots.
7
+ * [IGNORE] The node has not seen another valid `SignedExecutionPayloadEnvelope` for this block root.
8
+ */
9
+ export class SeenExecutionPayloadEnvelopes {
10
+ private readonly slotByBlockRoot = new Map<RootHex, Slot>();
11
+ private finalizedSlot: Slot = 0;
12
+
13
+ isKnown(blockRoot: RootHex): boolean {
14
+ return this.slotByBlockRoot.has(blockRoot);
15
+ }
16
+
17
+ add(blockRoot: RootHex, slot: Slot): void {
18
+ if (slot < this.finalizedSlot) {
19
+ throw Error(`slot ${slot} < finalizedSlot ${this.finalizedSlot}`);
20
+ }
21
+
22
+ this.slotByBlockRoot.set(blockRoot, slot);
23
+ }
24
+
25
+ prune(finalizedSlot: Slot): void {
26
+ this.finalizedSlot = finalizedSlot;
27
+
28
+ for (const [blockRoot, slot] of this.slotByBlockRoot.entries()) {
29
+ if (slot < finalizedSlot) {
30
+ this.slotByBlockRoot.delete(blockRoot);
31
+ }
32
+ }
33
+ }
34
+ }
@@ -379,7 +379,7 @@ export class SeenBlockInput {
379
379
  let itemsToDelete = this.blockInputs.size - MAX_BLOCK_INPUT_CACHE_SIZE;
380
380
 
381
381
  if (itemsToDelete > 0) {
382
- const sorted = [...this.blockInputs.entries()].sort((a, b) => b[1].slot - a[1].slot);
382
+ const sorted = [...this.blockInputs.entries()].sort((a, b) => a[1].slot - b[1].slot);
383
383
  for (const [rootHex] of sorted) {
384
384
  this.blockInputs.delete(rootHex);
385
385
  itemsToDelete--;
@@ -71,11 +71,34 @@ async function validateAggregateAndProof(
71
71
  const attData = aggregate.data;
72
72
  const attSlot = attData.slot;
73
73
 
74
- let attIndex: number | null;
75
- if (ForkSeq[fork] >= ForkSeq.electra) {
76
- attIndex = (aggregate as electra.Attestation).committeeBits.getSingleTrueBit();
74
+ let committeeIndex: number | null;
75
+ if (ForkSeq[fork] >= ForkSeq.gloas) {
76
+ // [REJECT] `aggregate.data.index < 2`.
77
+ if (attData.index >= 2) {
78
+ throw new AttestationError(GossipAction.REJECT, {
79
+ code: AttestationErrorCode.INVALID_PAYLOAD_STATUS_VALUE,
80
+ attDataIndex: attData.index,
81
+ });
82
+ }
83
+ // [REJECT] `aggregate.data.index == 0` if `block.slot == aggregate.data.slot`.
84
+ const block = chain.forkChoice.getBlock(attData.beaconBlockRoot);
85
+
86
+ // If block is unknown, we don't handle it here. It will throw error later on at `verifyHeadBlockAndTargetRoot()`
87
+ if (block !== null && block.slot === attData.slot && attData.index !== 0) {
88
+ throw new AttestationError(GossipAction.REJECT, {
89
+ code: AttestationErrorCode.PREMATURELY_INDICATED_PAYLOAD_PRESENT,
90
+ });
91
+ }
92
+
93
+ // [REJECT] len(committee_indices) == 1, where committee_indices = get_committee_indices(aggregate)
94
+ committeeIndex = (aggregate as electra.Attestation).committeeBits.getSingleTrueBit();
95
+ if (committeeIndex === null) {
96
+ throw new AttestationError(GossipAction.REJECT, {code: AttestationErrorCode.NOT_EXACTLY_ONE_COMMITTEE_BIT_SET});
97
+ }
98
+ } else if (ForkSeq[fork] >= ForkSeq.electra) {
99
+ committeeIndex = (aggregate as electra.Attestation).committeeBits.getSingleTrueBit();
77
100
  // [REJECT] len(committee_indices) == 1, where committee_indices = get_committee_indices(aggregate)
78
- if (attIndex === null) {
101
+ if (committeeIndex === null) {
79
102
  throw new AttestationError(GossipAction.REJECT, {code: AttestationErrorCode.NOT_EXACTLY_ONE_COMMITTEE_BIT_SET});
80
103
  }
81
104
  // [REJECT] aggregate.data.index == 0
@@ -83,11 +106,11 @@ async function validateAggregateAndProof(
83
106
  throw new AttestationError(GossipAction.REJECT, {code: AttestationErrorCode.NON_ZERO_ATTESTATION_DATA_INDEX});
84
107
  }
85
108
  } else {
86
- attIndex = attData.index;
109
+ committeeIndex = attData.index;
87
110
  }
88
111
 
89
112
  const seenAttDataKey = serializedData ? getSeenAttDataKeyFromSignedAggregateAndProof(fork, serializedData) : null;
90
- const cachedAttData = seenAttDataKey ? chain.seenAttestationDatas.get(attSlot, attIndex, seenAttDataKey) : null;
113
+ const cachedAttData = seenAttDataKey ? chain.seenAttestationDatas.get(attSlot, committeeIndex, seenAttDataKey) : null;
91
114
 
92
115
  const attEpoch = computeEpochAtSlot(attSlot);
93
116
  const attTarget = attData.target;
@@ -136,7 +159,7 @@ async function validateAggregateAndProof(
136
159
  : toRootHex(ssz.phase0.AttestationData.hashTreeRoot(attData));
137
160
  if (
138
161
  !skipValidationKnownAttesters &&
139
- chain.seenAggregatedAttestations.isKnown(targetEpoch, attIndex, attDataRootHex, aggregationBits)
162
+ chain.seenAggregatedAttestations.isKnown(targetEpoch, committeeIndex, attDataRootHex, aggregationBits)
140
163
  ) {
141
164
  throw new AttestationError(GossipAction.IGNORE, {
142
165
  code: AttestationErrorCode.ATTESTERS_ALREADY_KNOWN,
@@ -177,7 +200,7 @@ async function validateAggregateAndProof(
177
200
  // -- i.e. data.index < get_committee_count_per_slot(state, data.target.epoch)
178
201
  const committeeValidatorIndices = cachedAttData
179
202
  ? cachedAttData.committeeValidatorIndices
180
- : getCommitteeValidatorIndices(shuffling, attSlot, attIndex);
203
+ : getCommitteeValidatorIndices(shuffling, attSlot, committeeIndex);
181
204
 
182
205
  // [REJECT] The number of aggregation bits matches the committee size
183
206
  // -- i.e. `len(aggregation_bits) == len(get_beacon_committee(state, aggregate.data.slot, index))`.
@@ -216,16 +239,15 @@ async function validateAggregateAndProof(
216
239
  // by the validator with index aggregate_and_proof.aggregator_index.
217
240
  // [REJECT] The aggregator signature, signed_aggregate_and_proof.signature, is valid.
218
241
  // [REJECT] The signature of aggregate is valid.
219
- const aggregator = chain.index2pubkey[aggregateAndProof.aggregatorIndex];
220
242
  const signingRoot = cachedAttData ? cachedAttData.signingRoot : getAttestationDataSigningRoot(chain.config, attData);
221
243
  const indexedAttestationSignatureSet = createAggregateSignatureSetFromComponents(
222
- indexedAttestation.attestingIndices.map((i) => chain.index2pubkey[i]),
244
+ indexedAttestation.attestingIndices,
223
245
  signingRoot,
224
246
  indexedAttestation.signature
225
247
  );
226
248
  const signatureSets = [
227
- getSelectionProofSignatureSet(chain.config, attSlot, aggregator, signedAggregateAndProof),
228
- getAggregateAndProofSignatureSet(chain.config, attEpoch, aggregator, signedAggregateAndProof),
249
+ getSelectionProofSignatureSet(chain.config, attSlot, aggregatorIndex, signedAggregateAndProof),
250
+ getAggregateAndProofSignatureSet(chain.config, attEpoch, aggregatorIndex, signedAggregateAndProof),
229
251
  indexedAttestationSignatureSet,
230
252
  ];
231
253
  // no need to write to SeenAttestationDatas
@@ -248,7 +270,7 @@ async function validateAggregateAndProof(
248
270
  // Same race-condition check as above for seen aggregators
249
271
  if (
250
272
  !skipValidationKnownAttesters &&
251
- chain.seenAggregatedAttestations.isKnown(targetEpoch, attIndex, attDataRootHex, aggregationBits)
273
+ chain.seenAggregatedAttestations.isKnown(targetEpoch, committeeIndex, attDataRootHex, aggregationBits)
252
274
  ) {
253
275
  throw new AttestationError(GossipAction.IGNORE, {
254
276
  code: AttestationErrorCode.ATTESTERS_ALREADY_KNOWN,
@@ -260,7 +282,7 @@ async function validateAggregateAndProof(
260
282
  chain.seenAggregators.add(targetEpoch, aggregatorIndex);
261
283
  chain.seenAggregatedAttestations.add(
262
284
  targetEpoch,
263
- attIndex,
285
+ committeeIndex,
264
286
  attDataRootHex,
265
287
  {aggregationBits, trueBitCount: attestingIndices.length},
266
288
  false
@@ -10,16 +10,17 @@ import {
10
10
  ForkSeq,
11
11
  SLOTS_PER_EPOCH,
12
12
  isForkPostElectra,
13
+ isForkPostGloas,
13
14
  } from "@lodestar/params";
14
15
  import {
15
16
  EpochShuffling,
17
+ IndexedSignatureSet,
16
18
  ShufflingError,
17
19
  ShufflingErrorCode,
18
- SingleSignatureSet,
19
20
  computeEpochAtSlot,
20
21
  computeSigningRoot,
21
22
  computeStartSlotAtEpoch,
22
- createSingleSignatureSetFromComponents,
23
+ createIndexedSignatureSetFromComponents,
23
24
  } from "@lodestar/state-transition";
24
25
  import {
25
26
  CommitteeIndex,
@@ -89,7 +90,7 @@ export type GossipAttestation = {
89
90
  };
90
91
 
91
92
  export type Step0Result = AttestationValidationResult & {
92
- signatureSet: SingleSignatureSet;
93
+ signatureSet: IndexedSignatureSet;
93
94
  validatorIndex: number;
94
95
  };
95
96
 
@@ -124,7 +125,7 @@ export async function validateGossipAttestationsSameAttData(
124
125
  // step1: verify signatures of all valid attestations
125
126
  // map new index to index in resultOrErrors
126
127
  const newIndexToOldIndex = new Map<number, number>();
127
- const signatureSets: SingleSignatureSet[] = [];
128
+ const signatureSets: IndexedSignatureSet[] = [];
128
129
  let newIndex = 0;
129
130
  const step0Results: Step0Result[] = [];
130
131
  for (const [i, resultOrError] of step0ResultOrErrors.entries()) {
@@ -142,7 +143,7 @@ export async function validateGossipAttestationsSameAttData(
142
143
  if (batchableBls) {
143
144
  // all signature sets should have same signing root since we filtered in network processor
144
145
  signatureValids = await chain.bls.verifySignatureSetsSameMessage(
145
- signatureSets.map((set) => ({publicKey: set.pubkey, signature: set.signature})),
146
+ signatureSets.map((set) => ({publicKey: chain.index2pubkey[set.index], signature: set.signature})),
146
147
  signatureSets[0].signingRoot
147
148
  );
148
149
  } else {
@@ -293,9 +294,29 @@ async function validateAttestationNoSignatureCheck(
293
294
  // api or first time validation of a gossip attestation
294
295
  committeeIndex = attestationOrCache.attestation.committeeIndex;
295
296
 
296
- // [REJECT] attestation.data.index == 0
297
- if (attData.index !== 0) {
298
- throw new AttestationError(GossipAction.REJECT, {code: AttestationErrorCode.NON_ZERO_ATTESTATION_DATA_INDEX});
297
+ if (isForkPostGloas(fork)) {
298
+ // [REJECT] `attestation.data.index < 2`.
299
+ if (attData.index >= 2) {
300
+ throw new AttestationError(GossipAction.REJECT, {
301
+ code: AttestationErrorCode.INVALID_PAYLOAD_STATUS_VALUE,
302
+ attDataIndex: attData.index,
303
+ });
304
+ }
305
+
306
+ // [REJECT] `attestation.data.index == 0` if `block.slot == attestation.data.slot`.
307
+ const block = chain.forkChoice.getBlock(attData.beaconBlockRoot);
308
+
309
+ // block being null will be handled by `verifyHeadBlockAndTargetRoot`
310
+ if (block !== null && block.slot === attSlot && attData.index !== 0) {
311
+ throw new AttestationError(GossipAction.REJECT, {
312
+ code: AttestationErrorCode.PREMATURELY_INDICATED_PAYLOAD_PRESENT,
313
+ });
314
+ }
315
+ } else {
316
+ // [REJECT] attestation.data.index == 0
317
+ if (attData.index !== 0) {
318
+ throw new AttestationError(GossipAction.REJECT, {code: AttestationErrorCode.NON_ZERO_ATTESTATION_DATA_INDEX});
319
+ }
299
320
  }
300
321
  } else {
301
322
  // phase0 attestation
@@ -477,7 +498,7 @@ async function validateAttestationNoSignatureCheck(
477
498
 
478
499
  // [REJECT] The signature of attestation is valid.
479
500
  const attestingIndices = [validatorIndex];
480
- let signatureSet: SingleSignatureSet;
501
+ let signatureSet: IndexedSignatureSet;
481
502
  let attDataRootHex: RootHex;
482
503
  const signature = attestationOrCache.attestation
483
504
  ? attestationOrCache.attestation.signature
@@ -492,18 +513,14 @@ async function validateAttestationNoSignatureCheck(
492
513
 
493
514
  if (attestationOrCache.cache) {
494
515
  // there could be up to 6% of cpu time to compute signing root if we don't clone the signature set
495
- signatureSet = createSingleSignatureSetFromComponents(
496
- chain.index2pubkey[validatorIndex],
516
+ signatureSet = createIndexedSignatureSetFromComponents(
517
+ validatorIndex,
497
518
  attestationOrCache.cache.signingRoot,
498
519
  signature
499
520
  );
500
521
  attDataRootHex = attestationOrCache.cache.attDataRootHex;
501
522
  } else {
502
- signatureSet = createSingleSignatureSetFromComponents(
503
- chain.index2pubkey[validatorIndex],
504
- getSigningRoot(),
505
- signature
506
- );
523
+ signatureSet = createIndexedSignatureSetFromComponents(validatorIndex, getSigningRoot(), signature);
507
524
 
508
525
  // add cached attestation data before verifying signature
509
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,
@@ -124,7 +124,7 @@ export async function validateGossipBlobSidecar(
124
124
  // [IGNORE] The block's parent (defined by block.parent_root) has been seen (via both gossip and non-gossip sources) (a client MAY queue blocks for processing once the parent block is retrieved).
125
125
  // [REJECT] The block's parent (defined by block.parent_root) passes validation.
126
126
  const blockState = await chain.regen
127
- .getBlockSlotState(parentRoot, blobSlot, {dontTransferCache: true}, RegenCaller.validateGossipBlock)
127
+ .getBlockSlotState(parentBlock, blobSlot, {dontTransferCache: true}, RegenCaller.validateGossipBlock)
128
128
  .catch(() => {
129
129
  throw new BlobSidecarGossipError(GossipAction.IGNORE, {
130
130
  code: BlobSidecarErrorCode.PARENT_UNKNOWN,
@@ -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
  );
@@ -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], {