@lodestar/beacon-node 1.40.0-dev.1cab20c166 → 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 (253) 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 -0
  6. package/lib/api/impl/lodestar/index.js.map +1 -1
  7. package/lib/chain/ColumnReconstructionTracker.d.ts +2 -0
  8. package/lib/chain/ColumnReconstructionTracker.d.ts.map +1 -1
  9. package/lib/chain/ColumnReconstructionTracker.js +7 -3
  10. package/lib/chain/ColumnReconstructionTracker.js.map +1 -1
  11. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  12. package/lib/chain/blocks/verifyBlock.js +1 -1
  13. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  14. package/lib/chain/blocks/verifyBlocksSignatures.d.ts +2 -2
  15. package/lib/chain/blocks/verifyBlocksSignatures.d.ts.map +1 -1
  16. package/lib/chain/blocks/verifyBlocksSignatures.js +2 -2
  17. package/lib/chain/blocks/verifyBlocksSignatures.js.map +1 -1
  18. package/lib/chain/bls/multithread/index.d.ts +3 -1
  19. package/lib/chain/bls/multithread/index.d.ts.map +1 -1
  20. package/lib/chain/bls/multithread/index.js +5 -3
  21. package/lib/chain/bls/multithread/index.js.map +1 -1
  22. package/lib/chain/bls/multithread/jobItem.d.ts +2 -2
  23. package/lib/chain/bls/multithread/jobItem.d.ts.map +1 -1
  24. package/lib/chain/bls/multithread/jobItem.js +2 -2
  25. package/lib/chain/bls/multithread/jobItem.js.map +1 -1
  26. package/lib/chain/bls/singleThread.d.ts +4 -2
  27. package/lib/chain/bls/singleThread.d.ts.map +1 -1
  28. package/lib/chain/bls/singleThread.js +4 -2
  29. package/lib/chain/bls/singleThread.js.map +1 -1
  30. package/lib/chain/bls/utils.d.ts +2 -2
  31. package/lib/chain/bls/utils.d.ts.map +1 -1
  32. package/lib/chain/bls/utils.js +9 -6
  33. package/lib/chain/bls/utils.js.map +1 -1
  34. package/lib/chain/chain.d.ts +7 -2
  35. package/lib/chain/chain.d.ts.map +1 -1
  36. package/lib/chain/chain.js +27 -9
  37. package/lib/chain/chain.js.map +1 -1
  38. package/lib/chain/errors/attestationError.d.ts +14 -1
  39. package/lib/chain/errors/attestationError.d.ts.map +1 -1
  40. package/lib/chain/errors/attestationError.js +8 -0
  41. package/lib/chain/errors/attestationError.js.map +1 -1
  42. package/lib/chain/errors/executionPayloadBid.d.ts +48 -0
  43. package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -0
  44. package/lib/chain/errors/executionPayloadBid.js +15 -0
  45. package/lib/chain/errors/executionPayloadBid.js.map +1 -0
  46. package/lib/chain/errors/executionPayloadEnvelope.d.ts +48 -0
  47. package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -0
  48. package/lib/chain/errors/executionPayloadEnvelope.js +16 -0
  49. package/lib/chain/errors/executionPayloadEnvelope.js.map +1 -0
  50. package/lib/chain/errors/index.d.ts +3 -0
  51. package/lib/chain/errors/index.d.ts.map +1 -1
  52. package/lib/chain/errors/index.js +3 -0
  53. package/lib/chain/errors/index.js.map +1 -1
  54. package/lib/chain/errors/payloadAttestation.d.ts +34 -0
  55. package/lib/chain/errors/payloadAttestation.d.ts.map +1 -0
  56. package/lib/chain/errors/payloadAttestation.js +13 -0
  57. package/lib/chain/errors/payloadAttestation.js.map +1 -0
  58. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  59. package/lib/chain/forkChoice/index.js +18 -0
  60. package/lib/chain/forkChoice/index.js.map +1 -1
  61. package/lib/chain/interface.d.ts +7 -2
  62. package/lib/chain/interface.d.ts.map +1 -1
  63. package/lib/chain/interface.js.map +1 -1
  64. package/lib/chain/opPools/executionPayloadBidPool.d.ts +21 -0
  65. package/lib/chain/opPools/executionPayloadBidPool.d.ts.map +1 -0
  66. package/lib/chain/opPools/executionPayloadBidPool.js +57 -0
  67. package/lib/chain/opPools/executionPayloadBidPool.js.map +1 -0
  68. package/lib/chain/opPools/index.d.ts +2 -0
  69. package/lib/chain/opPools/index.d.ts.map +1 -1
  70. package/lib/chain/opPools/index.js +2 -0
  71. package/lib/chain/opPools/index.js.map +1 -1
  72. package/lib/chain/opPools/payloadAttestationPool.d.ts +24 -0
  73. package/lib/chain/opPools/payloadAttestationPool.d.ts.map +1 -0
  74. package/lib/chain/opPools/payloadAttestationPool.js +109 -0
  75. package/lib/chain/opPools/payloadAttestationPool.js.map +1 -0
  76. package/lib/chain/regen/interface.d.ts +1 -0
  77. package/lib/chain/regen/interface.d.ts.map +1 -1
  78. package/lib/chain/regen/interface.js +1 -0
  79. package/lib/chain/regen/interface.js.map +1 -1
  80. package/lib/chain/regen/regen.d.ts +2 -0
  81. package/lib/chain/regen/regen.d.ts.map +1 -1
  82. package/lib/chain/regen/regen.js +4 -1
  83. package/lib/chain/regen/regen.js.map +1 -1
  84. package/lib/chain/seenCache/index.d.ts +3 -1
  85. package/lib/chain/seenCache/index.d.ts.map +1 -1
  86. package/lib/chain/seenCache/index.js +3 -1
  87. package/lib/chain/seenCache/index.js.map +1 -1
  88. package/lib/chain/seenCache/seenAttesters.d.ts +5 -0
  89. package/lib/chain/seenCache/seenAttesters.d.ts.map +1 -1
  90. package/lib/chain/seenCache/seenAttesters.js +5 -0
  91. package/lib/chain/seenCache/seenAttesters.js.map +1 -1
  92. package/lib/chain/seenCache/seenExecutionPayloadBids.d.ts +12 -0
  93. package/lib/chain/seenCache/seenExecutionPayloadBids.d.ts.map +1 -0
  94. package/lib/chain/seenCache/seenExecutionPayloadBids.js +30 -0
  95. package/lib/chain/seenCache/seenExecutionPayloadBids.js.map +1 -0
  96. package/lib/chain/seenCache/seenExecutionPayloadEnvelope.d.ts +15 -0
  97. package/lib/chain/seenCache/seenExecutionPayloadEnvelope.d.ts.map +1 -0
  98. package/lib/chain/seenCache/seenExecutionPayloadEnvelope.js +28 -0
  99. package/lib/chain/seenCache/seenExecutionPayloadEnvelope.js.map +1 -0
  100. package/lib/chain/seenCache/seenGossipBlockInput.js +1 -1
  101. package/lib/chain/validation/aggregateAndProof.js +35 -14
  102. package/lib/chain/validation/aggregateAndProof.js.map +1 -1
  103. package/lib/chain/validation/attestation.d.ts +2 -2
  104. package/lib/chain/validation/attestation.d.ts.map +1 -1
  105. package/lib/chain/validation/attestation.js +27 -8
  106. package/lib/chain/validation/attestation.js.map +1 -1
  107. package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
  108. package/lib/chain/validation/attesterSlashing.js +1 -1
  109. package/lib/chain/validation/attesterSlashing.js.map +1 -1
  110. package/lib/chain/validation/blobSidecar.d.ts.map +1 -1
  111. package/lib/chain/validation/blobSidecar.js +2 -2
  112. package/lib/chain/validation/blobSidecar.js.map +1 -1
  113. package/lib/chain/validation/block.d.ts.map +1 -1
  114. package/lib/chain/validation/block.js +5 -4
  115. package/lib/chain/validation/block.js.map +1 -1
  116. package/lib/chain/validation/dataColumnSidecar.d.ts.map +1 -1
  117. package/lib/chain/validation/dataColumnSidecar.js +2 -2
  118. package/lib/chain/validation/dataColumnSidecar.js.map +1 -1
  119. package/lib/chain/validation/executionPayloadBid.d.ts +5 -0
  120. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -0
  121. package/lib/chain/validation/executionPayloadBid.js +104 -0
  122. package/lib/chain/validation/executionPayloadBid.js.map +1 -0
  123. package/lib/chain/validation/executionPayloadEnvelope.d.ts +5 -0
  124. package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -0
  125. package/lib/chain/validation/executionPayloadEnvelope.js +89 -0
  126. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -0
  127. package/lib/chain/validation/payloadAttestationMessage.d.ts +9 -0
  128. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -0
  129. package/lib/chain/validation/payloadAttestationMessage.js +72 -0
  130. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -0
  131. package/lib/chain/validation/proposerSlashing.js +1 -1
  132. package/lib/chain/validation/proposerSlashing.js.map +1 -1
  133. package/lib/chain/validation/signatureSets/aggregateAndProof.d.ts +2 -3
  134. package/lib/chain/validation/signatureSets/aggregateAndProof.d.ts.map +1 -1
  135. package/lib/chain/validation/signatureSets/aggregateAndProof.js +8 -3
  136. package/lib/chain/validation/signatureSets/aggregateAndProof.js.map +1 -1
  137. package/lib/chain/validation/signatureSets/contributionAndProof.d.ts +2 -2
  138. package/lib/chain/validation/signatureSets/contributionAndProof.d.ts.map +1 -1
  139. package/lib/chain/validation/signatureSets/contributionAndProof.js +3 -3
  140. package/lib/chain/validation/signatureSets/contributionAndProof.js.map +1 -1
  141. package/lib/chain/validation/signatureSets/selectionProof.d.ts +2 -3
  142. package/lib/chain/validation/signatureSets/selectionProof.d.ts.map +1 -1
  143. package/lib/chain/validation/signatureSets/selectionProof.js +8 -3
  144. package/lib/chain/validation/signatureSets/selectionProof.js.map +1 -1
  145. package/lib/chain/validation/signatureSets/syncCommittee.d.ts +2 -2
  146. package/lib/chain/validation/signatureSets/syncCommittee.d.ts.map +1 -1
  147. package/lib/chain/validation/signatureSets/syncCommittee.js +3 -3
  148. package/lib/chain/validation/signatureSets/syncCommittee.js.map +1 -1
  149. package/lib/chain/validation/signatureSets/syncCommitteeContribution.d.ts +1 -2
  150. package/lib/chain/validation/signatureSets/syncCommitteeContribution.d.ts.map +1 -1
  151. package/lib/chain/validation/signatureSets/syncCommitteeContribution.js +2 -2
  152. package/lib/chain/validation/signatureSets/syncCommitteeContribution.js.map +1 -1
  153. package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.d.ts +2 -2
  154. package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.d.ts.map +1 -1
  155. package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.js +3 -3
  156. package/lib/chain/validation/signatureSets/syncCommitteeSelectionProof.js.map +1 -1
  157. package/lib/chain/validation/syncCommittee.js +1 -1
  158. package/lib/chain/validation/syncCommittee.js.map +1 -1
  159. package/lib/chain/validation/syncCommitteeContributionAndProof.d.ts.map +1 -1
  160. package/lib/chain/validation/syncCommitteeContributionAndProof.js +3 -5
  161. package/lib/chain/validation/syncCommitteeContributionAndProof.js.map +1 -1
  162. package/lib/chain/validation/voluntaryExit.js +1 -1
  163. package/lib/chain/validation/voluntaryExit.js.map +1 -1
  164. package/lib/chain/validatorMonitor.d.ts.map +1 -1
  165. package/lib/chain/validatorMonitor.js +7 -4
  166. package/lib/chain/validatorMonitor.js.map +1 -1
  167. package/lib/metrics/metrics/lodestar.d.ts +20 -0
  168. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  169. package/lib/metrics/metrics/lodestar.js +40 -0
  170. package/lib/metrics/metrics/lodestar.js.map +1 -1
  171. package/lib/network/gossip/interface.d.ts +20 -2
  172. package/lib/network/gossip/interface.d.ts.map +1 -1
  173. package/lib/network/gossip/interface.js +3 -0
  174. package/lib/network/gossip/interface.js.map +1 -1
  175. package/lib/network/gossip/scoringParameters.d.ts.map +1 -1
  176. package/lib/network/gossip/scoringParameters.js +38 -2
  177. package/lib/network/gossip/scoringParameters.js.map +1 -1
  178. package/lib/network/gossip/topic.d.ts +77 -1
  179. package/lib/network/gossip/topic.d.ts.map +1 -1
  180. package/lib/network/gossip/topic.js +20 -0
  181. package/lib/network/gossip/topic.js.map +1 -1
  182. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  183. package/lib/network/processor/gossipHandlers.js +34 -0
  184. package/lib/network/processor/gossipHandlers.js.map +1 -1
  185. package/lib/network/processor/gossipQueues/index.d.ts.map +1 -1
  186. package/lib/network/processor/gossipQueues/index.js +16 -0
  187. package/lib/network/processor/gossipQueues/index.js.map +1 -1
  188. package/lib/network/processor/index.d.ts.map +1 -1
  189. package/lib/network/processor/index.js +3 -0
  190. package/lib/network/processor/index.js.map +1 -1
  191. package/lib/sync/backfill/backfill.js +2 -2
  192. package/lib/sync/backfill/backfill.js.map +1 -1
  193. package/lib/sync/backfill/verify.d.ts +1 -2
  194. package/lib/sync/backfill/verify.d.ts.map +1 -1
  195. package/lib/sync/backfill/verify.js +2 -2
  196. package/lib/sync/backfill/verify.js.map +1 -1
  197. package/package.json +15 -15
  198. package/src/api/impl/beacon/blocks/index.ts +9 -7
  199. package/src/api/impl/lodestar/index.ts +12 -0
  200. package/src/chain/ColumnReconstructionTracker.ts +8 -4
  201. package/src/chain/blocks/verifyBlock.ts +0 -1
  202. package/src/chain/blocks/verifyBlocksSignatures.ts +4 -12
  203. package/src/chain/bls/multithread/index.ts +7 -4
  204. package/src/chain/bls/multithread/jobItem.ts +7 -3
  205. package/src/chain/bls/singleThread.ts +5 -3
  206. package/src/chain/bls/utils.ts +15 -7
  207. package/src/chain/chain.ts +30 -7
  208. package/src/chain/errors/attestationError.ts +11 -1
  209. package/src/chain/errors/executionPayloadBid.ts +35 -0
  210. package/src/chain/errors/executionPayloadEnvelope.ts +34 -0
  211. package/src/chain/errors/index.ts +3 -0
  212. package/src/chain/errors/payloadAttestation.ts +25 -0
  213. package/src/chain/forkChoice/index.ts +19 -0
  214. package/src/chain/interface.ts +16 -1
  215. package/src/chain/opPools/executionPayloadBidPool.ts +77 -0
  216. package/src/chain/opPools/index.ts +2 -0
  217. package/src/chain/opPools/payloadAttestationPool.ts +157 -0
  218. package/src/chain/regen/interface.ts +1 -0
  219. package/src/chain/regen/regen.ts +6 -1
  220. package/src/chain/seenCache/index.ts +3 -1
  221. package/src/chain/seenCache/seenAttesters.ts +5 -0
  222. package/src/chain/seenCache/seenExecutionPayloadBids.ts +35 -0
  223. package/src/chain/seenCache/seenExecutionPayloadEnvelope.ts +34 -0
  224. package/src/chain/seenCache/seenGossipBlockInput.ts +1 -1
  225. package/src/chain/validation/aggregateAndProof.ts +36 -14
  226. package/src/chain/validation/attestation.ts +33 -16
  227. package/src/chain/validation/attesterSlashing.ts +1 -6
  228. package/src/chain/validation/blobSidecar.ts +1 -6
  229. package/src/chain/validation/block.ts +5 -4
  230. package/src/chain/validation/dataColumnSidecar.ts +1 -6
  231. package/src/chain/validation/executionPayloadBid.ts +141 -0
  232. package/src/chain/validation/executionPayloadEnvelope.ts +122 -0
  233. package/src/chain/validation/payloadAttestationMessage.ts +109 -0
  234. package/src/chain/validation/proposerSlashing.ts +1 -6
  235. package/src/chain/validation/signatureSets/aggregateAndProof.ts +9 -14
  236. package/src/chain/validation/signatureSets/contributionAndProof.ts +2 -4
  237. package/src/chain/validation/signatureSets/selectionProof.ts +9 -9
  238. package/src/chain/validation/signatureSets/syncCommittee.ts +2 -4
  239. package/src/chain/validation/signatureSets/syncCommitteeContribution.ts +2 -3
  240. package/src/chain/validation/signatureSets/syncCommitteeSelectionProof.ts +2 -4
  241. package/src/chain/validation/syncCommittee.ts +1 -1
  242. package/src/chain/validation/syncCommitteeContributionAndProof.ts +3 -5
  243. package/src/chain/validation/voluntaryExit.ts +1 -1
  244. package/src/chain/validatorMonitor.ts +10 -5
  245. package/src/metrics/metrics/lodestar.ts +40 -0
  246. package/src/network/gossip/interface.ts +17 -0
  247. package/src/network/gossip/scoringParameters.ts +44 -2
  248. package/src/network/gossip/topic.ts +21 -0
  249. package/src/network/processor/gossipHandlers.ts +48 -0
  250. package/src/network/processor/gossipQueues/index.ts +16 -0
  251. package/src/network/processor/index.ts +3 -0
  252. package/src/sync/backfill/backfill.ts +2 -2
  253. package/src/sync/backfill/verify.ts +2 -3
@@ -1,17 +1,25 @@
1
1
  import {PublicKey, aggregatePublicKeys} from "@chainsafe/blst";
2
- import {ISignatureSet, SignatureSetType} from "@lodestar/state-transition";
2
+ import {ISignatureSet, Index2PubkeyCache, SignatureSetType} from "@lodestar/state-transition";
3
3
  import {Metrics} from "../../metrics/metrics.js";
4
4
 
5
- export function getAggregatedPubkey(signatureSet: ISignatureSet, metrics: Metrics | null = null): PublicKey {
5
+ export function getAggregatedPubkey(
6
+ signatureSet: ISignatureSet,
7
+ index2pubkey: Index2PubkeyCache,
8
+ metrics: Metrics | null = null
9
+ ): PublicKey {
6
10
  switch (signatureSet.type) {
7
11
  case SignatureSetType.single:
8
12
  return signatureSet.pubkey;
9
13
 
14
+ case SignatureSetType.indexed:
15
+ return index2pubkey[signatureSet.index];
16
+
10
17
  case SignatureSetType.aggregate: {
11
18
  const timer = metrics?.blsThreadPool.pubkeysAggregationMainThreadDuration.startTimer();
12
- const pubkeys = aggregatePublicKeys(signatureSet.pubkeys);
19
+ const pubkeys = signatureSet.indices.map((i) => index2pubkey[i]);
20
+ const aggregated = aggregatePublicKeys(pubkeys);
13
21
  timer?.();
14
- return pubkeys;
22
+ return aggregated;
15
23
  }
16
24
 
17
25
  default:
@@ -20,11 +28,11 @@ export function getAggregatedPubkey(signatureSet: ISignatureSet, metrics: Metric
20
28
  }
21
29
 
22
30
  export function getAggregatedPubkeysCount(signatureSets: ISignatureSet[]): number {
23
- let pubkeysConut = 0;
31
+ let pubkeysCount = 0;
24
32
  for (const set of signatureSets) {
25
33
  if (set.type === SignatureSetType.aggregate) {
26
- pubkeysConut += set.pubkeys.length;
34
+ pubkeysCount += set.indices.length;
27
35
  }
28
36
  }
29
- return pubkeysConut;
37
+ return pubkeysCount;
30
38
  }
@@ -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
  );
@@ -1262,6 +1277,8 @@ export class BeaconChain implements IBeaconChain {
1262
1277
  metrics.opPool.proposerSlashingPoolSize.set(this.opPool.proposerSlashingsSize);
1263
1278
  metrics.opPool.voluntaryExitPoolSize.set(this.opPool.voluntaryExitsSize);
1264
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);
1265
1282
  // syncContributionAndProofPool tracks metrics on its own
1266
1283
  metrics.opPool.blsToExecutionChangePoolSize.set(this.opPool.blsToExecutionChangeSize);
1267
1284
  metrics.chain.blacklistedBlocks.set(this.blacklistedBlocks.size);
@@ -1292,6 +1309,9 @@ export class BeaconChain implements IBeaconChain {
1292
1309
  this.aggregatedAttestationPool.prune(slot);
1293
1310
  this.syncCommitteeMessagePool.prune(slot);
1294
1311
  this.seenSyncCommitteeMessages.prune(slot);
1312
+ this.payloadAttestationPool.prune(slot);
1313
+ this.executionPayloadBidPool.prune(slot);
1314
+ this.seenExecutionPayloadBids.prune(slot);
1295
1315
  this.seenAttestationDatas.onSlot(slot);
1296
1316
  this.reprocessController.onSlot(slot);
1297
1317
 
@@ -1315,6 +1335,7 @@ export class BeaconChain implements IBeaconChain {
1315
1335
 
1316
1336
  this.seenAttesters.prune(epoch);
1317
1337
  this.seenAggregators.prune(epoch);
1338
+ this.seenPayloadAttesters.prune(epoch);
1318
1339
  this.seenAggregatedAttestations.prune(epoch);
1319
1340
  this.seenBlockAttesters.prune(epoch);
1320
1341
  this.beaconProposerCache.prune(epoch);
@@ -1338,7 +1359,9 @@ export class BeaconChain implements IBeaconChain {
1338
1359
 
1339
1360
  private async onForkChoiceFinalized(this: BeaconChain, cp: CheckpointWithHex): Promise<void> {
1340
1361
  this.logger.verbose("Fork choice finalized", {epoch: cp.epoch, root: cp.rootHex});
1341
- this.seenBlockProposers.prune(computeStartSlotAtEpoch(cp.epoch));
1362
+ const finalizedSlot = computeStartSlotAtEpoch(cp.epoch);
1363
+ this.seenBlockProposers.prune(finalizedSlot);
1364
+ this.seenExecutionPayloadEnvelopes.prune(finalizedSlot);
1342
1365
 
1343
1366
  // Update validator custody to account for effective balance changes
1344
1367
  await this.updateValidatorsCustodyRequirement(cp);
@@ -1346,13 +1369,13 @@ export class BeaconChain implements IBeaconChain {
1346
1369
  // TODO: Improve using regen here
1347
1370
  const {blockRoot, stateRoot, slot} = this.forkChoice.getHead();
1348
1371
  const headState = this.regen.getStateSync(stateRoot);
1349
- const headBlock = await this.db.block.get(fromHex(blockRoot));
1350
- if (headBlock == null) {
1351
- 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`);
1352
1375
  }
1353
1376
 
1354
1377
  if (headState) {
1355
- this.opPool.pruneAll(headBlock, headState);
1378
+ this.opPool.pruneAll(blockResult.block, headState);
1356
1379
  }
1357
1380
 
1358
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
+ }
@@ -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
  }
@@ -18,6 +18,7 @@ import {Metrics} from "../../metrics/index.js";
18
18
  import {nextEventLoop} from "../../util/eventLoop.js";
19
19
  import {getCheckpointFromState} from "../blocks/utils/checkpoint.js";
20
20
  import {ChainEvent, ChainEventEmitter} from "../emitter.js";
21
+ import {SeenBlockInput} from "../seenCache/seenGossipBlockInput.js";
21
22
  import {BlockStateCache, CheckpointStateCache} from "../stateCache/types.js";
22
23
  import {ValidatorMonitor} from "../validatorMonitor.js";
23
24
  import {RegenError, RegenErrorCode} from "./errors.js";
@@ -28,6 +29,7 @@ export type RegenModules = {
28
29
  forkChoice: IForkChoice;
29
30
  blockStateCache: BlockStateCache;
30
31
  checkpointStateCache: CheckpointStateCache;
32
+ seenBlockInputCache: SeenBlockInput;
31
33
  config: ChainForkConfig;
32
34
  emitter: ChainEventEmitter;
33
35
  logger: Logger;
@@ -191,7 +193,10 @@ export class StateRegenerator implements IStateRegeneratorInternal {
191
193
  const protoBlocksAsc = blocksToReplay.reverse();
192
194
  for (const [i, protoBlock] of protoBlocksAsc.entries()) {
193
195
  replaySlots[i] = protoBlock.slot;
194
- blockPromises[i] = this.modules.db.block.get(fromHex(protoBlock.blockRoot));
196
+ const blockInput = this.modules.seenBlockInputCache.get(protoBlock.blockRoot);
197
+ blockPromises[i] = blockInput?.hasBlock()
198
+ ? Promise.resolve(blockInput.getBlock())
199
+ : this.modules.db.block.get(fromHex(protoBlock.blockRoot));
195
200
  }
196
201
 
197
202
  const logCtx = {stateRoot, caller, replaySlots: replaySlots.join(",")};