@lodestar/beacon-node 1.44.0-dev.6ef8199cfa → 1.44.0-dev.762dd5f186

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 (238) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +66 -33
  3. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  4. package/lib/api/impl/beacon/pool/index.d.ts.map +1 -1
  5. package/lib/api/impl/beacon/pool/index.js +1 -26
  6. package/lib/api/impl/beacon/pool/index.js.map +1 -1
  7. package/lib/api/impl/config/constants.d.ts +5 -0
  8. package/lib/api/impl/config/constants.d.ts.map +1 -1
  9. package/lib/api/impl/config/constants.js +6 -1
  10. package/lib/api/impl/config/constants.js.map +1 -1
  11. package/lib/api/impl/debug/index.d.ts.map +1 -1
  12. package/lib/api/impl/debug/index.js +69 -12
  13. package/lib/api/impl/debug/index.js.map +1 -1
  14. package/lib/api/impl/lodestar/index.d.ts.map +1 -1
  15. package/lib/api/impl/lodestar/index.js +28 -0
  16. package/lib/api/impl/lodestar/index.js.map +1 -1
  17. package/lib/api/impl/validator/index.d.ts.map +1 -1
  18. package/lib/api/impl/validator/index.js +117 -72
  19. package/lib/api/impl/validator/index.js.map +1 -1
  20. package/lib/chain/archiveStore/archiveStore.d.ts +0 -1
  21. package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
  22. package/lib/chain/archiveStore/archiveStore.js +0 -4
  23. package/lib/chain/archiveStore/archiveStore.js.map +1 -1
  24. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  25. package/lib/chain/blocks/importBlock.js +19 -4
  26. package/lib/chain/blocks/importBlock.js.map +1 -1
  27. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  28. package/lib/chain/blocks/importExecutionPayload.js +5 -3
  29. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  30. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -1
  31. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +3 -3
  32. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -1
  33. package/lib/chain/chain.d.ts +3 -3
  34. package/lib/chain/chain.d.ts.map +1 -1
  35. package/lib/chain/chain.js +11 -3
  36. package/lib/chain/chain.js.map +1 -1
  37. package/lib/chain/emitter.d.ts +2 -1
  38. package/lib/chain/emitter.d.ts.map +1 -1
  39. package/lib/chain/emitter.js.map +1 -1
  40. package/lib/chain/errors/blockError.d.ts +0 -7
  41. package/lib/chain/errors/blockError.d.ts.map +1 -1
  42. package/lib/chain/errors/blockError.js +0 -3
  43. package/lib/chain/errors/blockError.js.map +1 -1
  44. package/lib/chain/errors/executionPayloadBid.d.ts +23 -1
  45. package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
  46. package/lib/chain/errors/executionPayloadBid.js +4 -0
  47. package/lib/chain/errors/executionPayloadBid.js.map +1 -1
  48. package/lib/chain/errors/payloadAttestation.d.ts +6 -0
  49. package/lib/chain/errors/payloadAttestation.d.ts.map +1 -1
  50. package/lib/chain/errors/payloadAttestation.js +1 -0
  51. package/lib/chain/errors/payloadAttestation.js.map +1 -1
  52. package/lib/chain/forkChoice/index.d.ts +4 -4
  53. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  54. package/lib/chain/forkChoice/index.js +24 -11
  55. package/lib/chain/forkChoice/index.js.map +1 -1
  56. package/lib/chain/interface.d.ts +2 -2
  57. package/lib/chain/interface.d.ts.map +1 -1
  58. package/lib/chain/interface.js.map +1 -1
  59. package/lib/chain/opPools/executionPayloadBidPool.d.ts +4 -4
  60. package/lib/chain/opPools/executionPayloadBidPool.d.ts.map +1 -1
  61. package/lib/chain/opPools/executionPayloadBidPool.js +6 -4
  62. package/lib/chain/opPools/executionPayloadBidPool.js.map +1 -1
  63. package/lib/chain/options.d.ts.map +1 -1
  64. package/lib/chain/options.js +1 -0
  65. package/lib/chain/options.js.map +1 -1
  66. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  67. package/lib/chain/prepareNextSlot.js +2 -10
  68. package/lib/chain/prepareNextSlot.js.map +1 -1
  69. package/lib/chain/produceBlock/produceBlockBody.d.ts +4 -2
  70. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  71. package/lib/chain/produceBlock/produceBlockBody.js +81 -27
  72. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  73. package/lib/chain/regen/interface.d.ts +2 -1
  74. package/lib/chain/regen/interface.d.ts.map +1 -1
  75. package/lib/chain/regen/interface.js +2 -0
  76. package/lib/chain/regen/interface.js.map +1 -1
  77. package/lib/chain/regen/queued.d.ts +0 -1
  78. package/lib/chain/regen/queued.d.ts.map +1 -1
  79. package/lib/chain/regen/queued.js +0 -4
  80. package/lib/chain/regen/queued.js.map +1 -1
  81. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  82. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +8 -2
  83. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  84. package/lib/chain/stateCache/fifoBlockStateCache.d.ts +0 -5
  85. package/lib/chain/stateCache/fifoBlockStateCache.d.ts.map +1 -1
  86. package/lib/chain/stateCache/fifoBlockStateCache.js +0 -5
  87. package/lib/chain/stateCache/fifoBlockStateCache.js.map +1 -1
  88. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts +1 -4
  89. package/lib/chain/stateCache/persistentCheckpointsCache.d.ts.map +1 -1
  90. package/lib/chain/stateCache/persistentCheckpointsCache.js +5 -2
  91. package/lib/chain/stateCache/persistentCheckpointsCache.js.map +1 -1
  92. package/lib/chain/stateCache/types.d.ts +0 -2
  93. package/lib/chain/stateCache/types.d.ts.map +1 -1
  94. package/lib/chain/stateCache/types.js.map +1 -1
  95. package/lib/chain/validation/block.d.ts +5 -1
  96. package/lib/chain/validation/block.d.ts.map +1 -1
  97. package/lib/chain/validation/block.js +4 -14
  98. package/lib/chain/validation/block.js.map +1 -1
  99. package/lib/chain/validation/executionPayloadBid.d.ts +7 -3
  100. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  101. package/lib/chain/validation/executionPayloadBid.js +81 -16
  102. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  103. package/lib/chain/validation/executionPayloadEnvelope.js +1 -3
  104. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  105. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
  106. package/lib/chain/validation/payloadAttestationMessage.js +24 -4
  107. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
  108. package/lib/chain/validatorMonitor.d.ts +1 -0
  109. package/lib/chain/validatorMonitor.d.ts.map +1 -1
  110. package/lib/chain/validatorMonitor.js +16 -0
  111. package/lib/chain/validatorMonitor.js.map +1 -1
  112. package/lib/execution/builder/index.d.ts +1 -2
  113. package/lib/execution/builder/index.d.ts.map +1 -1
  114. package/lib/execution/builder/index.js +0 -1
  115. package/lib/execution/builder/index.js.map +1 -1
  116. package/lib/execution/engine/http.js +1 -1
  117. package/lib/execution/engine/http.js.map +1 -1
  118. package/lib/execution/engine/interface.d.ts +2 -2
  119. package/lib/execution/engine/interface.d.ts.map +1 -1
  120. package/lib/execution/engine/interface.js +6 -2
  121. package/lib/execution/engine/interface.js.map +1 -1
  122. package/lib/execution/engine/mock.d.ts.map +1 -1
  123. package/lib/execution/engine/mock.js +3 -5
  124. package/lib/execution/engine/mock.js.map +1 -1
  125. package/lib/execution/engine/types.d.ts +15 -7
  126. package/lib/execution/engine/types.d.ts.map +1 -1
  127. package/lib/execution/engine/types.js +47 -9
  128. package/lib/execution/engine/types.js.map +1 -1
  129. package/lib/metrics/metrics/lodestar.d.ts +5 -1
  130. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  131. package/lib/metrics/metrics/lodestar.js +14 -3
  132. package/lib/metrics/metrics/lodestar.js.map +1 -1
  133. package/lib/network/gossip/topic.d.ts +770 -3
  134. package/lib/network/gossip/topic.d.ts.map +1 -1
  135. package/lib/network/interface.d.ts +1 -0
  136. package/lib/network/interface.d.ts.map +1 -1
  137. package/lib/network/network.d.ts +1 -0
  138. package/lib/network/network.d.ts.map +1 -1
  139. package/lib/network/network.js +5 -0
  140. package/lib/network/network.js.map +1 -1
  141. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  142. package/lib/network/processor/gossipHandlers.js +21 -6
  143. package/lib/network/processor/gossipHandlers.js.map +1 -1
  144. package/lib/network/processor/index.d.ts +2 -2
  145. package/lib/network/processor/index.d.ts.map +1 -1
  146. package/lib/network/processor/index.js +25 -23
  147. package/lib/network/processor/index.js.map +1 -1
  148. package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
  149. package/lib/network/reqresp/handlers/beaconBlocksByRange.js +9 -5
  150. package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
  151. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
  152. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +13 -3
  153. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
  154. package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.js +1 -1
  155. package/lib/network/reqresp/handlers/dataColumnSidecarsByRoot.js.map +1 -1
  156. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts +2 -1
  157. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts.map +1 -1
  158. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js +16 -6
  159. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
  160. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.d.ts +2 -1
  161. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.d.ts.map +1 -1
  162. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js +15 -1
  163. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js.map +1 -1
  164. package/lib/network/reqresp/handlers/index.js +4 -4
  165. package/lib/network/reqresp/handlers/index.js.map +1 -1
  166. package/lib/network/reqresp/utils/dataColumnResponseValidation.d.ts.map +1 -1
  167. package/lib/network/reqresp/utils/dataColumnResponseValidation.js +23 -5
  168. package/lib/network/reqresp/utils/dataColumnResponseValidation.js.map +1 -1
  169. package/lib/sync/types.d.ts +9 -1
  170. package/lib/sync/types.d.ts.map +1 -1
  171. package/lib/sync/types.js +9 -2
  172. package/lib/sync/types.js.map +1 -1
  173. package/lib/sync/unknownBlock.d.ts.map +1 -1
  174. package/lib/sync/unknownBlock.js +64 -30
  175. package/lib/sync/unknownBlock.js.map +1 -1
  176. package/lib/util/dataColumns.d.ts.map +1 -1
  177. package/lib/util/dataColumns.js +16 -11
  178. package/lib/util/dataColumns.js.map +1 -1
  179. package/lib/util/sszBytes.js +1 -1
  180. package/package.json +15 -17
  181. package/src/api/impl/beacon/blocks/index.ts +76 -42
  182. package/src/api/impl/beacon/pool/index.ts +4 -42
  183. package/src/api/impl/config/constants.ts +10 -0
  184. package/src/api/impl/debug/index.ts +73 -12
  185. package/src/api/impl/lodestar/index.ts +30 -0
  186. package/src/api/impl/validator/index.ts +137 -86
  187. package/src/chain/archiveStore/archiveStore.ts +0 -5
  188. package/src/chain/blocks/importBlock.ts +29 -7
  189. package/src/chain/blocks/importExecutionPayload.ts +8 -2
  190. package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +3 -5
  191. package/src/chain/chain.ts +14 -4
  192. package/src/chain/emitter.ts +3 -2
  193. package/src/chain/errors/blockError.ts +0 -4
  194. package/src/chain/errors/executionPayloadBid.ts +20 -1
  195. package/src/chain/errors/payloadAttestation.ts +2 -0
  196. package/src/chain/forkChoice/index.ts +27 -4
  197. package/src/chain/interface.ts +1 -2
  198. package/src/chain/opPools/executionPayloadBidPool.ts +10 -9
  199. package/src/chain/options.ts +1 -0
  200. package/src/chain/prepareNextSlot.ts +2 -11
  201. package/src/chain/produceBlock/produceBlockBody.ts +114 -40
  202. package/src/chain/regen/interface.ts +2 -1
  203. package/src/chain/regen/queued.ts +0 -5
  204. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +8 -3
  205. package/src/chain/stateCache/fifoBlockStateCache.ts +0 -6
  206. package/src/chain/stateCache/persistentCheckpointsCache.ts +6 -2
  207. package/src/chain/stateCache/types.ts +0 -2
  208. package/src/chain/validation/block.ts +12 -16
  209. package/src/chain/validation/executionPayloadBid.ts +90 -19
  210. package/src/chain/validation/executionPayloadEnvelope.ts +1 -3
  211. package/src/chain/validation/payloadAttestationMessage.ts +26 -4
  212. package/src/chain/validatorMonitor.ts +18 -0
  213. package/src/execution/builder/index.ts +1 -4
  214. package/src/execution/engine/http.ts +1 -1
  215. package/src/execution/engine/interface.ts +12 -2
  216. package/src/execution/engine/mock.ts +6 -5
  217. package/src/execution/engine/types.ts +75 -14
  218. package/src/metrics/metrics/lodestar.ts +15 -3
  219. package/src/network/interface.ts +1 -0
  220. package/src/network/network.ts +11 -0
  221. package/src/network/processor/gossipHandlers.ts +26 -6
  222. package/src/network/processor/index.ts +27 -27
  223. package/src/network/reqresp/handlers/beaconBlocksByRange.ts +12 -5
  224. package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +17 -3
  225. package/src/network/reqresp/handlers/dataColumnSidecarsByRoot.ts +1 -1
  226. package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +22 -6
  227. package/src/network/reqresp/handlers/executionPayloadEnvelopesByRoot.ts +20 -1
  228. package/src/network/reqresp/handlers/index.ts +4 -4
  229. package/src/network/reqresp/utils/dataColumnResponseValidation.ts +22 -5
  230. package/src/sync/types.ts +11 -2
  231. package/src/sync/unknownBlock.ts +70 -31
  232. package/src/util/dataColumns.ts +17 -12
  233. package/src/util/sszBytes.ts +1 -1
  234. package/lib/execution/builder/utils.d.ts +0 -5
  235. package/lib/execution/builder/utils.d.ts.map +0 -1
  236. package/lib/execution/builder/utils.js +0 -17
  237. package/lib/execution/builder/utils.js.map +0 -1
  238. package/src/execution/builder/utils.ts +0 -19
@@ -11,7 +11,6 @@ import {
11
11
  SLOTS_PER_HISTORICAL_ROOT,
12
12
  isForkPostBellatrix,
13
13
  isForkPostDeneb,
14
- isForkPostElectra,
15
14
  isForkPostFulu,
16
15
  isForkPostGloas,
17
16
  } from "@lodestar/params";
@@ -50,6 +49,7 @@ import {
50
49
  ProduceFullGloas,
51
50
  } from "../../../../chain/produceBlock/index.js";
52
51
  import {validateGossipBlock} from "../../../../chain/validation/block.js";
52
+ import {validateApiExecutionPayloadBid} from "../../../../chain/validation/executionPayloadBid.js";
53
53
  import {validateApiExecutionPayloadEnvelope} from "../../../../chain/validation/executionPayloadEnvelope.js";
54
54
  import {OpSource} from "../../../../chain/validatorMonitor.js";
55
55
  import {
@@ -93,7 +93,7 @@ export function getBeaconBlockApi({
93
93
  ApiModules,
94
94
  "chain" | "config" | "metrics" | "network" | "db"
95
95
  >): ApplicationMethods<routes.beacon.block.Endpoints> {
96
- const publishBlock: ApplicationMethods<routes.beacon.block.Endpoints>["publishBlockV2"] = async (
96
+ const publishBlockV2: ApplicationMethods<routes.beacon.block.Endpoints>["publishBlockV2"] = async (
97
97
  {signedBlockContents, broadcastValidation},
98
98
  _context,
99
99
  opts: PublishBlockOpts = {}
@@ -204,11 +204,19 @@ export function getBeaconBlockApi({
204
204
  try {
205
205
  await validateGossipBlock(config, chain, signedBlock, fork);
206
206
  } catch (error) {
207
- if (error instanceof BlockGossipError && error.type.code === BlockErrorCode.ALREADY_KNOWN) {
208
- chain.logger.debug("Ignoring known block during publishing", valLogMeta);
209
- // Blocks might already be published by another node as part of a fallback setup or DVT cluster
210
- // and can reach our node by gossip before the api. The error can be ignored and should not result in a 500 response.
211
- return;
207
+ if (error instanceof BlockGossipError) {
208
+ switch (error.type.code) {
209
+ case BlockErrorCode.ALREADY_KNOWN:
210
+ // Block has already been seen, e.g. via gossip racing the publish API. Benign.
211
+ chain.logger.debug("Ignoring already-known block during publishing", valLogMeta);
212
+ return;
213
+ case BlockErrorCode.REPEAT_PROPOSAL:
214
+ // The proposer already produced a block for this slot. For a solo setup this is a
215
+ // notable signal (duplicate-proposal attempt). For fallback / DVT setups it is
216
+ // expected on every block where another node published first.
217
+ chain.logger.warn("Ignoring repeat-proposal block during publishing", valLogMeta);
218
+ return;
219
+ }
212
220
  }
213
221
 
214
222
  chain.logger.error("Gossip validations failed while publishing the block", valLogMeta, error as Error);
@@ -397,8 +405,8 @@ export function getBeaconBlockApi({
397
405
  }
398
406
  };
399
407
 
400
- const publishBlindedBlock: ApplicationMethods<routes.beacon.block.Endpoints>["publishBlindedBlock"] = async (
401
- {signedBlindedBlock},
408
+ const publishBlindedBlockV2: ApplicationMethods<routes.beacon.block.Endpoints>["publishBlindedBlockV2"] = async (
409
+ {signedBlindedBlock, broadcastValidation},
402
410
  context,
403
411
  opts: PublishBlockOpts = {}
404
412
  ) => {
@@ -428,7 +436,7 @@ export function getBeaconBlockApi({
428
436
  );
429
437
 
430
438
  chain.logger.info("Publishing assembled block", {slot, blockRoot, source});
431
- return publishBlock({signedBlockContents}, {...context, sszBytes: null}, opts);
439
+ return publishBlockV2({signedBlockContents, broadcastValidation}, {...context, sszBytes: null}, opts);
432
440
  }
433
441
 
434
442
  const source = ProducedBlockSource.builder;
@@ -454,7 +462,11 @@ export function getBeaconBlockApi({
454
462
  //
455
463
  // see: https://github.com/ChainSafe/lodestar/issues/5404
456
464
  chain.logger.info("Publishing assembled block", {slot, blockRoot, source});
457
- return publishBlock({signedBlockContents}, {...context, sszBytes: null}, {...opts, ignoreIfKnown: true});
465
+ return publishBlockV2(
466
+ {signedBlockContents, broadcastValidation},
467
+ {...context, sszBytes: null},
468
+ {...opts, ignoreIfKnown: true}
469
+ );
458
470
  }
459
471
  };
460
472
 
@@ -589,23 +601,6 @@ export function getBeaconBlockApi({
589
601
  };
590
602
  },
591
603
 
592
- async getBlockAttestations({blockId}) {
593
- const {block, executionOptimistic, finalized} = await getBlockResponse(chain, blockId);
594
- const fork = config.getForkName(block.message.slot);
595
-
596
- if (isForkPostElectra(fork)) {
597
- throw new ApiError(
598
- 400,
599
- `Use getBlockAttestationsV2 to retrieve block attestations for post-electra fork=${fork}`
600
- );
601
- }
602
-
603
- return {
604
- data: block.message.body.attestations,
605
- meta: {executionOptimistic, finalized},
606
- };
607
- },
608
-
609
604
  async getBlockAttestationsV2({blockId}) {
610
605
  const {block, executionOptimistic, finalized} = await getBlockResponse(chain, blockId);
611
606
  return {
@@ -653,16 +648,8 @@ export function getBeaconBlockApi({
653
648
  };
654
649
  },
655
650
 
656
- publishBlock,
657
- publishBlindedBlock,
658
-
659
- async publishBlindedBlockV2(args, context, opts) {
660
- await publishBlindedBlock(args, context, opts);
661
- },
662
-
663
- async publishBlockV2(args, context, opts) {
664
- await publishBlock(args, context, opts);
665
- },
651
+ publishBlockV2,
652
+ publishBlindedBlockV2,
666
653
 
667
654
  async publishExecutionPayloadEnvelope({signedExecutionPayloadEnvelope}) {
668
655
  const seenTimestampSec = Date.now() / 1000;
@@ -677,9 +664,20 @@ export function getBeaconBlockApi({
677
664
  }
678
665
 
679
666
  // TODO GLOAS: review checks, do we want to implement `broadcast_validation`?
680
- const block = chain.forkChoice.getBlockHex(blockRootHex, PayloadStatus.EMPTY);
667
+ let block = chain.forkChoice.getBlockHex(blockRootHex, PayloadStatus.EMPTY);
681
668
  if (block === null) {
682
- throw new ApiError(404, `Block not found for beacon block root ${blockRootHex}`);
669
+ // Only wait if the envelope is for the current slot
670
+ if (chain.clock.isCurrentSlotGivenGossipDisparity(slot)) {
671
+ chain.logger.debug("Execution payload envelope received before block, waiting for block to be imported", {
672
+ blockRoot: blockRootHex,
673
+ slot,
674
+ });
675
+ await chain.waitForBlock(slot, blockRootHex);
676
+ block = chain.forkChoice.getBlockHex(blockRootHex, PayloadStatus.EMPTY);
677
+ }
678
+ if (block === null) {
679
+ throw new ApiError(404, `Block not found for beacon block root ${blockRootHex}`);
680
+ }
683
681
  }
684
682
  if (block.slot !== slot) {
685
683
  throw new ApiError(400, `Envelope slot ${slot} does not match block slot ${block.slot}`);
@@ -726,10 +724,11 @@ export function getBeaconBlockApi({
726
724
  await sleep(msToBlockSlot);
727
725
  }
728
726
 
729
- // TODO GLOAS: if block and payload are submitted in parallel, payloadInput may not yet exist.
730
- // A queuing mechanism is needed to handle this case. See https://github.com/ChainSafe/lodestar/issues/8915
731
727
  const payloadInput = chain.seenPayloadEnvelopeInputCache.get(blockRootHex);
732
728
  if (!payloadInput) {
729
+ // The block is awaited above (queuing if the envelope arrived first), and both the API and
730
+ // gossip import paths seed the PayloadEnvelopeInput before importing the block, so the input
731
+ // should exist here.
733
732
  throw new ApiError(404, `PayloadEnvelopeInput not found for block root ${blockRootHex}`);
734
733
  }
735
734
 
@@ -825,6 +824,41 @@ export function getBeaconBlockApi({
825
824
  });
826
825
  },
827
826
 
827
+ async publishExecutionPayloadBid({signedExecutionPayloadBid}) {
828
+ const bid = signedExecutionPayloadBid.message;
829
+ const slot = bid.slot;
830
+ const fork = config.getForkName(slot);
831
+
832
+ if (!isForkPostGloas(fork)) {
833
+ throw new ApiError(400, `publishExecutionPayloadBid not supported for pre-gloas fork=${fork}`);
834
+ }
835
+
836
+ await validateApiExecutionPayloadBid(chain, signedExecutionPayloadBid);
837
+
838
+ try {
839
+ const insertOutcome = chain.executionPayloadBidPool.add(signedExecutionPayloadBid);
840
+ metrics?.opPool.executionPayloadBidPool.apiInsertOutcome.inc({insertOutcome});
841
+ } catch (e) {
842
+ chain.logger.error("Error adding to executionPayloadBid pool", {}, e as Error);
843
+ }
844
+
845
+ const sentPeers = await network.publishSignedExecutionPayloadBid(signedExecutionPayloadBid);
846
+
847
+ chain.emitter.emit(routes.events.EventType.executionPayloadBid, {
848
+ version: fork,
849
+ data: signedExecutionPayloadBid,
850
+ });
851
+
852
+ chain.logger.info("Published execution payload bid", {
853
+ slot,
854
+ builderIndex: bid.builderIndex,
855
+ blockHash: toRootHex(bid.blockHash),
856
+ parentBlockHash: toRootHex(bid.parentBlockHash),
857
+ value: bid.value,
858
+ sentPeers,
859
+ });
860
+ },
861
+
828
862
  async getSignedExecutionPayloadEnvelope({blockId}, context) {
829
863
  const {block, executionOptimistic, finalized} = await getBlockResponse(chain, blockId);
830
864
  const slot = block.message.slot;
@@ -9,7 +9,7 @@ import {
9
9
  isForkPostGloas,
10
10
  } from "@lodestar/params";
11
11
  import {isStatePostAltair} from "@lodestar/state-transition";
12
- import {Attestation, Epoch, SingleAttestation, isElectraAttestation, ssz, sszTypesFor} from "@lodestar/types";
12
+ import {Epoch, SingleAttestation, isElectraAttestation, ssz, sszTypesFor} from "@lodestar/types";
13
13
  import {toRootHex} from "@lodestar/utils";
14
14
  import {
15
15
  AttestationError,
@@ -40,25 +40,6 @@ export function getBeaconPoolApi({
40
40
  network,
41
41
  }: Pick<ApiModules, "chain" | "logger" | "metrics" | "network">): ApplicationMethods<routes.beacon.pool.Endpoints> {
42
42
  return {
43
- async getPoolAttestations({slot, committeeIndex}) {
44
- // Already filtered by slot
45
- let attestations: Attestation[] = chain.aggregatedAttestationPool.getAll(slot);
46
- const fork = chain.config.getForkName(slot ?? chain.clock.currentSlot);
47
-
48
- if (isForkPostElectra(fork)) {
49
- throw new ApiError(
50
- 400,
51
- `Use getPoolAttestationsV2 to retrieve pool attestations for post-electra fork=${fork}`
52
- );
53
- }
54
-
55
- if (committeeIndex !== undefined) {
56
- attestations = attestations.filter((attestation) => committeeIndex === attestation.data.index);
57
- }
58
-
59
- return {data: attestations};
60
- },
61
-
62
43
  async getPoolAttestationsV2({slot, committeeIndex}) {
63
44
  // Already filtered by slot
64
45
  let attestations = chain.aggregatedAttestationPool.getAll(slot);
@@ -134,19 +115,6 @@ export function getBeaconPoolApi({
134
115
  }
135
116
  },
136
117
 
137
- async getPoolAttesterSlashings() {
138
- const fork = chain.config.getForkName(chain.clock.currentSlot);
139
-
140
- if (isForkPostElectra(fork)) {
141
- throw new ApiError(
142
- 400,
143
- `Use getPoolAttesterSlashingsV2 to retrieve pool attester slashings for post-electra fork=${fork}`
144
- );
145
- }
146
-
147
- return {data: chain.opPool.getAllAttesterSlashings()};
148
- },
149
-
150
118
  async getPoolAttesterSlashingsV2() {
151
119
  const fork = chain.config.getForkName(chain.clock.currentSlot);
152
120
  return {data: chain.opPool.getAllAttesterSlashings(), meta: {version: fork}};
@@ -164,10 +132,6 @@ export function getBeaconPoolApi({
164
132
  return {data: chain.opPool.getAllBlsToExecutionChanges().map(({data}) => data)};
165
133
  },
166
134
 
167
- async submitPoolAttestations({signedAttestations}) {
168
- await this.submitPoolAttestationsV2({signedAttestations});
169
- },
170
-
171
135
  async submitPoolAttestationsV2({signedAttestations}) {
172
136
  const fork = chain.config.getForkName(chain.clock.currentSlot);
173
137
  const seenTimestampSec = Date.now() / 1000;
@@ -247,10 +211,6 @@ export function getBeaconPoolApi({
247
211
  }
248
212
  },
249
213
 
250
- async submitPoolAttesterSlashings({attesterSlashing}) {
251
- await this.submitPoolAttesterSlashingsV2({attesterSlashing});
252
- },
253
-
254
214
  async submitPoolAttesterSlashingsV2({attesterSlashing}) {
255
215
  await validateApiAttesterSlashing(chain, attesterSlashing);
256
216
  const fork = chain.config.getForkName(Number(attesterSlashing.attestation1.data.slot));
@@ -328,8 +288,10 @@ export function getBeaconPoolApi({
328
288
 
329
289
  chain.forkChoice.notifyPtcMessages(
330
290
  toRootHex(payloadAttestationMessage.data.beaconBlockRoot),
291
+ payloadAttestationMessage.data.slot,
331
292
  validatorCommitteeIndices,
332
- payloadAttestationMessage.data.payloadPresent
293
+ payloadAttestationMessage.data.payloadPresent,
294
+ payloadAttestationMessage.data.blobDataAvailable
333
295
  );
334
296
 
335
297
  await network.publishPayloadAttestationMessage(payloadAttestationMessage);
@@ -5,6 +5,8 @@ import {
5
5
  BASE_REWARDS_PER_EPOCH,
6
6
  BLOB_TX_TYPE,
7
7
  BLS_WITHDRAWAL_PREFIX,
8
+ BUILDER_DEPOSIT_REQUEST_TYPE,
9
+ BUILDER_EXIT_REQUEST_TYPE,
8
10
  BUILDER_INDEX_FLAG,
9
11
  BUILDER_INDEX_SELF_BUILD,
10
12
  BUILDER_PAYMENT_THRESHOLD_DENOMINATOR,
@@ -21,6 +23,7 @@ import {
21
23
  DOMAIN_BEACON_BUILDER,
22
24
  DOMAIN_BEACON_PROPOSER,
23
25
  DOMAIN_BLS_TO_EXECUTION_CHANGE,
26
+ DOMAIN_BUILDER_DEPOSIT,
24
27
  DOMAIN_CONTRIBUTION_AND_PROOF,
25
28
  DOMAIN_DEPOSIT,
26
29
  DOMAIN_PROPOSER_PREFERENCES,
@@ -38,6 +41,7 @@ import {
38
41
  JUSTIFICATION_BITS_LENGTH,
39
42
  MAX_CONCURRENT_REQUESTS,
40
43
  NODE_ID_BITS,
44
+ PAYLOAD_BUILDER_VERSION,
41
45
  PROPOSER_WEIGHT,
42
46
  SYNC_COMMITTEE_SUBNET_COUNT,
43
47
  SYNC_REWARD_WEIGHT,
@@ -53,6 +57,7 @@ import {
53
57
  VERSIONED_HASH_VERSION_KZG,
54
58
  WEIGHT_DENOMINATOR,
55
59
  WITHDRAWAL_REQUEST_TYPE,
60
+ ZERO_HASH_HEX,
56
61
  } from "@lodestar/params";
57
62
 
58
63
  /**
@@ -69,6 +74,7 @@ export const specConstants = {
69
74
  DEPOSIT_CONTRACT_TREE_DEPTH,
70
75
  JUSTIFICATION_BITS_LENGTH,
71
76
  ENDIANNESS: "little",
77
+ EMPTY_BLOCK_HASH: ZERO_HASH_HEX,
72
78
  // ## Withdrawal prefixes
73
79
  BLS_WITHDRAWAL_PREFIX: toHexByte(BLS_WITHDRAWAL_PREFIX),
74
80
  ETH1_ADDRESS_WITHDRAWAL_PREFIX: toHexByte(ETH1_ADDRESS_WITHDRAWAL_PREFIX),
@@ -138,6 +144,10 @@ export const specConstants = {
138
144
  BUILDER_INDEX_SELF_BUILD,
139
145
  BUILDER_PAYMENT_THRESHOLD_NUMERATOR,
140
146
  BUILDER_PAYMENT_THRESHOLD_DENOMINATOR,
147
+ PAYLOAD_BUILDER_VERSION,
148
+ DOMAIN_BUILDER_DEPOSIT,
149
+ BUILDER_DEPOSIT_REQUEST_TYPE: toHexByte(BUILDER_DEPOSIT_REQUEST_TYPE),
150
+ BUILDER_EXIT_REQUEST_TYPE: toHexByte(BUILDER_EXIT_REQUEST_TYPE),
141
151
  };
142
152
 
143
153
  /** Convert single-byte numbers to hex strings for API spec compliance */
@@ -1,7 +1,8 @@
1
1
  import {routes} from "@lodestar/api";
2
2
  import {ApplicationMethods} from "@lodestar/api/server";
3
- import {ExecutionStatus} from "@lodestar/fork-choice";
3
+ import {ExecutionStatus, PayloadStatus} from "@lodestar/fork-choice";
4
4
  import {ForkPostDeneb, ZERO_HASH_HEX, isForkPostDeneb, isForkPostFulu} from "@lodestar/params";
5
+ import {computeTimeAtSlot} from "@lodestar/state-transition";
5
6
  import {BeaconState, DataColumnSidecar, DataColumnSidecars, type SignedBeaconBlock, sszTypesFor} from "@lodestar/types";
6
7
  import {toRootHex} from "@lodestar/utils";
7
8
  import {getBlobKzgCommitments} from "../../../util/dataColumns.js";
@@ -12,6 +13,29 @@ import {getStateResponseWithRegen} from "../beacon/state/utils.js";
12
13
  import {ApiModules} from "../types.js";
13
14
  import {assertUniqueItems} from "../utils.js";
14
15
 
16
+ function toForkChoiceValidity(status: ExecutionStatus): "valid" | "invalid" | "optimistic" {
17
+ switch (status) {
18
+ case ExecutionStatus.Valid:
19
+ return "valid";
20
+ case ExecutionStatus.Invalid:
21
+ return "invalid";
22
+ case ExecutionStatus.Syncing:
23
+ case ExecutionStatus.PreMerge:
24
+ return "optimistic";
25
+ }
26
+ }
27
+
28
+ function toPayloadStatusName(status: PayloadStatus): "pending" | "empty" | "full" {
29
+ switch (status) {
30
+ case PayloadStatus.PENDING:
31
+ return "pending";
32
+ case PayloadStatus.EMPTY:
33
+ return "empty";
34
+ case PayloadStatus.FULL:
35
+ return "full";
36
+ }
37
+ }
38
+
15
39
  export function getDebugApi({
16
40
  chain,
17
41
  config,
@@ -40,23 +64,60 @@ export function getDebugApi({
40
64
  justifiedEpoch: node.justifiedEpoch,
41
65
  finalizedEpoch: node.finalizedEpoch,
42
66
  weight: node.weight,
43
- validity: (() => {
44
- switch (node.executionStatus) {
45
- case ExecutionStatus.Valid:
46
- return "valid";
47
- case ExecutionStatus.Invalid:
48
- return "invalid";
49
- case ExecutionStatus.Syncing:
50
- case ExecutionStatus.PreMerge:
51
- return "optimistic";
52
- }
53
- })(),
67
+ validity: toForkChoiceValidity(node.executionStatus),
54
68
  executionBlockHash: node.executionPayloadBlockHash ?? ZERO_HASH_HEX,
55
69
  })),
56
70
  },
57
71
  };
58
72
  },
59
73
 
74
+ async getDebugForkChoiceV2() {
75
+ const {forkChoice} = chain;
76
+ return {
77
+ data: {
78
+ justifiedCheckpoint: forkChoice.getJustifiedCheckpoint(),
79
+ finalizedCheckpoint: forkChoice.getFinalizedCheckpoint(),
80
+ forkChoiceNodes: forkChoice.getAllNodes().map((node) => {
81
+ // Payload-specific fields apply only to a revealed Gloas payload = the FULL variant of a
82
+ // Gloas block
83
+ const ptc = node.payloadStatus === PayloadStatus.FULL ? forkChoice.getPTCVoteCounts(node.blockRoot) : null;
84
+ return {
85
+ payloadStatus: toPayloadStatusName(node.payloadStatus),
86
+ slot: node.slot,
87
+ blockRoot: node.blockRoot,
88
+ parentRoot: node.parentRoot,
89
+ weight: node.weight,
90
+ validity: toForkChoiceValidity(node.executionStatus),
91
+ executionBlockHash: node.executionPayloadBlockHash ?? ZERO_HASH_HEX,
92
+ extraData: {
93
+ executionOptimistic: isOptimisticBlock(node),
94
+ timestamp: computeTimeAtSlot(config, node.slot, chain.genesisTime),
95
+ target: node.targetRoot,
96
+ justifiedEpoch: node.justifiedEpoch,
97
+ finalizedEpoch: node.finalizedEpoch,
98
+ unrealizedJustifiedEpoch: node.unrealizedJustifiedEpoch,
99
+ unrealizedFinalizedEpoch: node.unrealizedFinalizedEpoch,
100
+ payloadAttesterCount: ptc?.attesterCount ?? null,
101
+ payloadAvailabilityYesCount: ptc?.payloadPresentCount ?? null,
102
+ payloadDataAvailabilityYesCount: ptc?.dataAvailableCount ?? null,
103
+ gasLimit:
104
+ node.payloadStatus === PayloadStatus.FULL && "executionPayloadGasLimit" in node
105
+ ? node.executionPayloadGasLimit
106
+ : null,
107
+ },
108
+ };
109
+ }),
110
+ extraData: {
111
+ unrealizedJustifiedCheckpoint: forkChoice.getUnrealizedJustifiedCheckpoint(),
112
+ unrealizedFinalizedCheckpoint: forkChoice.getUnrealizedFinalizedCheckpoint(),
113
+ proposerBoostRoot: forkChoice.getProposerBoostRoot(),
114
+ previousProposerBoostRoot: forkChoice.getPreviousProposerBoostRoot(),
115
+ headRoot: forkChoice.getHeadRoot(),
116
+ },
117
+ },
118
+ };
119
+ },
120
+
60
121
  async getProtoArrayNodes() {
61
122
  const nodes = chain.forkChoice.getAllNodes().map((node) => ({
62
123
  // if node has executionPayloadNumber, it will overwrite the below default
@@ -280,6 +280,36 @@ export function getLodestarApi({
280
280
  };
281
281
  },
282
282
 
283
+ async getFastConfirmationInfo() {
284
+ const confirmedRoot = chain.forkChoice.getConfirmedRoot();
285
+ const confirmedBlock = chain.forkChoice.getConfirmedBlock();
286
+ const justifiedCheckpoint = chain.forkChoice.getJustifiedCheckpoint();
287
+ const finalizedCheckpoint = chain.forkChoice.getFinalizedCheckpoint();
288
+ const headRoot = chain.forkChoice.getHeadRoot();
289
+ const head = chain.forkChoice.getHead();
290
+
291
+ return {
292
+ data: {
293
+ confirmed: {
294
+ rootHex: confirmedRoot,
295
+ slot: confirmedBlock?.slot ?? null,
296
+ },
297
+ head: {
298
+ rootHex: headRoot,
299
+ slot: head.slot,
300
+ },
301
+ justifiedCheckpoint: {
302
+ rootHex: justifiedCheckpoint.rootHex,
303
+ epoch: justifiedCheckpoint.epoch,
304
+ },
305
+ finalizedCheckpoint: {
306
+ rootHex: finalizedCheckpoint.rootHex,
307
+ epoch: finalizedCheckpoint.epoch,
308
+ },
309
+ },
310
+ };
311
+ },
312
+
283
313
  async getAttesterSlashingsFromBlocks({signedBlocks}) {
284
314
  const attestations = new Map<Epoch, Attestation[]>();
285
315