@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
@@ -79,7 +79,9 @@ import {LightClientServer} from "./lightClient/index.js";
79
79
  import {
80
80
  AggregatedAttestationPool,
81
81
  AttestationPool,
82
+ ExecutionPayloadBidPool,
82
83
  OpPool,
84
+ PayloadAttestationPool,
83
85
  SyncCommitteeMessagePool,
84
86
  SyncContributionAndProofPool,
85
87
  } from "./opPools/index.js";
@@ -95,6 +97,9 @@ import {
95
97
  SeenAttesters,
96
98
  SeenBlockProposers,
97
99
  SeenContributionAndProof,
100
+ SeenExecutionPayloadBids,
101
+ SeenExecutionPayloadEnvelopes,
102
+ SeenPayloadAttesters,
98
103
  SeenSyncCommitteeMessages,
99
104
  } from "./seenCache/index.js";
100
105
  import {SeenAggregatedAttestations} from "./seenCache/seenAggregateAndProof.js";
@@ -156,12 +161,17 @@ export class BeaconChain implements IBeaconChain {
156
161
  readonly aggregatedAttestationPool: AggregatedAttestationPool;
157
162
  readonly syncCommitteeMessagePool: SyncCommitteeMessagePool;
158
163
  readonly syncContributionAndProofPool;
164
+ readonly executionPayloadBidPool: ExecutionPayloadBidPool;
165
+ readonly payloadAttestationPool: PayloadAttestationPool;
159
166
  readonly opPool: OpPool;
160
167
 
161
168
  // Gossip seen cache
162
169
  readonly seenAttesters = new SeenAttesters();
163
170
  readonly seenAggregators = new SeenAggregators();
171
+ readonly seenPayloadAttesters = new SeenPayloadAttesters();
164
172
  readonly seenAggregatedAttestations: SeenAggregatedAttestations;
173
+ readonly seenExecutionPayloadEnvelopes = new SeenExecutionPayloadEnvelopes();
174
+ readonly seenExecutionPayloadBids = new SeenExecutionPayloadBids();
165
175
  readonly seenBlockProposers = new SeenBlockProposers();
166
176
  readonly seenSyncCommitteeMessages = new SeenSyncCommitteeMessages();
167
177
  readonly seenContributionAndProof: SeenContributionAndProof;
@@ -268,8 +278,8 @@ export class BeaconChain implements IBeaconChain {
268
278
  const emitter = new ChainEventEmitter();
269
279
  // by default, verify signatures on both main threads and worker threads
270
280
  const bls = opts.blsVerifyAllMainThread
271
- ? new BlsSingleThreadVerifier({metrics})
272
- : new BlsMultiThreadWorkerPool(opts, {logger, metrics});
281
+ ? new BlsSingleThreadVerifier({metrics, index2pubkey})
282
+ : new BlsMultiThreadWorkerPool(opts, {logger, metrics, index2pubkey});
273
283
 
274
284
  if (!clock) clock = new Clock({config, genesisTime: this.genesisTime, signal});
275
285
 
@@ -278,6 +288,8 @@ export class BeaconChain implements IBeaconChain {
278
288
  this.aggregatedAttestationPool = new AggregatedAttestationPool(this.config, metrics);
279
289
  this.syncCommitteeMessagePool = new SyncCommitteeMessagePool(config, clock, this.opts?.preaggregateSlotDistance);
280
290
  this.syncContributionAndProofPool = new SyncContributionAndProofPool(config, clock, metrics, logger);
291
+ this.executionPayloadBidPool = new ExecutionPayloadBidPool();
292
+ this.payloadAttestationPool = new PayloadAttestationPool(config, clock, metrics);
281
293
  this.opPool = new OpPool(config);
282
294
 
283
295
  this.seenAggregatedAttestations = new SeenAggregatedAttestations(metrics);
@@ -375,6 +387,7 @@ export class BeaconChain implements IBeaconChain {
375
387
  forkChoice,
376
388
  blockStateCache,
377
389
  checkpointStateCache,
390
+ seenBlockInputCache: this.seenBlockInputCache,
378
391
  db,
379
392
  metrics,
380
393
  validatorMonitor,
@@ -488,6 +501,8 @@ export class BeaconChain implements IBeaconChain {
488
501
  this.seenAttesters.isKnown(epoch, index) ||
489
502
  // seenAggregators = single aggregator index, not participants of the aggregate
490
503
  this.seenAggregators.isKnown(epoch, index) ||
504
+ // seenPayloadAttesters = single signer of payload attestation message
505
+ this.seenPayloadAttesters.isKnown(epoch, index) ||
491
506
  // seenBlockProposers = single block proposer
492
507
  this.seenBlockProposers.seenAtEpoch(epoch, index)
493
508
  );
@@ -530,7 +545,7 @@ export class BeaconChain implements IBeaconChain {
530
545
  // only use regen queue if necessary, it'll cache in checkpointStateCache if regen gets through epoch transition
531
546
  const head = this.forkChoice.getHead();
532
547
  const startSlot = computeStartSlotAtEpoch(epoch);
533
- return this.regen.getBlockSlotState(head.blockRoot, startSlot, {dontTransferCache: true}, regenCaller);
548
+ return this.regen.getBlockSlotState(head, startSlot, {dontTransferCache: true}, regenCaller);
534
549
  }
535
550
 
536
551
  async getStateBySlot(
@@ -548,12 +563,7 @@ export class BeaconChain implements IBeaconChain {
548
563
  if (opts?.allowRegen) {
549
564
  // Find closest canonical block to slot, then trigger regen
550
565
  const block = this.forkChoice.getCanonicalBlockClosestLteSlot(slot) ?? finalizedBlock;
551
- const state = await this.regen.getBlockSlotState(
552
- block.blockRoot,
553
- slot,
554
- {dontTransferCache: true},
555
- RegenCaller.restApi
556
- );
566
+ const state = await this.regen.getBlockSlotState(block, slot, {dontTransferCache: true}, RegenCaller.restApi);
557
567
  return {
558
568
  state,
559
569
  executionOptimistic: isOptimisticBlock(block),
@@ -854,9 +864,9 @@ export class BeaconChain implements IBeaconChain {
854
864
  }
855
865
 
856
866
  async produceCommonBlockBody(blockAttributes: BlockAttributes): Promise<CommonBlockBody> {
857
- const {slot, parentBlockRoot} = blockAttributes;
867
+ const {slot, parentBlock} = blockAttributes;
858
868
  const state = await this.regen.getBlockSlotState(
859
- toRootHex(parentBlockRoot),
869
+ parentBlock,
860
870
  slot,
861
871
  {dontTransferCache: true},
862
872
  RegenCaller.produceBlock
@@ -893,7 +903,7 @@ export class BeaconChain implements IBeaconChain {
893
903
  slot,
894
904
  feeRecipient,
895
905
  commonBlockBodyPromise,
896
- parentBlockRoot,
906
+ parentBlock,
897
907
  }: BlockAttributes & {commonBlockBodyPromise: Promise<CommonBlockBody>}
898
908
  ): Promise<{
899
909
  block: AssembledBlockType<T>;
@@ -902,7 +912,7 @@ export class BeaconChain implements IBeaconChain {
902
912
  shouldOverrideBuilder?: boolean;
903
913
  }> {
904
914
  const state = await this.regen.getBlockSlotState(
905
- toRootHex(parentBlockRoot),
915
+ parentBlock,
906
916
  slot,
907
917
  {dontTransferCache: true},
908
918
  RegenCaller.produceBlock
@@ -919,7 +929,7 @@ export class BeaconChain implements IBeaconChain {
919
929
  graffiti,
920
930
  slot,
921
931
  feeRecipient,
922
- parentBlockRoot,
932
+ parentBlock,
923
933
  proposerIndex,
924
934
  proposerPubKey,
925
935
  commonBlockBodyPromise,
@@ -942,7 +952,7 @@ export class BeaconChain implements IBeaconChain {
942
952
  const block = {
943
953
  slot,
944
954
  proposerIndex,
945
- parentRoot: parentBlockRoot,
955
+ parentRoot: fromHex(parentBlock.blockRoot),
946
956
  stateRoot: ZERO_HASH,
947
957
  body,
948
958
  } as AssembledBlockType<T>;
@@ -1138,12 +1148,7 @@ export class BeaconChain implements IBeaconChain {
1138
1148
  // thanks to one epoch look ahead, we don't need to dial up to attEpoch
1139
1149
  const targetSlot = computeStartSlotAtEpoch(attEpoch - 1);
1140
1150
  this.metrics?.gossipAttestation.useHeadBlockStateDialedToTargetEpoch.inc({caller: regenCaller});
1141
- state = await this.regen.getBlockSlotState(
1142
- attHeadBlock.blockRoot,
1143
- targetSlot,
1144
- {dontTransferCache: true},
1145
- regenCaller
1146
- );
1151
+ state = await this.regen.getBlockSlotState(attHeadBlock, targetSlot, {dontTransferCache: true}, regenCaller);
1147
1152
  } else if (blockEpoch > attEpoch) {
1148
1153
  // should not happen, handled inside attestation verification code
1149
1154
  throw Error(`Block epoch ${blockEpoch} is after attestation epoch ${attEpoch}`);
@@ -1272,6 +1277,8 @@ export class BeaconChain implements IBeaconChain {
1272
1277
  metrics.opPool.proposerSlashingPoolSize.set(this.opPool.proposerSlashingsSize);
1273
1278
  metrics.opPool.voluntaryExitPoolSize.set(this.opPool.voluntaryExitsSize);
1274
1279
  metrics.opPool.syncCommitteeMessagePoolSize.set(this.syncCommitteeMessagePool.size);
1280
+ metrics.opPool.payloadAttestationPool.size.set(this.payloadAttestationPool.size);
1281
+ metrics.opPool.executionPayloadBidPool.size.set(this.executionPayloadBidPool.size);
1275
1282
  // syncContributionAndProofPool tracks metrics on its own
1276
1283
  metrics.opPool.blsToExecutionChangePoolSize.set(this.opPool.blsToExecutionChangeSize);
1277
1284
  metrics.chain.blacklistedBlocks.set(this.blacklistedBlocks.size);
@@ -1302,6 +1309,9 @@ export class BeaconChain implements IBeaconChain {
1302
1309
  this.aggregatedAttestationPool.prune(slot);
1303
1310
  this.syncCommitteeMessagePool.prune(slot);
1304
1311
  this.seenSyncCommitteeMessages.prune(slot);
1312
+ this.payloadAttestationPool.prune(slot);
1313
+ this.executionPayloadBidPool.prune(slot);
1314
+ this.seenExecutionPayloadBids.prune(slot);
1305
1315
  this.seenAttestationDatas.onSlot(slot);
1306
1316
  this.reprocessController.onSlot(slot);
1307
1317
 
@@ -1325,6 +1335,7 @@ export class BeaconChain implements IBeaconChain {
1325
1335
 
1326
1336
  this.seenAttesters.prune(epoch);
1327
1337
  this.seenAggregators.prune(epoch);
1338
+ this.seenPayloadAttesters.prune(epoch);
1328
1339
  this.seenAggregatedAttestations.prune(epoch);
1329
1340
  this.seenBlockAttesters.prune(epoch);
1330
1341
  this.beaconProposerCache.prune(epoch);
@@ -1348,7 +1359,9 @@ export class BeaconChain implements IBeaconChain {
1348
1359
 
1349
1360
  private async onForkChoiceFinalized(this: BeaconChain, cp: CheckpointWithHex): Promise<void> {
1350
1361
  this.logger.verbose("Fork choice finalized", {epoch: cp.epoch, root: cp.rootHex});
1351
- this.seenBlockProposers.prune(computeStartSlotAtEpoch(cp.epoch));
1362
+ const finalizedSlot = computeStartSlotAtEpoch(cp.epoch);
1363
+ this.seenBlockProposers.prune(finalizedSlot);
1364
+ this.seenExecutionPayloadEnvelopes.prune(finalizedSlot);
1352
1365
 
1353
1366
  // Update validator custody to account for effective balance changes
1354
1367
  await this.updateValidatorsCustodyRequirement(cp);
@@ -1356,13 +1369,13 @@ export class BeaconChain implements IBeaconChain {
1356
1369
  // TODO: Improve using regen here
1357
1370
  const {blockRoot, stateRoot, slot} = this.forkChoice.getHead();
1358
1371
  const headState = this.regen.getStateSync(stateRoot);
1359
- const headBlock = await this.db.block.get(fromHex(blockRoot));
1360
- if (headBlock == null) {
1361
- throw Error(`Head block ${slot} ${headBlock} is not available in database`);
1372
+ const blockResult = await this.getBlockByRoot(blockRoot);
1373
+ if (blockResult == null) {
1374
+ throw Error(`Head block for ${slot} is not available in cache or database`);
1362
1375
  }
1363
1376
 
1364
1377
  if (headState) {
1365
- this.opPool.pruneAll(headBlock, headState);
1378
+ this.opPool.pruneAll(blockResult.block, headState);
1366
1379
  }
1367
1380
 
1368
1381
  if (headState === null) {
@@ -139,6 +139,14 @@ export enum AttestationErrorCode {
139
139
  * Electra: Attester not in committee
140
140
  */
141
141
  ATTESTER_NOT_IN_COMMITTEE = "ATTESTATION_ERROR_ATTESTER_NOT_IN_COMMITTEE",
142
+ /**
143
+ * Gloas: Invalid attestationData index: is non-zero and non-one
144
+ */
145
+ INVALID_PAYLOAD_STATUS_VALUE = "ATTESTATION_ERROR_INVALID_PAYLOAD_STATUS_VALUE",
146
+ /**
147
+ * Gloas: Current slot attestation is marking payload as present
148
+ */
149
+ PREMATURELY_INDICATED_PAYLOAD_PRESENT = "ATTESTATION_ERROR_PREMATURELY_INDICATED_PAYLOAD_PRESENT",
142
150
  }
143
151
 
144
152
  export type AttestationErrorType =
@@ -175,7 +183,9 @@ export type AttestationErrorType =
175
183
  | {code: AttestationErrorCode.TOO_MANY_SKIPPED_SLOTS; headBlockSlot: Slot; attestationSlot: Slot}
176
184
  | {code: AttestationErrorCode.NOT_EXACTLY_ONE_COMMITTEE_BIT_SET}
177
185
  | {code: AttestationErrorCode.NON_ZERO_ATTESTATION_DATA_INDEX}
178
- | {code: AttestationErrorCode.ATTESTER_NOT_IN_COMMITTEE};
186
+ | {code: AttestationErrorCode.ATTESTER_NOT_IN_COMMITTEE}
187
+ | {code: AttestationErrorCode.INVALID_PAYLOAD_STATUS_VALUE; attDataIndex: number}
188
+ | {code: AttestationErrorCode.PREMATURELY_INDICATED_PAYLOAD_PRESENT};
179
189
 
180
190
  export class AttestationError extends GossipActionError<AttestationErrorType> {
181
191
  getMetadata(): Record<string, string | number | null> {
@@ -0,0 +1,35 @@
1
+ import {BuilderIndex, RootHex, Slot} from "@lodestar/types";
2
+ import {GossipActionError} from "./gossipValidation.ts";
3
+
4
+ export enum ExecutionPayloadBidErrorCode {
5
+ BUILDER_NOT_ELIGIBLE = "EXECUTION_PAYLOAD_BID_ERROR_BUILDER_NOT_ELIGIBLE",
6
+ NON_ZERO_EXECUTION_PAYMENT = "EXECUTION_PAYLOAD_BID_ERROR_NON_ZERO_EXECUTION_PAYMENT",
7
+ BID_ALREADY_KNOWN = "EXECUTION_PAYLOAD_BID_ERROR_BID_ALREADY_KNOWN",
8
+ BID_TOO_LOW = "EXECUTION_PAYLOAD_BID_ERROR_BID_TOO_LOW",
9
+ BID_TOO_HIGH = "EXECUTION_PAYLOAD_BID_ERROR_BID_TOO_HIGH",
10
+ UNKNOWN_BLOCK_ROOT = "EXECUTION_PAYLOAD_BID_ERROR_UNKNOWN_BLOCK_ROOT",
11
+ INVALID_SLOT = "EXECUTION_PAYLOAD_BID_ERROR_INVALID_SLOT",
12
+ INVALID_SIGNATURE = "EXECUTION_PAYLOAD_BID_ERROR_INVALID_SIGNATURE",
13
+ }
14
+
15
+ export type ExecutionPayloadBidErrorType =
16
+ | {code: ExecutionPayloadBidErrorCode.BUILDER_NOT_ELIGIBLE; builderIndex: BuilderIndex}
17
+ | {
18
+ code: ExecutionPayloadBidErrorCode.NON_ZERO_EXECUTION_PAYMENT;
19
+ builderIndex: BuilderIndex;
20
+ executionPayment: number;
21
+ }
22
+ | {
23
+ code: ExecutionPayloadBidErrorCode.BID_ALREADY_KNOWN;
24
+ builderIndex: BuilderIndex;
25
+ slot: Slot;
26
+ parentBlockRoot: RootHex;
27
+ parentBlockHash: RootHex;
28
+ }
29
+ | {code: ExecutionPayloadBidErrorCode.BID_TOO_LOW; bidValue: number; currentHighestBid: number}
30
+ | {code: ExecutionPayloadBidErrorCode.BID_TOO_HIGH; bidValue: number; builderBalance: number}
31
+ | {code: ExecutionPayloadBidErrorCode.UNKNOWN_BLOCK_ROOT; parentBlockRoot: RootHex}
32
+ | {code: ExecutionPayloadBidErrorCode.INVALID_SLOT; builderIndex: BuilderIndex; slot: Slot}
33
+ | {code: ExecutionPayloadBidErrorCode.INVALID_SIGNATURE; builderIndex: BuilderIndex; slot: Slot};
34
+
35
+ export class ExecutionPayloadBidError extends GossipActionError<ExecutionPayloadBidErrorType> {}
@@ -0,0 +1,34 @@
1
+ import {BuilderIndex, RootHex, Slot} from "@lodestar/types";
2
+ import {GossipActionError} from "./gossipValidation.js";
3
+
4
+ export enum ExecutionPayloadEnvelopeErrorCode {
5
+ BELONG_TO_FINALIZED_BLOCK = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_BELONG_TO_FINALIZED_BLOCK",
6
+ BLOCK_ROOT_UNKNOWN = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_BLOCK_ROOT_UNKNOWN",
7
+ ENVELOPE_ALREADY_KNOWN = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_ALREADY_KNOWN",
8
+ INVALID_BLOCK = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_INVALID_BLOCK",
9
+ SLOT_MISMATCH = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_SLOT_MISMATCH",
10
+ BUILDER_INDEX_MISMATCH = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_BUILDER_INDEX_MISMATCH",
11
+ BLOCK_HASH_MISMATCH = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_BLOCK_HASH_MISMATCH",
12
+ INVALID_SIGNATURE = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_INVALID_SIGNATURE",
13
+ CACHE_FAIL = "EXECUTION_PAYLOAD_ENVELOPE_ERROR_CACHE_FAIL",
14
+ }
15
+ export type ExecutionPayloadEnvelopeErrorType =
16
+ | {code: ExecutionPayloadEnvelopeErrorCode.BELONG_TO_FINALIZED_BLOCK; envelopeSlot: Slot; finalizedSlot: Slot}
17
+ | {code: ExecutionPayloadEnvelopeErrorCode.BLOCK_ROOT_UNKNOWN; blockRoot: RootHex}
18
+ | {
19
+ code: ExecutionPayloadEnvelopeErrorCode.ENVELOPE_ALREADY_KNOWN;
20
+ blockRoot: RootHex;
21
+ slot: Slot;
22
+ }
23
+ | {code: ExecutionPayloadEnvelopeErrorCode.INVALID_BLOCK; blockRoot: RootHex}
24
+ | {code: ExecutionPayloadEnvelopeErrorCode.SLOT_MISMATCH; envelopeSlot: Slot; blockSlot: Slot}
25
+ | {
26
+ code: ExecutionPayloadEnvelopeErrorCode.BUILDER_INDEX_MISMATCH;
27
+ envelopeBuilderIndex: BuilderIndex;
28
+ bidBuilderIndex: BuilderIndex;
29
+ }
30
+ | {code: ExecutionPayloadEnvelopeErrorCode.BLOCK_HASH_MISMATCH; envelopeBlockHash: RootHex; bidBlockHash: RootHex}
31
+ | {code: ExecutionPayloadEnvelopeErrorCode.INVALID_SIGNATURE}
32
+ | {code: ExecutionPayloadEnvelopeErrorCode.CACHE_FAIL; blockRoot: RootHex};
33
+
34
+ export class ExecutionPayloadEnvelopeError extends GossipActionError<ExecutionPayloadEnvelopeErrorType> {}
@@ -4,7 +4,10 @@ export * from "./blobSidecarError.js";
4
4
  export * from "./blockError.js";
5
5
  export * from "./blsToExecutionChangeError.js";
6
6
  export * from "./dataColumnSidecarError.js";
7
+ export * from "./executionPayloadBid.js";
8
+ export * from "./executionPayloadEnvelope.js";
7
9
  export * from "./gossipValidation.js";
10
+ export * from "./payloadAttestation.js";
8
11
  export * from "./proposerSlashingError.js";
9
12
  export * from "./syncCommitteeError.js";
10
13
  export * from "./voluntaryExitError.js";
@@ -0,0 +1,25 @@
1
+ import {RootHex, Slot, ValidatorIndex} from "@lodestar/types";
2
+ import {GossipActionError} from "./gossipValidation.ts";
3
+
4
+ export enum PayloadAttestationErrorCode {
5
+ NOT_CURRENT_SLOT = "PAYLOAD_ATTESTATION_ERROR_NOT_CURRENT_SLOT",
6
+ PAYLOAD_ATTESTATION_ALREADY_KNOWN = "PAYLOAD_ATTESTATION_ERROR_PAYLOAD_ATTESTATION_ALREADY_KNOWN",
7
+ UNKNOWN_BLOCK_ROOT = "PAYLOAD_ATTESTATION_ERROR_UNKNOWN_BLOCK_ROOT",
8
+ INVALID_BLOCK = "PAYLOAD_ATTESTATION_ERROR_INVALID_BLOCK",
9
+ INVALID_ATTESTER = "PAYLOAD_ATTESTATION_ERROR_INVALID_ATTESTER",
10
+ INVALID_SIGNATURE = "PAYLOAD_ATTESTATION_ERROR_INVALID_SIGNATURE",
11
+ }
12
+ export type PayloadAttestationErrorType =
13
+ | {code: PayloadAttestationErrorCode.NOT_CURRENT_SLOT; currentSlot: Slot; slot: Slot}
14
+ | {
15
+ code: PayloadAttestationErrorCode.PAYLOAD_ATTESTATION_ALREADY_KNOWN;
16
+ validatorIndex: ValidatorIndex;
17
+ slot: Slot;
18
+ blockRoot: RootHex;
19
+ }
20
+ | {code: PayloadAttestationErrorCode.UNKNOWN_BLOCK_ROOT; blockRoot: RootHex}
21
+ | {code: PayloadAttestationErrorCode.INVALID_BLOCK; blockRoot: RootHex}
22
+ | {code: PayloadAttestationErrorCode.INVALID_ATTESTER; attesterIndex: ValidatorIndex}
23
+ | {code: PayloadAttestationErrorCode.INVALID_SIGNATURE};
24
+
25
+ export class PayloadAttestationError extends GossipActionError<PayloadAttestationErrorType> {}
@@ -11,6 +11,7 @@ import {
11
11
  import {ZERO_HASH_HEX} from "@lodestar/params";
12
12
  import {
13
13
  CachedBeaconStateAllForks,
14
+ CachedBeaconStateGloas,
14
15
  DataAvailabilityStatus,
15
16
  computeAnchorCheckpoint,
16
17
  computeEpochAtSlot,
@@ -144,6 +145,15 @@ export function initializeForkChoiceFromFinalizedState(
144
145
  : {executionPayloadBlockHash: null, executionStatus: ExecutionStatus.PreMerge}),
145
146
 
146
147
  dataAvailabilityStatus: DataAvailabilityStatus.PreData,
148
+ ...(computeEpochAtSlot(blockHeader.slot) < state.config.GLOAS_FORK_EPOCH
149
+ ? {
150
+ builderIndex: undefined,
151
+ blockHashHex: undefined,
152
+ }
153
+ : {
154
+ builderIndex: (state as CachedBeaconStateGloas).latestExecutionPayloadBid.builderIndex,
155
+ blockHashHex: toRootHex((state as CachedBeaconStateGloas).latestExecutionPayloadBid.blockHash),
156
+ }),
147
157
  },
148
158
  currentSlot
149
159
  ),
@@ -225,6 +235,15 @@ export function initializeForkChoiceFromUnfinalizedState(
225
235
  : {executionPayloadBlockHash: null, executionStatus: ExecutionStatus.PreMerge}),
226
236
 
227
237
  dataAvailabilityStatus: DataAvailabilityStatus.PreData,
238
+ ...(computeEpochAtSlot(blockHeader.slot) < unfinalizedState.config.GLOAS_FORK_EPOCH
239
+ ? {
240
+ builderIndex: undefined,
241
+ blockHashHex: undefined,
242
+ }
243
+ : {
244
+ builderIndex: (unfinalizedState as CachedBeaconStateGloas).latestExecutionPayloadBid.builderIndex,
245
+ blockHashHex: toRootHex((unfinalizedState as CachedBeaconStateGloas).latestExecutionPayloadBid.blockHash),
246
+ }),
228
247
  };
229
248
 
230
249
  const parentSlot = blockHeader.slot - 1;
@@ -46,7 +46,14 @@ import {ForkchoiceCaller} from "./forkChoice/index.js";
46
46
  import {GetBlobsTracker} from "./GetBlobsTracker.js";
47
47
  import {LightClientServer} from "./lightClient/index.js";
48
48
  import {AggregatedAttestationPool} from "./opPools/aggregatedAttestationPool.js";
49
- import {AttestationPool, OpPool, SyncCommitteeMessagePool, SyncContributionAndProofPool} from "./opPools/index.js";
49
+ import {
50
+ AttestationPool,
51
+ ExecutionPayloadBidPool,
52
+ OpPool,
53
+ PayloadAttestationPool,
54
+ SyncCommitteeMessagePool,
55
+ SyncContributionAndProofPool,
56
+ } from "./opPools/index.js";
50
57
  import {IChainOptions} from "./options.js";
51
58
  import {AssembledBlockType, BlockAttributes, BlockType, ProduceResult} from "./produceBlock/produceBlockBody.js";
52
59
  import {IStateRegenerator, RegenCaller} from "./regen/index.js";
@@ -56,6 +63,9 @@ import {
56
63
  SeenAttesters,
57
64
  SeenBlockProposers,
58
65
  SeenContributionAndProof,
66
+ SeenExecutionPayloadBids,
67
+ SeenExecutionPayloadEnvelopes,
68
+ SeenPayloadAttesters,
59
69
  SeenSyncCommitteeMessages,
60
70
  } from "./seenCache/index.js";
61
71
  import {SeenAggregatedAttestations} from "./seenCache/seenAggregateAndProof.js";
@@ -116,12 +126,17 @@ export interface IBeaconChain {
116
126
  readonly aggregatedAttestationPool: AggregatedAttestationPool;
117
127
  readonly syncCommitteeMessagePool: SyncCommitteeMessagePool;
118
128
  readonly syncContributionAndProofPool: SyncContributionAndProofPool;
129
+ readonly executionPayloadBidPool: ExecutionPayloadBidPool;
130
+ readonly payloadAttestationPool: PayloadAttestationPool;
119
131
  readonly opPool: OpPool;
120
132
 
121
133
  // Gossip seen cache
122
134
  readonly seenAttesters: SeenAttesters;
123
135
  readonly seenAggregators: SeenAggregators;
136
+ readonly seenPayloadAttesters: SeenPayloadAttesters;
124
137
  readonly seenAggregatedAttestations: SeenAggregatedAttestations;
138
+ readonly seenExecutionPayloadEnvelopes: SeenExecutionPayloadEnvelopes;
139
+ readonly seenExecutionPayloadBids: SeenExecutionPayloadBids;
125
140
  readonly seenBlockProposers: SeenBlockProposers;
126
141
  readonly seenSyncCommitteeMessages: SeenSyncCommitteeMessages;
127
142
  readonly seenContributionAndProof: SeenContributionAndProof;
@@ -0,0 +1,77 @@
1
+ import {Slot, gloas} from "@lodestar/types";
2
+ import {MapDef, toRootHex} from "@lodestar/utils";
3
+ import {InsertOutcome} from "./types.js";
4
+ import {pruneBySlot} from "./utils.js";
5
+
6
+ /**
7
+ * TODO GLOAS: Revisit this value and add rational for choosing it
8
+ */
9
+ const SLOTS_RETAINED = 2;
10
+
11
+ type BlockRootHex = string;
12
+ type BlockHashHex = string;
13
+
14
+ /**
15
+ * Store the best execution payload bid per slot / (parent block root, parent block hash).
16
+ */
17
+ export class ExecutionPayloadBidPool {
18
+ private readonly bidByParentHashByParentRootBySlot = new MapDef<
19
+ Slot,
20
+ MapDef<BlockRootHex, Map<BlockHashHex, gloas.ExecutionPayloadBid>>
21
+ >(() => new MapDef<BlockRootHex, Map<BlockHashHex, gloas.ExecutionPayloadBid>>(() => new Map()));
22
+ private lowestPermissibleSlot = 0;
23
+
24
+ get size(): number {
25
+ let count = 0;
26
+ for (const byParentRoot of this.bidByParentHashByParentRootBySlot.values()) {
27
+ for (const byParentHash of byParentRoot.values()) {
28
+ count += byParentHash.size;
29
+ }
30
+ }
31
+ return count;
32
+ }
33
+
34
+ add(bid: gloas.ExecutionPayloadBid): InsertOutcome {
35
+ const {slot, parentBlockRoot, parentBlockHash, value} = bid;
36
+ const lowestPermissibleSlot = this.lowestPermissibleSlot;
37
+
38
+ if (slot < lowestPermissibleSlot) {
39
+ return InsertOutcome.Old;
40
+ }
41
+
42
+ const parentRootHex = toRootHex(parentBlockRoot);
43
+ const parentHashHex = toRootHex(parentBlockHash);
44
+ const bidByParentHash = this.bidByParentHashByParentRootBySlot.getOrDefault(slot).getOrDefault(parentRootHex);
45
+ const existing = bidByParentHash.get(parentHashHex);
46
+
47
+ if (existing) {
48
+ const existingValue = existing.value;
49
+ const newValue = value;
50
+ if (newValue > existingValue) {
51
+ bidByParentHash.set(parentHashHex, bid);
52
+ return InsertOutcome.NewData;
53
+ }
54
+ return newValue === existingValue ? InsertOutcome.AlreadyKnown : InsertOutcome.NotBetterThan;
55
+ }
56
+
57
+ bidByParentHash.set(parentHashHex, bid);
58
+ return InsertOutcome.NewData;
59
+ }
60
+
61
+ /**
62
+ * Return the highest-value bid matching slot, parent block root, and parent block hash.
63
+ * Used for gossip validation and block production.
64
+ */
65
+ getBestBid(
66
+ parentBlockRoot: BlockRootHex,
67
+ parentBlockHash: BlockHashHex,
68
+ slot: Slot
69
+ ): gloas.ExecutionPayloadBid | null {
70
+ const bidByParentHash = this.bidByParentHashByParentRootBySlot.get(slot)?.get(parentBlockRoot);
71
+ return bidByParentHash?.get(parentBlockHash) ?? null;
72
+ }
73
+
74
+ prune(clockSlot: Slot): void {
75
+ this.lowestPermissibleSlot = pruneBySlot(this.bidByParentHashByParentRootBySlot, clockSlot, SLOTS_RETAINED);
76
+ }
77
+ }
@@ -1,5 +1,7 @@
1
1
  export {AggregatedAttestationPool} from "./aggregatedAttestationPool.js";
2
2
  export {AttestationPool} from "./attestationPool.js";
3
+ export {ExecutionPayloadBidPool} from "./executionPayloadBidPool.js";
3
4
  export {OpPool} from "./opPool.js";
5
+ export {PayloadAttestationPool} from "./payloadAttestationPool.js";
4
6
  export {SyncCommitteeMessagePool} from "./syncCommitteeMessagePool.js";
5
7
  export {SyncContributionAndProofPool} from "./syncContributionAndProofPool.js";
@@ -0,0 +1,157 @@
1
+ import {Signature, aggregateSignatures} from "@chainsafe/blst";
2
+ import {BitArray} from "@chainsafe/ssz";
3
+ import {ChainForkConfig} from "@lodestar/config";
4
+ import {MAX_COMMITTEES_PER_SLOT, PTC_SIZE} from "@lodestar/params";
5
+ import {RootHex, Slot, gloas} from "@lodestar/types";
6
+ import {MapDef, toRootHex} from "@lodestar/utils";
7
+ import {Metrics} from "../../metrics/metrics.js";
8
+ import {IClock} from "../../util/clock.js";
9
+ import {InsertOutcome, OpPoolError, OpPoolErrorCode} from "./types.js";
10
+ import {pruneBySlot, signatureFromBytesNoCheck} from "./utils.js";
11
+
12
+ /**
13
+ * TODO GLOAS: Revisit this value and add rational for choosing it
14
+ */
15
+ const SLOTS_RETAINED = 2;
16
+
17
+ /**
18
+ * The maximum number of distinct `PayloadAttestationData` that will be stored in each slot.
19
+ *
20
+ * This is a DoS protection measure.
21
+ */
22
+ // TODO GLOAS: Revisit this value. Educated guess would be MAX_ATTESTATIONS_PER_SLOT in AttestationPool divided by MAX_COMMITTEES_PER_SLOT
23
+ const MAX_PAYLOAD_ATTESTATIONS_PER_SLOT = 16_384 / MAX_COMMITTEES_PER_SLOT;
24
+
25
+ type DataRootHex = string;
26
+ type BlockRootHex = string;
27
+
28
+ type AggregateFast = {
29
+ aggregationBits: BitArray;
30
+ data: gloas.PayloadAttestationData;
31
+ signature: Signature;
32
+ };
33
+
34
+ export class PayloadAttestationPool {
35
+ private readonly aggregateByDataRootByBlockRootBySlot = new MapDef<
36
+ Slot,
37
+ Map<BlockRootHex, Map<DataRootHex, AggregateFast>>
38
+ >(() => new Map<BlockRootHex, Map<DataRootHex, AggregateFast>>());
39
+ private lowestPermissibleSlot = 0;
40
+
41
+ constructor(
42
+ private readonly config: ChainForkConfig,
43
+ private readonly clock: IClock,
44
+ private readonly metrics: Metrics | null = null
45
+ ) {}
46
+
47
+ get size(): number {
48
+ let count = 0;
49
+ for (const aggregateByDataRootByBlockRoot of this.aggregateByDataRootByBlockRootBySlot.values()) {
50
+ for (const aggregateByDataRoot of aggregateByDataRootByBlockRoot.values()) {
51
+ count += aggregateByDataRoot.size;
52
+ }
53
+ }
54
+ return count;
55
+ }
56
+
57
+ add(
58
+ message: gloas.PayloadAttestationMessage,
59
+ payloadAttDataRootHex: RootHex,
60
+ validatorCommitteeIndex: number
61
+ ): InsertOutcome {
62
+ const slot = message.data.slot;
63
+ const lowestPermissibleSlot = this.lowestPermissibleSlot;
64
+
65
+ if (slot < lowestPermissibleSlot) {
66
+ return InsertOutcome.Old;
67
+ }
68
+
69
+ if (slot < this.clock.slotWithPastTolerance(this.config.MAXIMUM_GOSSIP_CLOCK_DISPARITY / 1000)) {
70
+ return InsertOutcome.Late;
71
+ }
72
+
73
+ const aggregateByDataRootByBlockRoot = this.aggregateByDataRootByBlockRootBySlot.getOrDefault(slot);
74
+ let aggregateByDataRoot = aggregateByDataRootByBlockRoot.get(toRootHex(message.data.beaconBlockRoot));
75
+
76
+ if (!aggregateByDataRoot) {
77
+ aggregateByDataRoot = new Map<DataRootHex, AggregateFast>();
78
+ aggregateByDataRootByBlockRoot.set(toRootHex(message.data.beaconBlockRoot), aggregateByDataRoot);
79
+ }
80
+
81
+ if (aggregateByDataRoot.size >= MAX_PAYLOAD_ATTESTATIONS_PER_SLOT) {
82
+ throw new OpPoolError({code: OpPoolErrorCode.REACHED_MAX_PER_SLOT});
83
+ }
84
+
85
+ const aggregate = aggregateByDataRoot.get(payloadAttDataRootHex);
86
+ if (aggregate) {
87
+ // Aggregate msg into aggregate
88
+ return aggregateMessageInto(message, validatorCommitteeIndex, aggregate);
89
+ }
90
+ // Create a new aggregate with data
91
+ aggregateByDataRoot.set(payloadAttDataRootHex, messageToAggregate(message, validatorCommitteeIndex));
92
+
93
+ return InsertOutcome.NewData;
94
+ }
95
+
96
+ /**
97
+ * Get payload attestations to be included in a block.
98
+ * Pick the top `maxAttestation` number of attestations with the most votes
99
+ */
100
+ getPayloadAttestationsForBlock(
101
+ beaconBlockRoot: BlockRootHex,
102
+ slot: Slot,
103
+ maxAttestation: number
104
+ ): gloas.PayloadAttestation[] {
105
+ const aggregateByDataRootByBlockRoot = this.aggregateByDataRootByBlockRootBySlot.get(slot);
106
+
107
+ if (!aggregateByDataRootByBlockRoot) {
108
+ this.metrics?.opPool.payloadAttestationPool.getPayloadAttestationsCacheMisses.inc();
109
+ return [];
110
+ }
111
+
112
+ const aggregateByDataRoot = aggregateByDataRootByBlockRoot.get(beaconBlockRoot);
113
+
114
+ if (!aggregateByDataRoot) {
115
+ this.metrics?.opPool.payloadAttestationPool.getPayloadAttestationsCacheMisses.inc();
116
+ return [];
117
+ }
118
+
119
+ return Array.from(aggregateByDataRoot.values())
120
+ .slice()
121
+ .sort((a, b) => b.aggregationBits.getTrueBitIndexes().length - a.aggregationBits.getTrueBitIndexes().length)
122
+ .slice(0, maxAttestation)
123
+ .map(fastToPayloadAttestation);
124
+ }
125
+
126
+ prune(clockSlot: Slot): void {
127
+ pruneBySlot(this.aggregateByDataRootByBlockRootBySlot, clockSlot, SLOTS_RETAINED);
128
+ this.lowestPermissibleSlot = clockSlot;
129
+ }
130
+ }
131
+
132
+ function messageToAggregate(message: gloas.PayloadAttestationMessage, validatorCommitteeIndex: number): AggregateFast {
133
+ return {
134
+ aggregationBits: BitArray.fromSingleBit(PTC_SIZE, validatorCommitteeIndex),
135
+ data: message.data,
136
+ signature: signatureFromBytesNoCheck(message.signature),
137
+ };
138
+ }
139
+
140
+ function aggregateMessageInto(
141
+ message: gloas.PayloadAttestationMessage,
142
+ validatorCommitteeIndex: number,
143
+ aggregate: AggregateFast
144
+ ): InsertOutcome {
145
+ if (aggregate.aggregationBits.get(validatorCommitteeIndex) === true) {
146
+ return InsertOutcome.AlreadyKnown;
147
+ }
148
+
149
+ aggregate.aggregationBits.set(validatorCommitteeIndex, true);
150
+ aggregate.signature = aggregateSignatures([aggregate.signature, signatureFromBytesNoCheck(message.signature)]);
151
+
152
+ return InsertOutcome.Aggregated;
153
+ }
154
+
155
+ function fastToPayloadAttestation(aggFast: AggregateFast): gloas.PayloadAttestation {
156
+ return {...aggFast, signature: aggFast.signature.toBytes()};
157
+ }