@lodestar/beacon-node 1.40.0-dev.c7b6a784da → 1.40.0-dev.cfd894719f

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 (229) hide show
  1. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  2. package/lib/chain/blocks/verifyBlock.js +1 -1
  3. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  4. package/lib/chain/blocks/verifyBlocksSignatures.d.ts +2 -2
  5. package/lib/chain/blocks/verifyBlocksSignatures.d.ts.map +1 -1
  6. package/lib/chain/blocks/verifyBlocksSignatures.js +2 -2
  7. package/lib/chain/blocks/verifyBlocksSignatures.js.map +1 -1
  8. package/lib/chain/bls/multithread/index.d.ts +3 -1
  9. package/lib/chain/bls/multithread/index.d.ts.map +1 -1
  10. package/lib/chain/bls/multithread/index.js +5 -3
  11. package/lib/chain/bls/multithread/index.js.map +1 -1
  12. package/lib/chain/bls/multithread/jobItem.d.ts +2 -2
  13. package/lib/chain/bls/multithread/jobItem.d.ts.map +1 -1
  14. package/lib/chain/bls/multithread/jobItem.js +2 -2
  15. package/lib/chain/bls/multithread/jobItem.js.map +1 -1
  16. package/lib/chain/bls/singleThread.d.ts +4 -2
  17. package/lib/chain/bls/singleThread.d.ts.map +1 -1
  18. package/lib/chain/bls/singleThread.js +4 -2
  19. package/lib/chain/bls/singleThread.js.map +1 -1
  20. package/lib/chain/bls/utils.d.ts +2 -2
  21. package/lib/chain/bls/utils.d.ts.map +1 -1
  22. package/lib/chain/bls/utils.js +9 -6
  23. package/lib/chain/bls/utils.js.map +1 -1
  24. package/lib/chain/chain.d.ts +7 -2
  25. package/lib/chain/chain.d.ts.map +1 -1
  26. package/lib/chain/chain.js +22 -5
  27. package/lib/chain/chain.js.map +1 -1
  28. package/lib/chain/errors/attestationError.d.ts +14 -1
  29. package/lib/chain/errors/attestationError.d.ts.map +1 -1
  30. package/lib/chain/errors/attestationError.js +8 -0
  31. package/lib/chain/errors/attestationError.js.map +1 -1
  32. package/lib/chain/errors/executionPayloadBid.d.ts +48 -0
  33. package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -0
  34. package/lib/chain/errors/executionPayloadBid.js +15 -0
  35. package/lib/chain/errors/executionPayloadBid.js.map +1 -0
  36. package/lib/chain/errors/executionPayloadEnvelope.d.ts +48 -0
  37. package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -0
  38. package/lib/chain/errors/executionPayloadEnvelope.js +16 -0
  39. package/lib/chain/errors/executionPayloadEnvelope.js.map +1 -0
  40. package/lib/chain/errors/index.d.ts +3 -0
  41. package/lib/chain/errors/index.d.ts.map +1 -1
  42. package/lib/chain/errors/index.js +3 -0
  43. package/lib/chain/errors/index.js.map +1 -1
  44. package/lib/chain/errors/payloadAttestation.d.ts +34 -0
  45. package/lib/chain/errors/payloadAttestation.d.ts.map +1 -0
  46. package/lib/chain/errors/payloadAttestation.js +13 -0
  47. package/lib/chain/errors/payloadAttestation.js.map +1 -0
  48. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  49. package/lib/chain/forkChoice/index.js +18 -0
  50. package/lib/chain/forkChoice/index.js.map +1 -1
  51. package/lib/chain/interface.d.ts +7 -2
  52. package/lib/chain/interface.d.ts.map +1 -1
  53. package/lib/chain/interface.js.map +1 -1
  54. package/lib/chain/opPools/executionPayloadBidPool.d.ts +21 -0
  55. package/lib/chain/opPools/executionPayloadBidPool.d.ts.map +1 -0
  56. package/lib/chain/opPools/executionPayloadBidPool.js +57 -0
  57. package/lib/chain/opPools/executionPayloadBidPool.js.map +1 -0
  58. package/lib/chain/opPools/index.d.ts +2 -0
  59. package/lib/chain/opPools/index.d.ts.map +1 -1
  60. package/lib/chain/opPools/index.js +2 -0
  61. package/lib/chain/opPools/index.js.map +1 -1
  62. package/lib/chain/opPools/payloadAttestationPool.d.ts +24 -0
  63. package/lib/chain/opPools/payloadAttestationPool.d.ts.map +1 -0
  64. package/lib/chain/opPools/payloadAttestationPool.js +109 -0
  65. package/lib/chain/opPools/payloadAttestationPool.js.map +1 -0
  66. package/lib/chain/regen/interface.d.ts +1 -0
  67. package/lib/chain/regen/interface.d.ts.map +1 -1
  68. package/lib/chain/regen/interface.js +1 -0
  69. package/lib/chain/regen/interface.js.map +1 -1
  70. package/lib/chain/seenCache/index.d.ts +3 -1
  71. package/lib/chain/seenCache/index.d.ts.map +1 -1
  72. package/lib/chain/seenCache/index.js +3 -1
  73. package/lib/chain/seenCache/index.js.map +1 -1
  74. package/lib/chain/seenCache/seenAttesters.d.ts +5 -0
  75. package/lib/chain/seenCache/seenAttesters.d.ts.map +1 -1
  76. package/lib/chain/seenCache/seenAttesters.js +5 -0
  77. package/lib/chain/seenCache/seenAttesters.js.map +1 -1
  78. package/lib/chain/seenCache/seenExecutionPayloadBids.d.ts +12 -0
  79. package/lib/chain/seenCache/seenExecutionPayloadBids.d.ts.map +1 -0
  80. package/lib/chain/seenCache/seenExecutionPayloadBids.js +30 -0
  81. package/lib/chain/seenCache/seenExecutionPayloadBids.js.map +1 -0
  82. package/lib/chain/seenCache/seenExecutionPayloadEnvelope.d.ts +15 -0
  83. package/lib/chain/seenCache/seenExecutionPayloadEnvelope.d.ts.map +1 -0
  84. package/lib/chain/seenCache/seenExecutionPayloadEnvelope.js +28 -0
  85. package/lib/chain/seenCache/seenExecutionPayloadEnvelope.js.map +1 -0
  86. package/lib/chain/validation/aggregateAndProof.js +35 -14
  87. package/lib/chain/validation/aggregateAndProof.js.map +1 -1
  88. package/lib/chain/validation/attestation.d.ts +2 -2
  89. package/lib/chain/validation/attestation.d.ts.map +1 -1
  90. package/lib/chain/validation/attestation.js +27 -8
  91. package/lib/chain/validation/attestation.js.map +1 -1
  92. package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
  93. package/lib/chain/validation/attesterSlashing.js +1 -1
  94. package/lib/chain/validation/attesterSlashing.js.map +1 -1
  95. package/lib/chain/validation/blobSidecar.d.ts.map +1 -1
  96. package/lib/chain/validation/blobSidecar.js +2 -2
  97. package/lib/chain/validation/blobSidecar.js.map +1 -1
  98. package/lib/chain/validation/block.d.ts.map +1 -1
  99. package/lib/chain/validation/block.js +5 -4
  100. package/lib/chain/validation/block.js.map +1 -1
  101. package/lib/chain/validation/dataColumnSidecar.d.ts.map +1 -1
  102. package/lib/chain/validation/dataColumnSidecar.js +2 -2
  103. package/lib/chain/validation/dataColumnSidecar.js.map +1 -1
  104. package/lib/chain/validation/executionPayloadBid.d.ts +5 -0
  105. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -0
  106. package/lib/chain/validation/executionPayloadBid.js +103 -0
  107. package/lib/chain/validation/executionPayloadBid.js.map +1 -0
  108. package/lib/chain/validation/executionPayloadEnvelope.d.ts +5 -0
  109. package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -0
  110. package/lib/chain/validation/executionPayloadEnvelope.js +89 -0
  111. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -0
  112. package/lib/chain/validation/payloadAttestationMessage.d.ts +9 -0
  113. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -0
  114. package/lib/chain/validation/payloadAttestationMessage.js +72 -0
  115. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -0
  116. package/lib/chain/validation/proposerSlashing.js +1 -1
  117. package/lib/chain/validation/proposerSlashing.js.map +1 -1
  118. package/lib/chain/validation/signatureSets/aggregateAndProof.d.ts +2 -3
  119. package/lib/chain/validation/signatureSets/aggregateAndProof.d.ts.map +1 -1
  120. package/lib/chain/validation/signatureSets/aggregateAndProof.js +8 -3
  121. package/lib/chain/validation/signatureSets/aggregateAndProof.js.map +1 -1
  122. package/lib/chain/validation/signatureSets/contributionAndProof.d.ts +2 -2
  123. package/lib/chain/validation/signatureSets/contributionAndProof.d.ts.map +1 -1
  124. package/lib/chain/validation/signatureSets/contributionAndProof.js +3 -3
  125. package/lib/chain/validation/signatureSets/contributionAndProof.js.map +1 -1
  126. package/lib/chain/validation/signatureSets/selectionProof.d.ts +2 -3
  127. package/lib/chain/validation/signatureSets/selectionProof.d.ts.map +1 -1
  128. package/lib/chain/validation/signatureSets/selectionProof.js +8 -3
  129. package/lib/chain/validation/signatureSets/selectionProof.js.map +1 -1
  130. package/lib/chain/validation/signatureSets/syncCommittee.d.ts +2 -2
  131. package/lib/chain/validation/signatureSets/syncCommittee.d.ts.map +1 -1
  132. package/lib/chain/validation/signatureSets/syncCommittee.js +3 -3
  133. package/lib/chain/validation/signatureSets/syncCommittee.js.map +1 -1
  134. package/lib/chain/validation/signatureSets/syncCommitteeContribution.d.ts +1 -2
  135. package/lib/chain/validation/signatureSets/syncCommitteeContribution.d.ts.map +1 -1
  136. package/lib/chain/validation/signatureSets/syncCommitteeContribution.js +2 -2
  137. package/lib/chain/validation/signatureSets/syncCommitteeContribution.js.map +1 -1
  138. package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.d.ts +2 -2
  139. package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.d.ts.map +1 -1
  140. package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.js +3 -3
  141. package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.js.map +1 -1
  142. package/lib/chain/validation/syncCommittee.js +1 -1
  143. package/lib/chain/validation/syncCommittee.js.map +1 -1
  144. package/lib/chain/validation/syncCommitteeContributionAndProof.d.ts.map +1 -1
  145. package/lib/chain/validation/syncCommitteeContributionAndProof.js +3 -5
  146. package/lib/chain/validation/syncCommitteeContributionAndProof.js.map +1 -1
  147. package/lib/chain/validation/voluntaryExit.js +1 -1
  148. package/lib/chain/validation/voluntaryExit.js.map +1 -1
  149. package/lib/metrics/metrics/lodestar.d.ts +20 -0
  150. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  151. package/lib/metrics/metrics/lodestar.js +40 -0
  152. package/lib/metrics/metrics/lodestar.js.map +1 -1
  153. package/lib/network/gossip/interface.d.ts +20 -2
  154. package/lib/network/gossip/interface.d.ts.map +1 -1
  155. package/lib/network/gossip/interface.js +3 -0
  156. package/lib/network/gossip/interface.js.map +1 -1
  157. package/lib/network/gossip/scoringParameters.d.ts.map +1 -1
  158. package/lib/network/gossip/scoringParameters.js +38 -2
  159. package/lib/network/gossip/scoringParameters.js.map +1 -1
  160. package/lib/network/gossip/topic.d.ts +77 -1
  161. package/lib/network/gossip/topic.d.ts.map +1 -1
  162. package/lib/network/gossip/topic.js +20 -0
  163. package/lib/network/gossip/topic.js.map +1 -1
  164. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  165. package/lib/network/processor/gossipHandlers.js +34 -0
  166. package/lib/network/processor/gossipHandlers.js.map +1 -1
  167. package/lib/network/processor/gossipQueues/index.d.ts.map +1 -1
  168. package/lib/network/processor/gossipQueues/index.js +16 -0
  169. package/lib/network/processor/gossipQueues/index.js.map +1 -1
  170. package/lib/network/processor/index.d.ts.map +1 -1
  171. package/lib/network/processor/index.js +3 -0
  172. package/lib/network/processor/index.js.map +1 -1
  173. package/lib/sync/backfill/backfill.js +2 -2
  174. package/lib/sync/backfill/backfill.js.map +1 -1
  175. package/lib/sync/backfill/verify.d.ts +1 -2
  176. package/lib/sync/backfill/verify.d.ts.map +1 -1
  177. package/lib/sync/backfill/verify.js +2 -2
  178. package/lib/sync/backfill/verify.js.map +1 -1
  179. package/package.json +15 -15
  180. package/src/chain/blocks/verifyBlock.ts +0 -1
  181. package/src/chain/blocks/verifyBlocksSignatures.ts +4 -12
  182. package/src/chain/bls/multithread/index.ts +7 -4
  183. package/src/chain/bls/multithread/jobItem.ts +7 -3
  184. package/src/chain/bls/singleThread.ts +5 -3
  185. package/src/chain/bls/utils.ts +15 -7
  186. package/src/chain/chain.ts +25 -3
  187. package/src/chain/errors/attestationError.ts +11 -1
  188. package/src/chain/errors/executionPayloadBid.ts +35 -0
  189. package/src/chain/errors/executionPayloadEnvelope.ts +34 -0
  190. package/src/chain/errors/index.ts +3 -0
  191. package/src/chain/errors/payloadAttestation.ts +25 -0
  192. package/src/chain/forkChoice/index.ts +19 -0
  193. package/src/chain/interface.ts +16 -1
  194. package/src/chain/opPools/executionPayloadBidPool.ts +77 -0
  195. package/src/chain/opPools/index.ts +2 -0
  196. package/src/chain/opPools/payloadAttestationPool.ts +157 -0
  197. package/src/chain/regen/interface.ts +1 -0
  198. package/src/chain/seenCache/index.ts +3 -1
  199. package/src/chain/seenCache/seenAttesters.ts +5 -0
  200. package/src/chain/seenCache/seenExecutionPayloadBids.ts +35 -0
  201. package/src/chain/seenCache/seenExecutionPayloadEnvelope.ts +34 -0
  202. package/src/chain/validation/aggregateAndProof.ts +36 -14
  203. package/src/chain/validation/attestation.ts +33 -16
  204. package/src/chain/validation/attesterSlashing.ts +1 -6
  205. package/src/chain/validation/blobSidecar.ts +1 -6
  206. package/src/chain/validation/block.ts +5 -4
  207. package/src/chain/validation/dataColumnSidecar.ts +1 -6
  208. package/src/chain/validation/executionPayloadBid.ts +140 -0
  209. package/src/chain/validation/executionPayloadEnvelope.ts +122 -0
  210. package/src/chain/validation/payloadAttestationMessage.ts +109 -0
  211. package/src/chain/validation/proposerSlashing.ts +1 -6
  212. package/src/chain/validation/signatureSets/aggregateAndProof.ts +9 -14
  213. package/src/chain/validation/signatureSets/contributionAndProof.ts +2 -4
  214. package/src/chain/validation/signatureSets/selectionProof.ts +9 -9
  215. package/src/chain/validation/signatureSets/syncCommittee.ts +2 -4
  216. package/src/chain/validation/signatureSets/syncCommitteeContribution.ts +2 -3
  217. package/src/chain/validation/signatureSets/syncCommitteeSelectionProof.ts +2 -4
  218. package/src/chain/validation/syncCommittee.ts +1 -1
  219. package/src/chain/validation/syncCommitteeContributionAndProof.ts +3 -5
  220. package/src/chain/validation/voluntaryExit.ts +1 -1
  221. package/src/metrics/metrics/lodestar.ts +40 -0
  222. package/src/network/gossip/interface.ts +17 -0
  223. package/src/network/gossip/scoringParameters.ts +44 -2
  224. package/src/network/gossip/topic.ts +21 -0
  225. package/src/network/processor/gossipHandlers.ts +48 -0
  226. package/src/network/processor/gossipQueues/index.ts +16 -0
  227. package/src/network/processor/index.ts +3 -0
  228. package/src/sync/backfill/backfill.ts +2 -2
  229. 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);
@@ -488,6 +500,8 @@ export class BeaconChain implements IBeaconChain {
488
500
  this.seenAttesters.isKnown(epoch, index) ||
489
501
  // seenAggregators = single aggregator index, not participants of the aggregate
490
502
  this.seenAggregators.isKnown(epoch, index) ||
503
+ // seenPayloadAttesters = single signer of payload attestation message
504
+ this.seenPayloadAttesters.isKnown(epoch, index) ||
491
505
  // seenBlockProposers = single block proposer
492
506
  this.seenBlockProposers.seenAtEpoch(epoch, index)
493
507
  );
@@ -1262,6 +1276,8 @@ export class BeaconChain implements IBeaconChain {
1262
1276
  metrics.opPool.proposerSlashingPoolSize.set(this.opPool.proposerSlashingsSize);
1263
1277
  metrics.opPool.voluntaryExitPoolSize.set(this.opPool.voluntaryExitsSize);
1264
1278
  metrics.opPool.syncCommitteeMessagePoolSize.set(this.syncCommitteeMessagePool.size);
1279
+ metrics.opPool.payloadAttestationPool.size.set(this.payloadAttestationPool.size);
1280
+ metrics.opPool.executionPayloadBidPool.size.set(this.executionPayloadBidPool.size);
1265
1281
  // syncContributionAndProofPool tracks metrics on its own
1266
1282
  metrics.opPool.blsToExecutionChangePoolSize.set(this.opPool.blsToExecutionChangeSize);
1267
1283
  metrics.chain.blacklistedBlocks.set(this.blacklistedBlocks.size);
@@ -1292,6 +1308,9 @@ export class BeaconChain implements IBeaconChain {
1292
1308
  this.aggregatedAttestationPool.prune(slot);
1293
1309
  this.syncCommitteeMessagePool.prune(slot);
1294
1310
  this.seenSyncCommitteeMessages.prune(slot);
1311
+ this.payloadAttestationPool.prune(slot);
1312
+ this.executionPayloadBidPool.prune(slot);
1313
+ this.seenExecutionPayloadBids.prune(slot);
1295
1314
  this.seenAttestationDatas.onSlot(slot);
1296
1315
  this.reprocessController.onSlot(slot);
1297
1316
 
@@ -1315,6 +1334,7 @@ export class BeaconChain implements IBeaconChain {
1315
1334
 
1316
1335
  this.seenAttesters.prune(epoch);
1317
1336
  this.seenAggregators.prune(epoch);
1337
+ this.seenPayloadAttesters.prune(epoch);
1318
1338
  this.seenAggregatedAttestations.prune(epoch);
1319
1339
  this.seenBlockAttesters.prune(epoch);
1320
1340
  this.beaconProposerCache.prune(epoch);
@@ -1338,7 +1358,9 @@ export class BeaconChain implements IBeaconChain {
1338
1358
 
1339
1359
  private async onForkChoiceFinalized(this: BeaconChain, cp: CheckpointWithHex): Promise<void> {
1340
1360
  this.logger.verbose("Fork choice finalized", {epoch: cp.epoch, root: cp.rootHex});
1341
- this.seenBlockProposers.prune(computeStartSlotAtEpoch(cp.epoch));
1361
+ const finalizedSlot = computeStartSlotAtEpoch(cp.epoch);
1362
+ this.seenBlockProposers.prune(finalizedSlot);
1363
+ this.seenExecutionPayloadEnvelopes.prune(finalizedSlot);
1342
1364
 
1343
1365
  // Update validator custody to account for effective balance changes
1344
1366
  await this.updateValidatorsCustodyRequirement(cp);
@@ -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
+ }
@@ -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
  }
@@ -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
+ }