@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
@@ -914,20 +914,38 @@ export function getValidatorApi(
914
914
  notWhileSyncing();
915
915
  await waitForSlot(slot);
916
916
 
917
- // TODO GLOAS: support producing blocks from builder bids
918
- const source = ProducedBlockSource.engine;
919
-
920
- // TODO GLOAS: needs to be updated after fork choice changes are merged
921
917
  const parentBlock = chain.getProposerHead(slot);
922
918
  const {blockRoot: parentBlockRootHex, slot: parentSlot} = parentBlock;
923
919
  const parentBlockRoot = fromHex(parentBlockRootHex);
924
920
  notOnOutOfRangeData(parentBlockRoot);
925
921
  metrics?.blockProductionSlotDelta.set(slot - parentSlot);
926
- metrics?.blockProductionRequests.inc({source});
927
922
 
928
923
  const graffitiBytes = toGraffitiBytes(
929
924
  graffiti ?? getDefaultGraffiti(getLodestarClientVersion(opts), chain.executionEngine.clientVersion, opts)
930
925
  );
926
+
927
+ // TODO GLOAS: respect builderSelection (MaxProfit, BuilderAlways, ExecutionAlways, etc.) to let
928
+ // the user control bid source preferences and value comparison. Also add external builder api
929
+ // support when it is implemented.
930
+ const isBuildingOnFull = chain.forkChoice.shouldBuildOnFull(parentBlock, slot);
931
+ const bidParentBlockHash = isBuildingOnFull ? parentBlock.executionPayloadBlockHash : parentBlock.parentBlockHash;
932
+ const builderBid = chain.executionPayloadBidPool.getBestBid(slot, bidParentBlockHash, parentBlockRootHex);
933
+
934
+ const logCtx = {
935
+ slot,
936
+ parentSlot,
937
+ parentBlockRoot: parentBlockRootHex,
938
+ parentBlockHash: parentBlock.executionPayloadBlockHash,
939
+ fork,
940
+ ...(builderBid !== null
941
+ ? {
942
+ bidValue: builderBid.message.value,
943
+ builderIndex: builderBid.message.builderIndex,
944
+ bidBlockHash: toRootHex(builderBid.message.blockHash),
945
+ }
946
+ : {}),
947
+ };
948
+
931
949
  const commonBlockBodyPromise = chain.produceCommonBlockBody({
932
950
  slot,
933
951
  parentBlock,
@@ -935,44 +953,76 @@ export function getValidatorApi(
935
953
  graffiti: graffitiBytes,
936
954
  });
937
955
 
938
- let timer: undefined | ((opts: {source: ProducedBlockSource}) => number);
939
- try {
940
- timer = metrics?.blockProductionTime.startTimer();
941
- const {block, executionPayloadValue, consensusBlockValue} = await chain.produceBlock({
942
- slot,
943
- parentBlock,
944
- randaoReveal,
945
- graffiti: graffitiBytes,
946
- feeRecipient,
947
- commonBlockBodyPromise,
948
- });
956
+ const baseAttrs = {
957
+ slot,
958
+ parentBlock,
959
+ randaoReveal,
960
+ graffiti: graffitiBytes,
961
+ feeRecipient,
962
+ commonBlockBodyPromise,
963
+ };
949
964
 
950
- metrics?.blockProductionSuccess.inc({source});
951
- metrics?.blockProductionNumAggregated.observe({source}, block.body.attestations.length);
952
- metrics?.blockProductionConsensusBlockValue.observe({source}, Number(formatWeiToEth(consensusBlockValue)));
953
- metrics?.blockProductionExecutionPayloadValue.observe({source}, Number(formatWeiToEth(executionPayloadValue)));
965
+ metrics?.blockProductionRequests.inc({source: ProducedBlockSource.engine});
966
+ if (builderBid !== null) {
967
+ metrics?.blockProductionRequests.inc({source: ProducedBlockSource.builder});
968
+ }
954
969
 
955
- const blockRoot = toRootHex(config.getForkTypes(slot).BeaconBlock.hashTreeRoot(block));
956
- logger.verbose("Produced block", {
957
- slot,
958
- executionPayloadValue,
959
- consensusBlockValue,
960
- root: blockRoot,
961
- });
962
- if (chain.opts.persistProducedBlocks) {
963
- void chain.persistBlock(block, "produced_engine_block");
970
+ const timed = <T>(source: ProducedBlockSource, fn: () => Promise<T>): Promise<T> => {
971
+ const t = metrics?.blockProductionTime.startTimer();
972
+ return fn().finally(() => t?.({source}));
973
+ };
974
+
975
+ // Always build local block. If builder bid available, also build with it in parallel and prefer it.
976
+ const [engineResult, bidResult] = await Promise.allSettled([
977
+ timed(ProducedBlockSource.engine, () => chain.produceBlock(baseAttrs)),
978
+ builderBid !== null
979
+ ? timed(ProducedBlockSource.builder, () => chain.produceBlock({...baseAttrs, builderBid}))
980
+ : Promise.reject(),
981
+ ]);
982
+
983
+ let bestResult: typeof engineResult | null = null;
984
+ let source: ProducedBlockSource = ProducedBlockSource.engine;
985
+ if (builderBid !== null && bidResult.status === "fulfilled") {
986
+ source = ProducedBlockSource.builder;
987
+ bestResult = bidResult;
988
+ logger.info("Selected builder bid block", logCtx);
989
+ } else if (engineResult.status === "fulfilled") {
990
+ source = ProducedBlockSource.engine;
991
+ bestResult = engineResult;
992
+ if (builderBid !== null) {
993
+ logger.warn("Builder bid block production failed, using local block", logCtx);
964
994
  }
995
+ }
965
996
 
966
- return {
967
- data: block as gloas.BeaconBlock,
968
- meta: {
969
- version: fork,
970
- consensusBlockValue,
971
- },
972
- };
973
- } finally {
974
- timer?.({source});
997
+ if (bestResult === null || bestResult.status !== "fulfilled") {
998
+ const engineReason = engineResult.status === "rejected" ? engineResult.reason : undefined;
999
+ const bidReason = builderBid !== null && bidResult.status === "rejected" ? bidResult.reason : undefined;
1000
+ logger.error("Block production failed", {...logCtx, engineReason, bidReason});
1001
+ throw Error(`Block production failed: engine=${engineReason ?? "n/a"} builder=${bidReason ?? "n/a"}`);
1002
+ }
1003
+
1004
+ const {block, executionPayloadValue, consensusBlockValue} = bestResult.value;
1005
+
1006
+ metrics?.blockProductionSuccess.inc({source});
1007
+ metrics?.blockProductionNumAggregated.observe({source}, block.body.attestations.length);
1008
+ metrics?.blockProductionConsensusBlockValue.observe({source}, Number(formatWeiToEth(consensusBlockValue)));
1009
+ metrics?.blockProductionExecutionPayloadValue.observe({source}, Number(formatWeiToEth(executionPayloadValue)));
1010
+
1011
+ const blockRoot = toRootHex(config.getForkTypes(slot).BeaconBlock.hashTreeRoot(block));
1012
+ logger.verbose("Produced block", {
1013
+ ...logCtx,
1014
+ executionPayloadValue,
1015
+ consensusBlockValue,
1016
+ root: blockRoot,
1017
+ });
1018
+ if (chain.opts.persistProducedBlocks) {
1019
+ void chain.persistBlock(block, "produced_engine_block");
975
1020
  }
1021
+
1022
+ return {
1023
+ data: block as gloas.BeaconBlock,
1024
+ meta: {version: fork, consensusBlockValue},
1025
+ };
976
1026
  },
977
1027
 
978
1028
  async produceAttestationData({committeeIndex, slot}) {
@@ -1060,23 +1110,34 @@ export function getValidatorApi(
1060
1110
  notWhileSyncing();
1061
1111
  await waitForSlot(slot);
1062
1112
 
1063
- const block = chain.forkChoice.getCanonicalBlockClosestLteSlot(slot);
1113
+ const block = chain.forkChoice.getCanonicalBlockAtSlot(slot);
1064
1114
  if (!block) {
1065
- throw new ApiError(404, `No canonical block found at or before slot=${slot}`);
1115
+ // No block is seen at slot. Return 404 so vc can skip casting payload attestation.
1116
+ throw new ApiError(404, `No canonical block found at slot=${slot}`);
1066
1117
  }
1067
1118
 
1068
- const blockIsForSlot = block.slot === slot;
1069
1119
  const payloadInput = chain.seenPayloadEnvelopeInputCache.get(block.blockRoot);
1070
1120
  // Spec: set payload_present only if the envelope was seen before get_payload_due_ms()
1071
1121
  // into the slot. Use the envelope's own arrival time (getPayloadEnvelopeSource), not
1072
1122
  // the input's creation time.
1073
1123
  const payloadDueSec = config.getPayloadDueMs() / 1000;
1074
- const payloadPresent =
1075
- blockIsForSlot &&
1076
- payloadInput !== undefined &&
1077
- payloadInput.hasPayloadEnvelope() &&
1078
- chain.clock.secFromSlot(slot, payloadInput.getPayloadEnvelopeSource().seenTimestampSec) < payloadDueSec;
1079
- const blobDataAvailable = blockIsForSlot && (payloadInput?.hasAllData() ?? false);
1124
+ const payloadSeenSec =
1125
+ payloadInput?.hasPayloadEnvelope() === true
1126
+ ? chain.clock.secFromSlot(slot, payloadInput.getPayloadEnvelopeSource().seenTimestampSec)
1127
+ : null;
1128
+ const payloadPresent = payloadSeenSec !== null && payloadSeenSec < payloadDueSec;
1129
+ const blobDataAvailable = payloadInput?.hasAllData() === true;
1130
+
1131
+ logger.debug("Produced payload attestation data", {
1132
+ slot,
1133
+ blockRoot: block.blockRoot,
1134
+ blockSlot: block.slot,
1135
+ payloadPresent,
1136
+ blobDataAvailable,
1137
+ hasPayloadInput: payloadInput !== undefined,
1138
+ payloadSeenSec,
1139
+ payloadDueSec,
1140
+ });
1080
1141
 
1081
1142
  return {
1082
1143
  data: {
@@ -1146,7 +1207,10 @@ export function getValidatorApi(
1146
1207
  const isPostFulu = isForkPostFulu(config.getForkName(startSlot));
1147
1208
  const maxFutureEpoch = isPostFulu && nearNextEpoch && opts?.v2 ? nextEpoch + 1 : nextEpoch;
1148
1209
  if (currentEpoch >= 0 && epoch > maxFutureEpoch) {
1149
- throw new ApiError(400, `Requested epoch ${epoch} must not be more than one epoch in the future`);
1210
+ throw new ApiError(
1211
+ 400,
1212
+ `Requested epoch ${epoch} must not be more than ${maxFutureEpoch}, currentEpoch=${currentEpoch}, v2=${opts?.v2 ?? false}`
1213
+ );
1150
1214
  }
1151
1215
 
1152
1216
  const head = chain.forkChoice.getHead();
@@ -1230,17 +1294,35 @@ export function getValidatorApi(
1230
1294
  duties.push({slot: startSlot + i, validatorIndex: indexes[i], pubkey: pubkeys[i]});
1231
1295
  }
1232
1296
 
1233
- // Returns `null` on the one-off scenario where the genesis block decides its own shuffling.
1234
- // It should be set to the latest block applied to `self` or the genesis block root.
1235
- const dependentRoot =
1236
- // In v2 the dependent root is different after fulu due to deterministic proposer lookahead
1237
- proposerShufflingDecisionRoot(opts?.v2 ? config.getForkName(startSlot) : ForkName.phase0, state, epoch) ||
1238
- (await getGenesisBlockRoot(state));
1297
+ // In v2 the dependent root is different after fulu due to deterministic proposer lookahead
1298
+ let dependentRoot = proposerShufflingDecisionRoot(
1299
+ opts?.v2 ? config.getForkName(startSlot) : ForkName.phase0,
1300
+ state,
1301
+ epoch
1302
+ );
1303
+ const logCtx = {
1304
+ epoch,
1305
+ stateSlot: state.slot,
1306
+ stateEpoch: state.epoch,
1307
+ v2: opts?.v2 ?? false,
1308
+ };
1309
+ if (dependentRoot === null) {
1310
+ // fallback to get_proposer_duties() v1, also in lodestar v1.43
1311
+ logger.verbose("Proposer duties decision root not in state, falling back to state epoch", logCtx);
1312
+ dependentRoot = proposerShufflingDecisionRoot(ForkName.phase0, state, state.epoch);
1313
+ }
1314
+ if (dependentRoot === null) {
1315
+ logger.verbose("Proposer duties decision root not in state, falling back to genesis block root", logCtx);
1316
+ dependentRoot = await getGenesisBlockRoot(state);
1317
+ }
1318
+
1319
+ const dependentRootHex = toRootHex(dependentRoot);
1320
+ logger.verbose("Computed proposer duties decision root", {...logCtx, dependentRoot: dependentRootHex});
1239
1321
 
1240
1322
  return {
1241
1323
  data: duties,
1242
1324
  meta: {
1243
- dependentRoot: toRootHex(dependentRoot),
1325
+ dependentRoot: dependentRootHex,
1244
1326
  executionOptimistic: isOptimisticBlock(head),
1245
1327
  },
1246
1328
  };
@@ -1419,33 +1501,6 @@ export function getValidatorApi(
1419
1501
  };
1420
1502
  },
1421
1503
 
1422
- async getAggregatedAttestation({attestationDataRoot, slot}) {
1423
- notWhileSyncing();
1424
-
1425
- await waitForSlot(slot); // Must never request for a future slot > currentSlot
1426
-
1427
- const dataRootHex = toRootHex(attestationDataRoot);
1428
- const aggregate = chain.attestationPool.getAggregate(slot, dataRootHex, null);
1429
- const fork = chain.config.getForkName(slot);
1430
-
1431
- if (isForkPostElectra(fork)) {
1432
- throw new ApiError(
1433
- 400,
1434
- `Use getAggregatedAttestationV2 to retrieve aggregated attestations for post-electra fork=${fork}`
1435
- );
1436
- }
1437
-
1438
- if (!aggregate) {
1439
- throw new ApiError(404, `No aggregated attestation for slot=${slot}, dataRoot=${dataRootHex}`);
1440
- }
1441
-
1442
- metrics?.production.producedAggregateParticipants.observe(aggregate.aggregationBits.getTrueBitIndexes().length);
1443
-
1444
- return {
1445
- data: aggregate,
1446
- };
1447
- },
1448
-
1449
1504
  async getAggregatedAttestationV2({attestationDataRoot, slot, committeeIndex}) {
1450
1505
  notWhileSyncing();
1451
1506
 
@@ -1469,10 +1524,6 @@ export function getValidatorApi(
1469
1524
  };
1470
1525
  },
1471
1526
 
1472
- async publishAggregateAndProofs({signedAggregateAndProofs}) {
1473
- await this.publishAggregateAndProofsV2({signedAggregateAndProofs});
1474
- },
1475
-
1476
1527
  async publishAggregateAndProofsV2({signedAggregateAndProofs}) {
1477
1528
  notWhileSyncing();
1478
1529
 
@@ -30,7 +30,6 @@ export enum ArchiveStoreTask {
30
30
  PruneHistory = "prune_history",
31
31
  OnFinalizedCheckpoint = "on_finalized_checkpoint",
32
32
  MaybeArchiveState = "maybe_archive_state",
33
- RegenPruneOnFinalized = "regen_prune_on_finalized",
34
33
  ForkchoicePrune = "forkchoice_prune",
35
34
  UpdateBackfillRange = "update_backfill_range",
36
35
  }
@@ -229,10 +228,6 @@ export class ArchiveStore {
229
228
  await this.statesArchiverStrategy.maybeArchiveState(finalized, this.metrics);
230
229
  timer?.({source: ArchiveStoreTask.MaybeArchiveState});
231
230
 
232
- timer = this.metrics?.processFinalizedCheckpoint.durationByTask.startTimer();
233
- this.chain.regen.pruneOnFinalized(finalizedEpoch);
234
- timer?.({source: ArchiveStoreTask.RegenPruneOnFinalized});
235
-
236
231
  // tasks rely on extended fork choice
237
232
  timer = this.metrics?.processFinalizedCheckpoint.durationByTask.startTimer();
238
233
  const prunedBlocks = this.chain.forkChoice.prune(finalized.rootHex);
@@ -22,7 +22,7 @@ import {
22
22
  } from "@lodestar/state-transition";
23
23
  import {Attestation, BeaconBlock, altair, capella, electra, isGloasBeaconBlock, phase0, ssz} from "@lodestar/types";
24
24
  import {isErrorAborted, toRootHex} from "@lodestar/utils";
25
- import {ZERO_HASH_HEX} from "../../constants/index.js";
25
+ import {GENESIS_SLOT, ZERO_HASH_HEX} from "../../constants/index.js";
26
26
  import {callInNextEventLoop} from "../../util/eventLoop.js";
27
27
  import {isOptimisticBlock} from "../../util/forkChoice.js";
28
28
  import {isQueueErrorAborted} from "../../util/queue/index.js";
@@ -116,13 +116,19 @@ export async function importBlock(
116
116
  }
117
117
  executionStatus = parentBlock.executionStatus;
118
118
  }
119
+
120
+ // getBeaconProposerOrNull will return null if head state is more than one epoch away
121
+ // from block slot. We skip proposer boost canonical check as we cannot determine the canonical proposer
122
+ const expectedProposerIndex: number | null = this.getHeadState().getBeaconProposerOrNull(blockSlot);
123
+
119
124
  const blockSummary = this.forkChoice.onBlock(
120
125
  block.message,
121
126
  postState,
122
127
  blockDelaySec,
123
128
  currentSlot,
124
129
  executionStatus,
125
- dataAvailabilityStatus
130
+ dataAvailabilityStatus,
131
+ expectedProposerIndex
126
132
  );
127
133
 
128
134
  // This adds the state necessary to process the next block
@@ -183,10 +189,12 @@ export async function importBlock(
183
189
  this.seenBlockAttesters.addIndices(blockEpoch, indexedAttestation.attestingIndices);
184
190
 
185
191
  const correctHead = ssz.Root.equals(rootCache.getBlockRootAtSlot(attestation.data.slot), beaconBlockRoot);
186
- const missedSlotVote = ssz.Root.equals(
187
- rootCache.getBlockRootAtSlot(attestation.data.slot - 1),
188
- rootCache.getBlockRootAtSlot(attestation.data.slot)
189
- );
192
+ const missedSlotVote =
193
+ attestation.data.slot > GENESIS_SLOT &&
194
+ ssz.Root.equals(
195
+ rootCache.getBlockRootAtSlot(attestation.data.slot - 1),
196
+ rootCache.getBlockRootAtSlot(attestation.data.slot)
197
+ );
190
198
  this.validatorMonitor?.registerAttestationInBlock(
191
199
  indexedAttestation,
192
200
  parentBlockSlot,
@@ -257,8 +265,10 @@ export async function importBlock(
257
265
  if (ptcIndices.length > 0) {
258
266
  this.forkChoice.notifyPtcMessages(
259
267
  toRootHex(payloadAttestation.data.beaconBlockRoot),
268
+ payloadAttestation.data.slot,
260
269
  ptcIndices,
261
- payloadAttestation.data.payloadPresent
270
+ payloadAttestation.data.payloadPresent,
271
+ payloadAttestation.data.blobDataAvailable
262
272
  );
263
273
  }
264
274
  } catch (e) {
@@ -273,6 +283,18 @@ export async function importBlock(
273
283
  const newHead = this.recomputeForkChoiceHead(ForkchoiceCaller.importBlock);
274
284
  const currFinalizedEpoch = this.forkChoice.getFinalizedCheckpoint().epoch;
275
285
 
286
+ // Prune the gloas payload-envelope cache below the new head's parent so it stays bounded during
287
+ // syncing. On a synced node, cache holds just 2 entries — head (parent for
288
+ // next-slot production) and head.parent (proposer-boost-reorg fallback)
289
+ if (fork >= ForkSeq.gloas) {
290
+ callInNextEventLoop(() => {
291
+ const newHeadParent = this.forkChoice.getBlockHexDefaultStatus(newHead.parentRoot);
292
+ if (newHeadParent) {
293
+ this.seenPayloadEnvelopeInputCache.pruneBelowParent(newHeadParent);
294
+ }
295
+ });
296
+ }
297
+
276
298
  if (newHead.blockRoot !== oldHead.blockRoot) {
277
299
  // Set head state as strong reference
278
300
  this.regen.updateHeadState(newHead, postState);
@@ -129,7 +129,7 @@ export async function importExecutionPayload(
129
129
 
130
130
  // 3. Regenerate state for envelope verification
131
131
  const blockState = await this.regen
132
- .getBlockSlotState(protoBlock, protoBlock.slot, {dontTransferCache: true}, RegenCaller.processBlock)
132
+ .getBlockSlotState(protoBlock, protoBlock.slot, {dontTransferCache: true}, RegenCaller.importExecutionPayload)
133
133
  .catch(() =>
134
134
  // only happen at the 1st batch of skipped slot checkpoint sync
135
135
  this.regen.getClosestHeadState(protoBlock)
@@ -237,6 +237,7 @@ export async function importExecutionPayload(
237
237
  blockRootHex,
238
238
  blockHashHex,
239
239
  envelope.payload.blockNumber,
240
+ envelope.payload.gasLimit,
240
241
  execStatus,
241
242
  dataAvailabilityStatus
242
243
  );
@@ -254,7 +255,11 @@ export async function importExecutionPayload(
254
255
  }
255
256
 
256
257
  // 8. Record metrics for payload envelope and column sources
257
- this.metrics?.importPayload.bySource.inc({source: payloadInput.getPayloadEnvelopeSource().source});
258
+ const delaySec = this.clock.secFromSlot(slot);
259
+ this.metrics?.importPayload.elapsedTimeTillImported.observe(
260
+ {source: payloadInput.getPayloadEnvelopeSource().source},
261
+ delaySec
262
+ );
258
263
  for (const {source} of payloadInput.getSampledColumnsWithSource()) {
259
264
  this.metrics?.importPayload.columnsBySource.inc({source});
260
265
  }
@@ -275,6 +280,7 @@ export async function importExecutionPayload(
275
280
  builderIndex: envelope.builderIndex,
276
281
  blockRoot: blockRootHex,
277
282
  blockHash: blockHashHex,
283
+ delaySec,
278
284
  });
279
285
  }
280
286
 
@@ -61,10 +61,8 @@ export function verifyExecutionPayloadEnvelope(
61
61
  `Prev randao mismatch between bid and payload bid=${toHex(bid.prevRandao)} payload=${toHex(payload.prevRandao)}`
62
62
  );
63
63
  }
64
- if (Number(bid.gasLimit) !== payload.gasLimit) {
65
- throw new Error(
66
- `Gas limit mismatch between payload and bid payload=${payload.gasLimit} bid=${Number(bid.gasLimit)}`
67
- );
64
+ if (bid.gasLimit !== payload.gasLimit) {
65
+ throw new Error(`Gas limit mismatch between payload and bid payload=${payload.gasLimit} bid=${bid.gasLimit}`);
68
66
  }
69
67
  if (!byteArrayEquals(bid.blockHash, payload.blockHash)) {
70
68
  throw new Error(
@@ -74,7 +72,7 @@ export function verifyExecutionPayloadEnvelope(
74
72
  // Verify execution_requests_root matches bid commitment.
75
73
  // Can be skipped if already verified during gossip validation.
76
74
  if (verifyExecutionRequestsRoot) {
77
- const requestsRoot = ssz.electra.ExecutionRequests.hashTreeRoot(envelope.executionRequests);
75
+ const requestsRoot = ssz.gloas.ExecutionRequests.hashTreeRoot(envelope.executionRequests);
78
76
  if (!byteArrayEquals(requestsRoot, bid.executionRequestsRoot)) {
79
77
  throw new Error(
80
78
  `Execution requests root mismatch envelope=${toRootHex(requestsRoot)} bid=${toRootHex(bid.executionRequestsRoot)}`
@@ -2,7 +2,7 @@ import path from "node:path";
2
2
  import {PrivateKey} from "@libp2p/interface";
3
3
  import {Type} from "@chainsafe/ssz";
4
4
  import {BeaconConfig} from "@lodestar/config";
5
- import {CheckpointWithHex, IForkChoice, ProtoBlock, UpdateHeadOpt} from "@lodestar/fork-choice";
5
+ import {CheckpointWithHex, ForkChoiceStateGetter, IForkChoice, ProtoBlock, UpdateHeadOpt} from "@lodestar/fork-choice";
6
6
  import {LoggerNode} from "@lodestar/logger/node";
7
7
  import {
8
8
  EFFECTIVE_BALANCE_INCREMENT,
@@ -40,7 +40,6 @@ import {
40
40
  ValidatorIndex,
41
41
  Wei,
42
42
  deneb,
43
- electra,
44
43
  gloas,
45
44
  isBlindedBeaconBlock,
46
45
  phase0,
@@ -382,6 +381,14 @@ export class BeaconChain implements IBeaconChain {
382
381
  blockStateCache.setHeadState(anchorState);
383
382
  checkpointStateCache.add(checkpoint, anchorState);
384
383
 
384
+ const forkChoiceStateGetter: ForkChoiceStateGetter = ({stateRoot, checkpoint}) => {
385
+ if (stateRoot) return blockStateCache.get(stateRoot);
386
+
387
+ if (checkpoint) return checkpointStateCache.get({epoch: checkpoint.epoch, rootHex: checkpoint.rootHex});
388
+
389
+ return null;
390
+ };
391
+
385
392
  const forkChoice = initializeForkChoice(
386
393
  config,
387
394
  emitter,
@@ -390,6 +397,7 @@ export class BeaconChain implements IBeaconChain {
390
397
  isAnchorStateFinalized,
391
398
  opts,
392
399
  this.justifiedBalancesGetter.bind(this),
400
+ forkChoiceStateGetter,
393
401
  metrics,
394
402
  logger
395
403
  );
@@ -916,10 +924,10 @@ export class BeaconChain implements IBeaconChain {
916
924
  async getParentExecutionRequests(
917
925
  parentBlockSlot: Slot,
918
926
  parentBlockRootHex: RootHex
919
- ): Promise<electra.ExecutionRequests> {
927
+ ): Promise<gloas.ExecutionRequests> {
920
928
  // at the fork boundary, parent is pre-gloas
921
929
  if (!isForkPostGloas(this.config.getForkName(parentBlockSlot))) {
922
- return ssz.electra.ExecutionRequests.defaultValue();
930
+ return ssz.gloas.ExecutionRequests.defaultValue();
923
931
  }
924
932
  const envelope = await this.getExecutionPayloadEnvelope(parentBlockSlot, parentBlockRootHex);
925
933
  if (envelope === null) {
@@ -1049,6 +1057,7 @@ export class BeaconChain implements IBeaconChain {
1049
1057
  feeRecipient,
1050
1058
  commonBlockBodyPromise,
1051
1059
  parentBlock,
1060
+ builderBid,
1052
1061
  }: BlockAttributes & {commonBlockBodyPromise: Promise<CommonBlockBody>}
1053
1062
  ): Promise<{
1054
1063
  block: AssembledBlockType<T>;
@@ -1078,6 +1087,7 @@ export class BeaconChain implements IBeaconChain {
1078
1087
  proposerIndex,
1079
1088
  proposerPubKey,
1080
1089
  commonBlockBodyPromise,
1090
+ builderBid,
1081
1091
  }
1082
1092
  );
1083
1093
 
@@ -3,7 +3,7 @@ import {StrictEventEmitter} from "strict-event-emitter-types";
3
3
  import {routes} from "@lodestar/api";
4
4
  import {CheckpointWithHex} from "@lodestar/fork-choice";
5
5
  import {IBeaconStateView} from "@lodestar/state-transition";
6
- import {DataColumnSidecar, RootHex, deneb, phase0} from "@lodestar/types";
6
+ import {DataColumnSidecar, RootHex, Slot, deneb, phase0} from "@lodestar/types";
7
7
  import {PeerIdStr} from "../util/peerId.js";
8
8
  import {BlockInputSource, IBlockInput} from "./blocks/blockInput/types.js";
9
9
  import {PayloadEnvelopeInput} from "./blocks/payloadEnvelopeInput/payloadEnvelopeInput.js";
@@ -94,7 +94,8 @@ export type ChainEventData = {
94
94
  peer: PeerIdStr;
95
95
  source: BlockInputSource;
96
96
  };
97
- [ChainEvent.unknownEnvelopeBlockRoot]: {rootHex: RootHex; peer?: PeerIdStr; source: BlockInputSource};
97
+ // slot is the message slot, not necessarily the envelope's slot, but useful as a logging/prune hint
98
+ [ChainEvent.unknownEnvelopeBlockRoot]: {rootHex: RootHex; slot: Slot; peer?: PeerIdStr; source: BlockInputSource};
98
99
  };
99
100
 
100
101
  export type IChainEvents = ApiEvents & {
@@ -61,9 +61,6 @@ export enum BlockErrorCode {
61
61
  TRANSACTIONS_TOO_BIG = "BLOCK_ERROR_TRANSACTIONS_TOO_BIG",
62
62
  /** Execution engine is unavailable, syncing, or api call errored. Peers must not be downscored on this code */
63
63
  EXECUTION_ENGINE_ERROR = "BLOCK_ERROR_EXECUTION_ERROR",
64
- /** The attestation head block is too far behind the attestation slot, causing many skip slots.
65
- This is deemed a DoS risk */
66
- TOO_MANY_SKIPPED_SLOTS = "TOO_MANY_SKIPPED_SLOTS",
67
64
  /** The blobs are unavailable */
68
65
  DATA_UNAVAILABLE = "BLOCK_ERROR_DATA_UNAVAILABLE",
69
66
  /** Block contains too many kzg commitments */
@@ -89,7 +86,6 @@ export type BlockErrorType =
89
86
  | {code: BlockErrorCode.FUTURE_SLOT; blockSlot: Slot; currentSlot: Slot}
90
87
  | {code: BlockErrorCode.STATE_ROOT_MISMATCH}
91
88
  | {code: BlockErrorCode.GENESIS_BLOCK}
92
- | {code: BlockErrorCode.TOO_MANY_SKIPPED_SLOTS; parentSlot: Slot; blockSlot: Slot}
93
89
  | {code: BlockErrorCode.WOULD_REVERT_FINALIZED_SLOT; blockSlot: Slot; finalizedSlot: Slot}
94
90
  | {code: BlockErrorCode.ALREADY_KNOWN; root: RootHex}
95
91
  | {code: BlockErrorCode.REPEAT_PROPOSAL; proposerIndex: ValidatorIndex}
@@ -3,13 +3,17 @@ import {GossipActionError} from "./gossipValidation.js";
3
3
 
4
4
  export enum ExecutionPayloadBidErrorCode {
5
5
  BUILDER_NOT_ELIGIBLE = "EXECUTION_PAYLOAD_BID_ERROR_BUILDER_NOT_ELIGIBLE",
6
+ INVALID_BUILDER_VERSION = "EXECUTION_PAYLOAD_BID_ERROR_INVALID_BUILDER_VERSION",
6
7
  NON_ZERO_EXECUTION_PAYMENT = "EXECUTION_PAYLOAD_BID_ERROR_NON_ZERO_EXECUTION_PAYMENT",
7
8
  BID_ALREADY_KNOWN = "EXECUTION_PAYLOAD_BID_ERROR_BID_ALREADY_KNOWN",
8
9
  BID_TOO_LOW = "EXECUTION_PAYLOAD_BID_ERROR_BID_TOO_LOW",
9
10
  BID_TOO_HIGH = "EXECUTION_PAYLOAD_BID_ERROR_BID_TOO_HIGH",
10
11
  TOO_MANY_KZG_COMMITMENTS = "EXECUTION_PAYLOAD_BID_ERROR_TOO_MANY_KZG_COMMITMENTS",
11
12
  UNKNOWN_BLOCK_ROOT = "EXECUTION_PAYLOAD_BID_ERROR_UNKNOWN_BLOCK_ROOT",
13
+ UNKNOWN_PARENT_BLOCK_HASH = "EXECUTION_PAYLOAD_BID_ERROR_UNKNOWN_PARENT_BLOCK_HASH",
12
14
  INVALID_SLOT = "EXECUTION_PAYLOAD_BID_ERROR_INVALID_SLOT",
15
+ NOT_LATER_THAN_PARENT = "EXECUTION_PAYLOAD_BID_ERROR_NOT_LATER_THAN_PARENT",
16
+ INVALID_PREV_RANDAO = "EXECUTION_PAYLOAD_BID_ERROR_INVALID_PREV_RANDAO",
13
17
  INVALID_SIGNATURE = "EXECUTION_PAYLOAD_BID_ERROR_INVALID_SIGNATURE",
14
18
  NO_MATCHING_PROPOSER_PREFERENCES = "EXECUTION_PAYLOAD_BID_ERROR_NO_MATCHING_PROPOSER_PREFERENCES",
15
19
  PROPOSER_PREFERENCES_FEE_RECIPIENT_MISMATCH = "EXECUTION_PAYLOAD_BID_ERROR_PROPOSER_PREFERENCES_FEE_RECIPIENT_MISMATCH",
@@ -18,6 +22,12 @@ export enum ExecutionPayloadBidErrorCode {
18
22
 
19
23
  export type ExecutionPayloadBidErrorType =
20
24
  | {code: ExecutionPayloadBidErrorCode.BUILDER_NOT_ELIGIBLE; builderIndex: BuilderIndex}
25
+ | {
26
+ code: ExecutionPayloadBidErrorCode.INVALID_BUILDER_VERSION;
27
+ builderIndex: BuilderIndex;
28
+ version: number;
29
+ expectedVersion: number;
30
+ }
21
31
  | {
22
32
  code: ExecutionPayloadBidErrorCode.NON_ZERO_EXECUTION_PAYMENT;
23
33
  builderIndex: BuilderIndex;
@@ -38,7 +48,15 @@ export type ExecutionPayloadBidErrorType =
38
48
  commitmentLimit: number;
39
49
  }
40
50
  | {code: ExecutionPayloadBidErrorCode.UNKNOWN_BLOCK_ROOT; parentBlockRoot: RootHex}
51
+ | {code: ExecutionPayloadBidErrorCode.UNKNOWN_PARENT_BLOCK_HASH; parentBlockHash: RootHex}
41
52
  | {code: ExecutionPayloadBidErrorCode.INVALID_SLOT; builderIndex: BuilderIndex; slot: Slot}
53
+ | {code: ExecutionPayloadBidErrorCode.NOT_LATER_THAN_PARENT; parentSlot: Slot; slot: Slot}
54
+ | {
55
+ code: ExecutionPayloadBidErrorCode.INVALID_PREV_RANDAO;
56
+ builderIndex: BuilderIndex;
57
+ bidPrevRandao: string;
58
+ expectedPrevRandao: string;
59
+ }
42
60
  | {code: ExecutionPayloadBidErrorCode.INVALID_SIGNATURE; builderIndex: BuilderIndex; slot: Slot}
43
61
  | {
44
62
  code: ExecutionPayloadBidErrorCode.NO_MATCHING_PROPOSER_PREFERENCES;
@@ -56,7 +74,8 @@ export type ExecutionPayloadBidErrorType =
56
74
  code: ExecutionPayloadBidErrorCode.PROPOSER_PREFERENCES_GAS_LIMIT_MISMATCH;
57
75
  builderIndex: BuilderIndex;
58
76
  bidGasLimit: number;
59
- expectedGasLimit: number;
77
+ parentGasLimit: number;
78
+ targetGasLimit: number;
60
79
  };
61
80
 
62
81
  export class ExecutionPayloadBidError extends GossipActionError<ExecutionPayloadBidErrorType> {}
@@ -5,6 +5,7 @@ export enum PayloadAttestationErrorCode {
5
5
  NOT_CURRENT_SLOT = "PAYLOAD_ATTESTATION_ERROR_NOT_CURRENT_SLOT",
6
6
  PAYLOAD_ATTESTATION_ALREADY_KNOWN = "PAYLOAD_ATTESTATION_ERROR_PAYLOAD_ATTESTATION_ALREADY_KNOWN",
7
7
  UNKNOWN_BLOCK_ROOT = "PAYLOAD_ATTESTATION_ERROR_UNKNOWN_BLOCK_ROOT",
8
+ INVALID_BLOCK_SLOT = "PAYLOAD_ATTESTATION_ERROR_INVALID_BLOCK_SLOT",
8
9
  INVALID_BLOCK = "PAYLOAD_ATTESTATION_ERROR_INVALID_BLOCK",
9
10
  INVALID_ATTESTER = "PAYLOAD_ATTESTATION_ERROR_INVALID_ATTESTER",
10
11
  INVALID_SIGNATURE = "PAYLOAD_ATTESTATION_ERROR_INVALID_SIGNATURE",
@@ -18,6 +19,7 @@ export type PayloadAttestationErrorType =
18
19
  blockRoot: RootHex;
19
20
  }
20
21
  | {code: PayloadAttestationErrorCode.UNKNOWN_BLOCK_ROOT; blockRoot: RootHex}
22
+ | {code: PayloadAttestationErrorCode.INVALID_BLOCK_SLOT; blockRoot: RootHex; blockSlot: Slot; slot: Slot}
21
23
  | {code: PayloadAttestationErrorCode.INVALID_BLOCK; blockRoot: RootHex}
22
24
  | {code: PayloadAttestationErrorCode.INVALID_ATTESTER; attesterIndex: ValidatorIndex}
23
25
  | {code: PayloadAttestationErrorCode.INVALID_SIGNATURE};