@lodestar/beacon-node 1.43.0-dev.ca1fc40294 → 1.43.0-dev.d901f86f98

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 (301) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +16 -5
  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 +45 -2
  6. package/lib/api/impl/beacon/pool/index.js.map +1 -1
  7. package/lib/api/impl/debug/index.d.ts.map +1 -1
  8. package/lib/api/impl/debug/index.js +0 -1
  9. package/lib/api/impl/debug/index.js.map +1 -1
  10. package/lib/api/impl/lodestar/index.js +1 -1
  11. package/lib/api/impl/lodestar/index.js.map +1 -1
  12. package/lib/api/impl/validator/index.d.ts.map +1 -1
  13. package/lib/api/impl/validator/index.js +68 -2
  14. package/lib/api/impl/validator/index.js.map +1 -1
  15. package/lib/chain/blocks/blockInput/blockInput.d.ts +3 -0
  16. package/lib/chain/blocks/blockInput/blockInput.d.ts.map +1 -1
  17. package/lib/chain/blocks/blockInput/blockInput.js +4 -1
  18. package/lib/chain/blocks/blockInput/blockInput.js.map +1 -1
  19. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  20. package/lib/chain/blocks/importBlock.js +16 -28
  21. package/lib/chain/blocks/importBlock.js.map +1 -1
  22. package/lib/chain/blocks/importExecutionPayload.d.ts +32 -14
  23. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  24. package/lib/chain/blocks/importExecutionPayload.js +100 -82
  25. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  26. package/lib/chain/blocks/index.d.ts +5 -3
  27. package/lib/chain/blocks/index.d.ts.map +1 -1
  28. package/lib/chain/blocks/index.js +58 -26
  29. package/lib/chain/blocks/index.js.map +1 -1
  30. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +12 -1
  31. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
  32. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +28 -2
  33. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
  34. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +17 -0
  35. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
  36. package/lib/chain/blocks/payloadEnvelopeProcessor.js +2 -2
  37. package/lib/chain/blocks/payloadEnvelopeProcessor.js.map +1 -1
  38. package/lib/chain/blocks/types.d.ts +15 -20
  39. package/lib/chain/blocks/types.d.ts.map +1 -1
  40. package/lib/chain/blocks/utils/chainSegment.d.ts +23 -2
  41. package/lib/chain/blocks/utils/chainSegment.d.ts.map +1 -1
  42. package/lib/chain/blocks/utils/chainSegment.js +89 -12
  43. package/lib/chain/blocks/utils/chainSegment.js.map +1 -1
  44. package/lib/chain/blocks/verifyBlock.d.ts +5 -3
  45. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  46. package/lib/chain/blocks/verifyBlock.js +50 -7
  47. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  48. package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts +0 -4
  49. package/lib/chain/blocks/verifyBlocksExecutionPayloads.d.ts.map +1 -1
  50. package/lib/chain/blocks/verifyBlocksExecutionPayloads.js +5 -2
  51. package/lib/chain/blocks/verifyBlocksExecutionPayloads.js.map +1 -1
  52. package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts +2 -1
  53. package/lib/chain/blocks/verifyBlocksSanityChecks.d.ts.map +1 -1
  54. package/lib/chain/blocks/verifyBlocksSanityChecks.js +25 -5
  55. package/lib/chain/blocks/verifyBlocksSanityChecks.js.map +1 -1
  56. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts +24 -0
  57. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -0
  58. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +80 -0
  59. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -0
  60. package/lib/chain/blocks/verifyPayloadsDataAvailability.d.ts.map +1 -1
  61. package/lib/chain/blocks/verifyPayloadsDataAvailability.js +8 -3
  62. package/lib/chain/blocks/verifyPayloadsDataAvailability.js.map +1 -1
  63. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.d.ts +1 -1
  64. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.d.ts.map +1 -1
  65. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js +2 -11
  66. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js.map +1 -1
  67. package/lib/chain/chain.d.ts +5 -3
  68. package/lib/chain/chain.d.ts.map +1 -1
  69. package/lib/chain/chain.js +42 -12
  70. package/lib/chain/chain.js.map +1 -1
  71. package/lib/chain/emitter.d.ts +0 -11
  72. package/lib/chain/emitter.d.ts.map +1 -1
  73. package/lib/chain/emitter.js +0 -4
  74. package/lib/chain/emitter.js.map +1 -1
  75. package/lib/chain/errors/blockError.d.ts +8 -1
  76. package/lib/chain/errors/blockError.d.ts.map +1 -1
  77. package/lib/chain/errors/blockError.js +2 -0
  78. package/lib/chain/errors/blockError.js.map +1 -1
  79. package/lib/chain/errors/executionPayloadBid.d.ts +5 -0
  80. package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
  81. package/lib/chain/errors/executionPayloadBid.js +1 -0
  82. package/lib/chain/errors/executionPayloadBid.js.map +1 -1
  83. package/lib/chain/errors/executionPayloadEnvelope.d.ts +5 -0
  84. package/lib/chain/errors/executionPayloadEnvelope.d.ts.map +1 -1
  85. package/lib/chain/errors/executionPayloadEnvelope.js +1 -0
  86. package/lib/chain/errors/executionPayloadEnvelope.js.map +1 -1
  87. package/lib/chain/errors/index.d.ts +1 -0
  88. package/lib/chain/errors/index.d.ts.map +1 -1
  89. package/lib/chain/errors/index.js +1 -0
  90. package/lib/chain/errors/index.js.map +1 -1
  91. package/lib/chain/errors/proposerPreferences.d.ts +40 -0
  92. package/lib/chain/errors/proposerPreferences.d.ts.map +1 -0
  93. package/lib/chain/errors/proposerPreferences.js +14 -0
  94. package/lib/chain/errors/proposerPreferences.js.map +1 -0
  95. package/lib/chain/forkChoice/index.js +2 -2
  96. package/lib/chain/forkChoice/index.js.map +1 -1
  97. package/lib/chain/initState.d.ts.map +1 -1
  98. package/lib/chain/initState.js +6 -1
  99. package/lib/chain/initState.js.map +1 -1
  100. package/lib/chain/interface.d.ts +5 -3
  101. package/lib/chain/interface.d.ts.map +1 -1
  102. package/lib/chain/interface.js.map +1 -1
  103. package/lib/chain/opPools/payloadAttestationPool.d.ts +3 -2
  104. package/lib/chain/opPools/payloadAttestationPool.d.ts.map +1 -1
  105. package/lib/chain/opPools/payloadAttestationPool.js +26 -4
  106. package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
  107. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  108. package/lib/chain/prepareNextSlot.js +31 -13
  109. package/lib/chain/prepareNextSlot.js.map +1 -1
  110. package/lib/chain/produceBlock/produceBlockBody.d.ts +11 -1
  111. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  112. package/lib/chain/produceBlock/produceBlockBody.js +47 -14
  113. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  114. package/lib/chain/regen/interface.d.ts +1 -0
  115. package/lib/chain/regen/interface.d.ts.map +1 -1
  116. package/lib/chain/regen/interface.js +1 -0
  117. package/lib/chain/regen/interface.js.map +1 -1
  118. package/lib/chain/regen/queued.d.ts.map +1 -1
  119. package/lib/chain/regen/queued.js +1 -4
  120. package/lib/chain/regen/queued.js.map +1 -1
  121. package/lib/chain/regen/regen.d.ts.map +1 -1
  122. package/lib/chain/regen/regen.js +1 -4
  123. package/lib/chain/regen/regen.js.map +1 -1
  124. package/lib/chain/seenCache/index.d.ts +1 -0
  125. package/lib/chain/seenCache/index.d.ts.map +1 -1
  126. package/lib/chain/seenCache/index.js +1 -0
  127. package/lib/chain/seenCache/index.js.map +1 -1
  128. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +24 -7
  129. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  130. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +69 -17
  131. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  132. package/lib/chain/seenCache/seenProposerPreferences.d.ts +16 -0
  133. package/lib/chain/seenCache/seenProposerPreferences.d.ts.map +1 -0
  134. package/lib/chain/seenCache/seenProposerPreferences.js +26 -0
  135. package/lib/chain/seenCache/seenProposerPreferences.js.map +1 -0
  136. package/lib/chain/validation/block.d.ts.map +1 -1
  137. package/lib/chain/validation/block.js +1 -0
  138. package/lib/chain/validation/block.js.map +1 -1
  139. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  140. package/lib/chain/validation/executionPayloadBid.js +24 -9
  141. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  142. package/lib/chain/validation/executionPayloadEnvelope.d.ts.map +1 -1
  143. package/lib/chain/validation/executionPayloadEnvelope.js +11 -1
  144. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  145. package/lib/chain/validation/proposerPreferences.d.ts +8 -0
  146. package/lib/chain/validation/proposerPreferences.d.ts.map +1 -0
  147. package/lib/chain/validation/proposerPreferences.js +91 -0
  148. package/lib/chain/validation/proposerPreferences.js.map +1 -0
  149. package/lib/metrics/metrics/lodestar.d.ts +1 -0
  150. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  151. package/lib/metrics/metrics/lodestar.js +4 -0
  152. package/lib/metrics/metrics/lodestar.js.map +1 -1
  153. package/lib/network/gossip/interface.d.ts +7 -1
  154. package/lib/network/gossip/interface.d.ts.map +1 -1
  155. package/lib/network/gossip/interface.js +1 -0
  156. package/lib/network/gossip/interface.js.map +1 -1
  157. package/lib/network/gossip/scoringParameters.d.ts.map +1 -1
  158. package/lib/network/gossip/scoringParameters.js +12 -1
  159. package/lib/network/gossip/scoringParameters.js.map +1 -1
  160. package/lib/network/gossip/topic.d.ts +10 -0
  161. package/lib/network/gossip/topic.d.ts.map +1 -1
  162. package/lib/network/gossip/topic.js +6 -0
  163. package/lib/network/gossip/topic.js.map +1 -1
  164. package/lib/network/interface.d.ts +1 -0
  165. package/lib/network/interface.d.ts.map +1 -1
  166. package/lib/network/network.d.ts +1 -0
  167. package/lib/network/network.d.ts.map +1 -1
  168. package/lib/network/network.js +5 -0
  169. package/lib/network/network.js.map +1 -1
  170. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  171. package/lib/network/processor/gossipHandlers.js +38 -16
  172. package/lib/network/processor/gossipHandlers.js.map +1 -1
  173. package/lib/network/processor/gossipQueues/index.d.ts.map +1 -1
  174. package/lib/network/processor/gossipQueues/index.js +5 -0
  175. package/lib/network/processor/gossipQueues/index.js.map +1 -1
  176. package/lib/network/processor/index.d.ts.map +1 -1
  177. package/lib/network/processor/index.js +6 -5
  178. package/lib/network/processor/index.js.map +1 -1
  179. package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
  180. package/lib/network/reqresp/handlers/beaconBlocksByRange.js +14 -6
  181. package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
  182. package/lib/network/reqresp/handlers/blobSidecarsByRange.d.ts.map +1 -1
  183. package/lib/network/reqresp/handlers/blobSidecarsByRange.js +11 -5
  184. package/lib/network/reqresp/handlers/blobSidecarsByRange.js.map +1 -1
  185. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
  186. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +17 -5
  187. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
  188. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts.map +1 -1
  189. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js +7 -4
  190. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
  191. package/lib/node/nodejs.js +2 -2
  192. package/lib/node/nodejs.js.map +1 -1
  193. package/lib/sync/constants.d.ts +3 -1
  194. package/lib/sync/constants.d.ts.map +1 -1
  195. package/lib/sync/constants.js +3 -4
  196. package/lib/sync/constants.js.map +1 -1
  197. package/lib/sync/range/batch.d.ts +35 -5
  198. package/lib/sync/range/batch.d.ts.map +1 -1
  199. package/lib/sync/range/batch.js +240 -59
  200. package/lib/sync/range/batch.js.map +1 -1
  201. package/lib/sync/range/chain.d.ts +19 -4
  202. package/lib/sync/range/chain.d.ts.map +1 -1
  203. package/lib/sync/range/chain.js +64 -11
  204. package/lib/sync/range/chain.js.map +1 -1
  205. package/lib/sync/range/range.d.ts.map +1 -1
  206. package/lib/sync/range/range.js +31 -9
  207. package/lib/sync/range/range.js.map +1 -1
  208. package/lib/sync/sync.d.ts.map +1 -1
  209. package/lib/sync/sync.js +13 -0
  210. package/lib/sync/sync.js.map +1 -1
  211. package/lib/sync/types.d.ts +34 -0
  212. package/lib/sync/types.d.ts.map +1 -1
  213. package/lib/sync/types.js +34 -0
  214. package/lib/sync/types.js.map +1 -1
  215. package/lib/sync/unknownBlock.d.ts +29 -1
  216. package/lib/sync/unknownBlock.d.ts.map +1 -1
  217. package/lib/sync/unknownBlock.js +738 -61
  218. package/lib/sync/unknownBlock.js.map +1 -1
  219. package/lib/sync/utils/downloadByRange.d.ts +67 -10
  220. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  221. package/lib/sync/utils/downloadByRange.js +211 -26
  222. package/lib/sync/utils/downloadByRange.js.map +1 -1
  223. package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
  224. package/lib/sync/utils/downloadByRoot.js +16 -2
  225. package/lib/sync/utils/downloadByRoot.js.map +1 -1
  226. package/lib/sync/utils/pendingBlocksTree.d.ts +0 -1
  227. package/lib/sync/utils/pendingBlocksTree.d.ts.map +1 -1
  228. package/lib/sync/utils/pendingBlocksTree.js +0 -9
  229. package/lib/sync/utils/pendingBlocksTree.js.map +1 -1
  230. package/lib/util/sszBytes.d.ts.map +1 -1
  231. package/lib/util/sszBytes.js +8 -6
  232. package/lib/util/sszBytes.js.map +1 -1
  233. package/package.json +17 -16
  234. package/src/api/impl/beacon/blocks/index.ts +21 -5
  235. package/src/api/impl/beacon/pool/index.ts +83 -1
  236. package/src/api/impl/debug/index.ts +0 -1
  237. package/src/api/impl/lodestar/index.ts +1 -1
  238. package/src/api/impl/validator/index.ts +82 -1
  239. package/src/chain/blocks/blockInput/blockInput.ts +4 -1
  240. package/src/chain/blocks/importBlock.ts +16 -48
  241. package/src/chain/blocks/importExecutionPayload.ts +126 -100
  242. package/src/chain/blocks/index.ts +71 -23
  243. package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +37 -3
  244. package/src/chain/blocks/payloadEnvelopeInput/types.ts +18 -0
  245. package/src/chain/blocks/payloadEnvelopeProcessor.ts +2 -2
  246. package/src/chain/blocks/types.ts +15 -25
  247. package/src/chain/blocks/utils/chainSegment.ts +114 -17
  248. package/src/chain/blocks/verifyBlock.ts +70 -9
  249. package/src/chain/blocks/verifyBlocksExecutionPayloads.ts +6 -4
  250. package/src/chain/blocks/verifyBlocksSanityChecks.ts +26 -7
  251. package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +137 -0
  252. package/src/chain/blocks/verifyPayloadsDataAvailability.ts +7 -4
  253. package/src/chain/blocks/writePayloadEnvelopeInputToDb.ts +9 -18
  254. package/src/chain/chain.ts +55 -10
  255. package/src/chain/emitter.ts +0 -11
  256. package/src/chain/errors/blockError.ts +4 -1
  257. package/src/chain/errors/executionPayloadBid.ts +6 -0
  258. package/src/chain/errors/executionPayloadEnvelope.ts +6 -0
  259. package/src/chain/errors/index.ts +1 -0
  260. package/src/chain/errors/proposerPreferences.ts +47 -0
  261. package/src/chain/forkChoice/index.ts +2 -2
  262. package/src/chain/initState.ts +9 -1
  263. package/src/chain/interface.ts +9 -1
  264. package/src/chain/opPools/payloadAttestationPool.ts +29 -8
  265. package/src/chain/prepareNextSlot.ts +36 -14
  266. package/src/chain/produceBlock/produceBlockBody.ts +57 -13
  267. package/src/chain/regen/interface.ts +1 -0
  268. package/src/chain/regen/queued.ts +2 -7
  269. package/src/chain/regen/regen.ts +2 -7
  270. package/src/chain/seenCache/index.ts +1 -0
  271. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +89 -21
  272. package/src/chain/seenCache/seenProposerPreferences.ts +32 -0
  273. package/src/chain/validation/block.ts +1 -0
  274. package/src/chain/validation/executionPayloadBid.ts +25 -8
  275. package/src/chain/validation/executionPayloadEnvelope.ts +12 -2
  276. package/src/chain/validation/proposerPreferences.ts +110 -0
  277. package/src/metrics/metrics/lodestar.ts +4 -0
  278. package/src/network/gossip/interface.ts +6 -0
  279. package/src/network/gossip/scoringParameters.ts +14 -1
  280. package/src/network/gossip/topic.ts +6 -0
  281. package/src/network/interface.ts +1 -0
  282. package/src/network/network.ts +11 -0
  283. package/src/network/processor/gossipHandlers.ts +53 -17
  284. package/src/network/processor/gossipQueues/index.ts +5 -0
  285. package/src/network/processor/index.ts +6 -5
  286. package/src/network/reqresp/handlers/beaconBlocksByRange.ts +14 -6
  287. package/src/network/reqresp/handlers/blobSidecarsByRange.ts +11 -5
  288. package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +17 -5
  289. package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +7 -4
  290. package/src/node/nodejs.ts +2 -2
  291. package/src/sync/constants.ts +4 -4
  292. package/src/sync/range/batch.ts +320 -67
  293. package/src/sync/range/chain.ts +89 -14
  294. package/src/sync/range/range.ts +34 -9
  295. package/src/sync/sync.ts +13 -1
  296. package/src/sync/types.ts +72 -0
  297. package/src/sync/unknownBlock.ts +928 -65
  298. package/src/sync/utils/downloadByRange.ts +378 -39
  299. package/src/sync/utils/downloadByRoot.ts +24 -2
  300. package/src/sync/utils/pendingBlocksTree.ts +0 -15
  301. package/src/util/sszBytes.ts +8 -6
@@ -1,14 +1,18 @@
1
1
  import {routes} from "@lodestar/api";
2
- import {ExecutionStatus, PayloadExecutionStatus} from "@lodestar/fork-choice";
3
- import {SLOTS_PER_EPOCH} from "@lodestar/params";
4
- import {getExecutionPayloadEnvelopeSignatureSet, isStatePostGloas} from "@lodestar/state-transition";
5
- import {fromHex, toRootHex} from "@lodestar/utils";
2
+ import {ExecutionStatus, PayloadExecutionStatus, getSafeExecutionBlockHash} from "@lodestar/fork-choice";
3
+ import {DataAvailabilityStatus, isStatePostGloas} from "@lodestar/state-transition";
4
+ import {isErrorAborted} from "@lodestar/utils";
5
+ import {ZERO_HASH_HEX} from "../../constants/index.js";
6
6
  import {ExecutionPayloadStatus} from "../../execution/index.js";
7
7
  import {isQueueErrorAborted} from "../../util/queue/index.js";
8
8
  import {BeaconChain} from "../chain.js";
9
9
  import {RegenCaller} from "../regen/interface.js";
10
10
  import {PayloadEnvelopeInput} from "../seenCache/seenPayloadEnvelopeInput.js";
11
11
  import {ImportPayloadOpts} from "./types.js";
12
+ import {
13
+ verifyExecutionPayloadEnvelope,
14
+ verifyExecutionPayloadEnvelopeSignature,
15
+ } from "./verifyExecutionPayloadEnvelope.js";
12
16
  import {verifyPayloadsDataAvailability} from "./verifyPayloadsDataAvailability.js";
13
17
 
14
18
  const EVENTSTREAM_EMIT_RECENT_EXECUTION_PAYLOAD_SLOTS = 64;
@@ -17,7 +21,8 @@ export enum PayloadErrorCode {
17
21
  EXECUTION_ENGINE_INVALID = "PAYLOAD_ERROR_EXECUTION_ENGINE_INVALID",
18
22
  EXECUTION_ENGINE_ERROR = "PAYLOAD_ERROR_EXECUTION_ENGINE_ERROR",
19
23
  BLOCK_NOT_IN_FORK_CHOICE = "PAYLOAD_ERROR_BLOCK_NOT_IN_FORK_CHOICE",
20
- STATE_TRANSITION_ERROR = "PAYLOAD_ERROR_STATE_TRANSITION_ERROR",
24
+ MISS_BLOCK_STATE = "PAYLOAD_ERROR_MISS_BLOCK_STATE",
25
+ ENVELOPE_VERIFICATION_ERROR = "PAYLOAD_ERROR_ENVELOPE_VERIFICATION_ERROR",
21
26
  INVALID_SIGNATURE = "PAYLOAD_ERROR_INVALID_SIGNATURE",
22
27
  }
23
28
 
@@ -37,7 +42,11 @@ export type PayloadErrorType =
37
42
  blockRootHex: string;
38
43
  }
39
44
  | {
40
- code: PayloadErrorCode.STATE_TRANSITION_ERROR;
45
+ code: PayloadErrorCode.MISS_BLOCK_STATE;
46
+ blockRootHex: string;
47
+ }
48
+ | {
49
+ code: PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR;
41
50
  message: string;
42
51
  }
43
52
  | {
@@ -57,7 +66,6 @@ function toForkChoiceExecutionStatus(status: ExecutionPayloadStatus): PayloadExe
57
66
  switch (status) {
58
67
  case ExecutionPayloadStatus.VALID:
59
68
  return ExecutionStatus.Valid;
60
- // TODO GLOAS: Handle optimistic import for payload
61
69
  case ExecutionPayloadStatus.SYNCING:
62
70
  case ExecutionPayloadStatus.ACCEPTED:
63
71
  return ExecutionStatus.Syncing;
@@ -69,38 +77,43 @@ function toForkChoiceExecutionStatus(status: ExecutionPayloadStatus): PayloadExe
69
77
  /**
70
78
  * Import an execution payload envelope after all data is available.
71
79
  *
72
- * This function:
73
- * 1. Emits `execution_payload_available` if payload is for current slot
74
- * 2. Gets the ProtoBlock from fork choice
75
- * 3. Applies write-queue backpressure (waitForSpace) early, before verification
76
- * 4. Regenerates the block state
77
- * 5. Runs EL verification (notifyNewPayload) in parallel with signature verification and processExecutionPayloadEnvelope
78
- * 6. Persists verified payload envelope to hot DB
79
- * 7. Updates fork choice
80
- * 8. Caches the post-execution payload state
81
- * 9. Records metrics for column sources
82
- * 10. Emits `execution_payload` for recent enough payloads after successful import
80
+ * The envelope is only verified here, no state mutation. State effects from the payload
81
+ * are applied on the next block via processParentExecutionPayload.
82
+ *
83
+ * The DA wait must have run upstream (range sync awaits DA in `verifyBlocksInEpoch` for the
84
+ * whole segment; gossip / API path uses the `processExecutionPayload` wrapper below).
83
85
  *
86
+ * Steps:
87
+ * 1. Emit `execution_payload_available` event for payload attestation
88
+ * 2. Get the ProtoBlock from fork choice
89
+ * 3. Regenerate state for envelope verification
90
+ * 4. Verify envelope (fields against state, signature, and EL in parallel where possible)
91
+ * 5. Persist verified payload envelope to hot DB (waits for write-queue space for backpressure)
92
+ * 6. Update fork choice (transitions the block's PENDING variant to FULL)
93
+ * 7. Queue notifyForkchoiceUpdate to engine api
94
+ * 8. Record metrics for payload envelope and column sources
95
+ * 9. Emit `execution_payload` event
84
96
  */
85
97
  export async function importExecutionPayload(
86
98
  this: BeaconChain,
87
99
  payloadInput: PayloadEnvelopeInput,
88
- signal: AbortSignal,
100
+ dataAvailabilityStatus: DataAvailabilityStatus,
89
101
  opts: ImportPayloadOpts = {}
90
102
  ): Promise<void> {
91
103
  const signedEnvelope = payloadInput.getPayloadEnvelope();
92
104
  const envelope = signedEnvelope.message;
105
+ const slot = envelope.payload.slotNumber;
93
106
  const blockRootHex = payloadInput.blockRootHex;
94
107
  const blockHashHex = payloadInput.getBlockHashHex();
95
- const fork = this.config.getForkName(envelope.payload.slotNumber);
108
+ const fork = this.config.getForkName(slot);
96
109
 
97
- // 1. Emit `execution_payload_available` event at the start of import. At this point the payload input
98
- // is already complete, so the payload and required data are available for payload attestation.
99
- // This event is only about availability, not validity of the execution payload, hence we can emit
100
- // it before getting a response from the execution client on whether the payload is valid or not.
101
- if (this.clock.currentSlot - envelope.payload.slotNumber < EVENTSTREAM_EMIT_RECENT_EXECUTION_PAYLOAD_SLOTS) {
110
+ // 1. Emit `execution_payload_available` event at the start of import. At this point the
111
+ // payload input is already complete, so the payload and required data are available for
112
+ // payload attestation. This event only signals availability (not validity), so we can emit
113
+ // it before getting a response from the EL on whether the payload is valid or not.
114
+ if (this.clock.currentSlot - slot < EVENTSTREAM_EMIT_RECENT_EXECUTION_PAYLOAD_SLOTS) {
102
115
  this.emitter.emit(routes.events.EventType.executionPayloadAvailable, {
103
- slot: envelope.payload.slotNumber,
116
+ slot,
104
117
  blockRoot: blockRootHex,
105
118
  });
106
119
  }
@@ -114,80 +127,72 @@ export async function importExecutionPayload(
114
127
  });
115
128
  }
116
129
 
117
- // 3. Wait for data columns to be available before claiming a write-queue slot.
118
- // The helper is shared with future gloas sync services; take the single-item batch form here.
119
- await verifyPayloadsDataAvailability([payloadInput], signal);
120
-
121
- // 4. Apply backpressure from the write queue, before doing verification work.
122
- // The actual DB write is deferred until after verification succeeds.
123
- await this.unfinalizedPayloadEnvelopeWrites.waitForSpace();
130
+ // 3. Regenerate state for envelope verification
131
+ const blockState = await this.regen
132
+ .getBlockSlotState(protoBlock, protoBlock.slot, {dontTransferCache: true}, RegenCaller.processBlock)
133
+ .catch(() =>
134
+ // only happen at the 1st batch of skipped slot checkpoint sync
135
+ this.regen.getClosestHeadState(protoBlock)
136
+ );
124
137
 
125
- // 5. Get pre-state for processExecutionPayloadEnvelope
126
- // We need the block state (post-block, pre-payload) to process the envelope
127
- const blockState = await this.regen.getBlockSlotState(
128
- protoBlock,
129
- protoBlock.slot,
130
- {dontTransferCache: true},
131
- RegenCaller.processBlock
132
- );
138
+ if (blockState == null) {
139
+ throw new PayloadError({
140
+ code: PayloadErrorCode.MISS_BLOCK_STATE,
141
+ blockRootHex: protoBlock.blockRoot,
142
+ });
143
+ }
133
144
  if (!isStatePostGloas(blockState)) {
134
145
  throw new PayloadError({
135
- code: PayloadErrorCode.STATE_TRANSITION_ERROR,
136
- message: `Expected gloas+ block state for payload import, got fork=${blockState.forkName}`,
146
+ code: PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR,
147
+ message: `Expected gloas+ state for payload import, got fork=${blockState.forkName}`,
137
148
  });
138
149
  }
139
150
 
140
- // 6. Run verification steps in parallel
141
- const [execResult, signatureValid, postPayloadResult] = await Promise.all([
151
+ // 4. Verify envelope fields against state first to fail fast before the EL + BLS work.
152
+ // When validSignature is true, gossip/API has already verified both the signature and the
153
+ // executionRequestsRoot, so we skip those checks here.
154
+ try {
155
+ verifyExecutionPayloadEnvelope(this.config, blockState, envelope, {
156
+ verifyExecutionRequestsRoot: !opts.validSignature,
157
+ });
158
+ } catch (e) {
159
+ throw new PayloadError(
160
+ {
161
+ code: PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR,
162
+ message: (e as Error).message,
163
+ },
164
+ `Envelope verification error: ${(e as Error).message}`
165
+ );
166
+ }
167
+
168
+ // 4a. Run EL and signature verification in parallel
169
+ const [execResult, signatureValid] = await Promise.all([
142
170
  this.executionEngine.notifyNewPayload(
143
171
  fork,
144
172
  envelope.payload,
145
173
  payloadInput.getVersionedHashes(),
146
- fromHex(protoBlock.parentRoot),
174
+ envelope.parentBeaconBlockRoot,
147
175
  envelope.executionRequests
148
176
  ),
149
177
 
150
178
  opts.validSignature === true
151
179
  ? Promise.resolve(true)
152
- : (async () => {
153
- const signatureSet = getExecutionPayloadEnvelopeSignatureSet(
154
- this.config,
155
- this.pubkeyCache,
156
- blockState,
157
- signedEnvelope,
158
- payloadInput.proposerIndex
159
- );
160
- return this.bls.verifySignatureSets([signatureSet]);
161
- })(),
162
-
163
- // Signature verified separately above.
164
- // State root check is done separately below with better error typing (matching block pipeline pattern).
165
- (async () => {
166
- try {
167
- return {
168
- postPayloadState: blockState.processExecutionPayloadEnvelope(signedEnvelope, {
169
- verifySignature: false,
170
- verifyStateRoot: false,
171
- }),
172
- };
173
- } catch (e) {
174
- throw new PayloadError(
175
- {
176
- code: PayloadErrorCode.STATE_TRANSITION_ERROR,
177
- message: (e as Error).message,
178
- },
179
- `State transition error: ${(e as Error).message}`
180
- );
181
- }
182
- })(),
180
+ : verifyExecutionPayloadEnvelopeSignature(
181
+ this.config,
182
+ blockState,
183
+ this.pubkeyCache,
184
+ signedEnvelope,
185
+ payloadInput.proposerIndex,
186
+ this.bls
187
+ ),
183
188
  ]);
184
189
 
185
- // 5a. Check signature verification result
190
+ // 4b. Check signature verification result
186
191
  if (!signatureValid) {
187
192
  throw new PayloadError({code: PayloadErrorCode.INVALID_SIGNATURE});
188
193
  }
189
194
 
190
- // 5b. Handle EL response
195
+ // 4c. Handle EL response
191
196
  switch (execResult.status) {
192
197
  case ExecutionPayloadStatus.VALID:
193
198
  break;
@@ -213,59 +218,80 @@ export async function importExecutionPayload(
213
218
  });
214
219
  }
215
220
 
216
- // 5c. Compute post-payload state root
217
- const postPayloadState = postPayloadResult.postPayloadState;
218
- const postPayloadStateRoot = postPayloadState.hashTreeRoot();
219
-
220
- // 6. Persist payload envelope to hot DB (performed asynchronously to avoid blocking)
221
+ // 5. Persist payload envelope to hot DB. Wait for write-queue space here to apply backpressure
222
+ // on the import pipeline during sync, then perform the write asynchronously to avoid blocking.
223
+ await this.unfinalizedPayloadEnvelopeWrites.waitForSpace();
221
224
  this.unfinalizedPayloadEnvelopeWrites.push(payloadInput).catch((e) => {
222
225
  if (!isQueueErrorAborted(e)) {
223
226
  this.logger.error(
224
227
  "Error pushing payload envelope to unfinalized write queue",
225
- {slot: envelope.payload.slotNumber, blockRoot: blockRootHex},
228
+ {slot, blockRoot: blockRootHex},
226
229
  e as Error
227
230
  );
228
231
  }
229
232
  });
230
233
 
231
- // 7. Update fork choice
234
+ // 6. Update fork choice, transitions the block's PENDING variant to FULL
235
+ const execStatus = toForkChoiceExecutionStatus(execResult.status);
232
236
  this.forkChoice.onExecutionPayload(
233
237
  blockRootHex,
234
238
  blockHashHex,
235
239
  envelope.payload.blockNumber,
236
- toRootHex(postPayloadStateRoot),
237
- toForkChoiceExecutionStatus(execResult.status)
240
+ execStatus,
241
+ dataAvailabilityStatus
238
242
  );
239
243
 
240
- // 8. Cache payload state
241
- this.regen.processState(blockRootHex, postPayloadState);
242
- if (postPayloadState.slot % SLOTS_PER_EPOCH === 0) {
243
- const {checkpoint} = postPayloadState.computeAnchorCheckpoint();
244
- this.regen.addCheckpointState(checkpoint, postPayloadState);
244
+ // 7. Queue notifyForkchoiceUpdate to engine api
245
+ const head = this.forkChoice.getHead();
246
+ if (!this.opts.disableImportExecutionFcU && blockRootHex === head.blockRoot) {
247
+ const safeBlockHash = getSafeExecutionBlockHash(this.forkChoice);
248
+ const finalizedBlockHash = this.forkChoice.getFinalizedBlock().executionPayloadBlockHash ?? ZERO_HASH_HEX;
249
+ this.executionEngine.notifyForkchoiceUpdate(fork, blockHashHex, safeBlockHash, finalizedBlockHash).catch((e) => {
250
+ if (!isErrorAborted(e) && !isQueueErrorAborted(e)) {
251
+ this.logger.error("Error pushing notifyForkchoiceUpdate()", {blockHashHex, finalizedBlockHash}, e);
252
+ }
253
+ });
245
254
  }
246
255
 
247
- // 9. Record metrics for payload envelope and column sources
256
+ // 8. Record metrics for payload envelope and column sources
248
257
  this.metrics?.importPayload.bySource.inc({source: payloadInput.getPayloadEnvelopeSource().source});
249
258
  for (const {source} of payloadInput.getSampledColumnsWithSource()) {
250
259
  this.metrics?.importPayload.columnsBySource.inc({source});
251
260
  }
252
261
 
253
- // 10. Emit event after payload is fully verified and imported to fork choice, only for recent enough payloads
254
- if (this.clock.currentSlot - envelope.payload.slotNumber < EVENTSTREAM_EMIT_RECENT_EXECUTION_PAYLOAD_SLOTS) {
262
+ // 9. Emit event after payload is fully verified and imported to fork choice, only for recent enough payloads
263
+ if (this.clock.currentSlot - slot < EVENTSTREAM_EMIT_RECENT_EXECUTION_PAYLOAD_SLOTS) {
255
264
  this.emitter.emit(routes.events.EventType.executionPayload, {
256
- slot: envelope.payload.slotNumber,
265
+ slot,
257
266
  builderIndex: envelope.builderIndex,
258
267
  blockHash: blockHashHex,
259
268
  blockRoot: blockRootHex,
260
- // TODO GLOAS: revisit once we support optimistic import
261
- executionOptimistic: false,
269
+ executionOptimistic: execStatus === ExecutionStatus.Syncing,
262
270
  });
263
271
  }
264
272
 
265
273
  this.logger.verbose("Execution payload imported", {
266
- slot: envelope.payload.slotNumber,
274
+ slot,
267
275
  builderIndex: envelope.builderIndex,
268
276
  blockRoot: blockRootHex,
269
277
  blockHash: blockHashHex,
270
278
  });
271
279
  }
280
+
281
+ /**
282
+ * Process an execution payload envelope end-to-end: wait for DA, then import.
283
+ *
284
+ * Used by the PayloadEnvelopeProcessor queue (gossip / API / unknown-payload sync) — i.e.
285
+ * callers that have NOT already awaited DA themselves. Range sync's inline dispatch in
286
+ * processBlocks skips this wrapper and calls `importExecutionPayload` directly, since
287
+ * `verifyBlocksInEpoch` already awaited DA for the segment.
288
+ */
289
+ export async function processExecutionPayload(
290
+ this: BeaconChain,
291
+ payloadInput: PayloadEnvelopeInput,
292
+ signal: AbortSignal,
293
+ opts: ImportPayloadOpts = {}
294
+ ): Promise<void> {
295
+ const {dataAvailabilityStatuses} = await verifyPayloadsDataAvailability([payloadInput], signal);
296
+ await importExecutionPayload.call(this, payloadInput, dataAvailabilityStatuses[0], opts);
297
+ }
@@ -1,4 +1,4 @@
1
- import {SignedBeaconBlock} from "@lodestar/types";
1
+ import {SignedBeaconBlock, Slot} from "@lodestar/types";
2
2
  import {isErrorAborted, toRootHex} from "@lodestar/utils";
3
3
  import {Metrics} from "../../metrics/metrics.js";
4
4
  import {nextEventLoop} from "../../util/eventLoop.js";
@@ -8,6 +8,8 @@ import {BlockError, BlockErrorCode, isBlockErrorAborted} from "../errors/index.j
8
8
  import {BlockProcessOpts} from "../options.js";
9
9
  import {IBlockInput} from "./blockInput/types.js";
10
10
  import {importBlock} from "./importBlock.js";
11
+ import {importExecutionPayload} from "./importExecutionPayload.js";
12
+ import {PayloadEnvelopeInput} from "./payloadEnvelopeInput/payloadEnvelopeInput.js";
11
13
  import {FullyVerifiedBlock, ImportBlockOpts} from "./types.js";
12
14
  import {assertLinearChainSegment} from "./utils/chainSegment.js";
13
15
  import {verifyBlocksInEpoch} from "./verifyBlock.js";
@@ -21,20 +23,24 @@ const QUEUE_MAX_LENGTH = 256;
21
23
  * BlockProcessor processes block jobs in a queued fashion, one after the other.
22
24
  */
23
25
  export class BlockProcessor {
24
- readonly jobQueue: JobItemQueue<[IBlockInput[], ImportBlockOpts], void>;
26
+ readonly jobQueue: JobItemQueue<[IBlockInput[], Map<Slot, PayloadEnvelopeInput> | null, ImportBlockOpts], void>;
25
27
 
26
28
  constructor(chain: BeaconChain, metrics: Metrics | null, opts: BlockProcessOpts, signal: AbortSignal) {
27
- this.jobQueue = new JobItemQueue<[IBlockInput[], ImportBlockOpts], void>(
28
- (job, importOpts) => {
29
- return processBlocks.call(chain, job, {...opts, ...importOpts});
29
+ this.jobQueue = new JobItemQueue<[IBlockInput[], Map<Slot, PayloadEnvelopeInput> | null, ImportBlockOpts], void>(
30
+ (job, payloadEnvelopes, importOpts) => {
31
+ return processBlocks.call(chain, job, payloadEnvelopes, {...opts, ...importOpts});
30
32
  },
31
33
  {maxLength: QUEUE_MAX_LENGTH, noYieldIfOneItem: true, signal},
32
34
  metrics?.blockProcessorQueue ?? undefined
33
35
  );
34
36
  }
35
37
 
36
- async processBlocksJob(job: IBlockInput[], opts: ImportBlockOpts = {}): Promise<void> {
37
- await this.jobQueue.push(job, opts);
38
+ async processBlocksJob(
39
+ job: IBlockInput[],
40
+ payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null,
41
+ opts: ImportBlockOpts = {}
42
+ ): Promise<void> {
43
+ await this.jobQueue.push(job, payloadEnvelopes, opts);
38
44
  }
39
45
  }
40
46
 
@@ -51,18 +57,15 @@ export class BlockProcessor {
51
57
  export async function processBlocks(
52
58
  this: BeaconChain,
53
59
  blocks: IBlockInput[],
60
+ payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null,
54
61
  opts: BlockProcessOpts & ImportBlockOpts
55
62
  ): Promise<void> {
56
63
  if (blocks.length === 0) {
57
64
  return; // TODO: or throw?
58
65
  }
59
66
 
60
- if (blocks.length > 1) {
61
- assertLinearChainSegment(this.config, blocks);
62
- }
63
-
64
67
  try {
65
- const {relevantBlocks, parentSlots, parentBlock} = verifyBlocksSanityChecks(this, blocks, opts);
68
+ const {relevantBlocks, parentSlots, parentBlock} = verifyBlocksSanityChecks(this, blocks, payloadEnvelopes, opts);
66
69
 
67
70
  // No relevant blocks, skip verifyBlocksInEpoch()
68
71
  if (relevantBlocks.length === 0 || parentBlock === null) {
@@ -70,10 +73,31 @@ export async function processBlocks(
70
73
  return;
71
74
  }
72
75
 
76
+ const {warnings: orphanedPayloads} = assertLinearChainSegment(
77
+ this.config,
78
+ relevantBlocks,
79
+ payloadEnvelopes,
80
+ parentBlock
81
+ );
82
+ if (orphanedPayloads != null) {
83
+ for (const orphaned of orphanedPayloads) {
84
+ this.logger.debug("Orphaned payload envelope in chain segment", {
85
+ slot: orphaned.slot,
86
+ blockRoot: orphaned.payloadEnvelopeInput.blockRootHex,
87
+ });
88
+ }
89
+ }
90
+
73
91
  // Fully verify a block to be imported immediately after. Does not produce any side-effects besides adding intermediate
74
92
  // states in the state cache through regen.
75
- const {postStates, dataAvailabilityStatuses, proposerBalanceDeltas, segmentExecStatus, indexedAttestationsByBlock} =
76
- await verifyBlocksInEpoch.call(this, parentBlock, relevantBlocks, opts);
93
+ const {
94
+ postStates,
95
+ blockDAStatuses,
96
+ payloadDAStatuses,
97
+ proposerBalanceDeltas,
98
+ segmentExecStatus,
99
+ indexedAttestationsByBlock,
100
+ } = await verifyBlocksInEpoch.call(this, parentBlock, relevantBlocks, payloadEnvelopes, opts);
77
101
 
78
102
  // If segmentExecStatus has lvhForkchoice then, the entire segment should be invalid
79
103
  // and we need to further propagate
@@ -85,25 +109,49 @@ export async function processBlocks(
85
109
  }
86
110
 
87
111
  const {executionStatuses} = segmentExecStatus;
88
- const fullyVerifiedBlocks = relevantBlocks.map(
89
- (block, i): FullyVerifiedBlock => ({
112
+ const verifiedBlocksBySlot = new Map<Slot, FullyVerifiedBlock>();
113
+ for (let i = 0; i < relevantBlocks.length; i++) {
114
+ const block = relevantBlocks[i];
115
+ verifiedBlocksBySlot.set(block.getBlock().message.slot, {
90
116
  blockInput: block,
91
117
  postState: postStates[i],
92
- postPayloadState: null,
93
118
  parentBlockSlot: parentSlots[i],
94
119
  executionStatus: executionStatuses[i],
95
120
  // start supporting optimistic syncing/processing
96
- dataAvailabilityStatus: dataAvailabilityStatuses[i],
121
+ dataAvailabilityStatus: blockDAStatuses[i],
97
122
  proposerBalanceDelta: proposerBalanceDeltas[i],
98
123
  indexedAttestations: indexedAttestationsByBlock[i],
99
124
  // TODO: Make this param mandatory and capture in gossip
100
125
  seenTimestampSec: opts.seenTimestampSec ?? Math.floor(Date.now() / 1000),
101
- })
102
- );
126
+ });
127
+ }
128
+
129
+ const slotSet = new Set<Slot>(blocks.map((b) => b.getBlock().message.slot));
130
+ if (payloadEnvelopes) {
131
+ for (const slot of payloadEnvelopes.keys()) slotSet.add(slot);
132
+ }
133
+ const slots = Array.from(slotSet).sort((a, b) => a - b);
134
+ for (const slot of slots) {
135
+ const fullyVerifiedBlock = verifiedBlocksBySlot.get(slot);
136
+ if (fullyVerifiedBlock !== undefined) {
137
+ // TODO: Consider batching importBlock too if it takes significant time
138
+ await importBlock.call(this, fullyVerifiedBlock, opts);
139
+ }
140
+
141
+ const payloadInput = payloadEnvelopes?.get(slot);
142
+ if (payloadInput?.hasPayloadEnvelope()) {
143
+ if (!payloadInput.isComplete()) {
144
+ // we validated DA before reaching this
145
+ throw new Error(`Payload envelope for slot ${slot} not complete after DA verification`);
146
+ }
147
+ // we already awaited DA in verifyBlocksInEpoch for this segment
148
+ const payloadDA = payloadDAStatuses.get(slot);
149
+ if (payloadDA === undefined) {
150
+ throw new Error(`Missing payload DA status for slot ${slot}`);
151
+ }
152
+ await importExecutionPayload.call(this, payloadInput, payloadDA, {validSignature: false});
153
+ }
103
154
 
104
- for (const fullyVerifiedBlock of fullyVerifiedBlocks) {
105
- // TODO: Consider batching importBlock too if it takes significant time
106
- await importBlock.call(this, fullyVerifiedBlock, opts);
107
155
  await nextEventLoop();
108
156
  }
109
157
  } catch (e) {
@@ -4,7 +4,13 @@ import {toRootHex, withTimeout} from "@lodestar/utils";
4
4
  import {VersionedHashes} from "../../../execution/index.js";
5
5
  import {kzgCommitmentToVersionedHash} from "../../../util/blobs.js";
6
6
  import {MissingColumnMeta} from "../blockInput/types.js";
7
- import {AddPayloadEnvelopeProps, ColumnWithSource, CreateFromBlockProps, SourceMeta} from "./types.js";
7
+ import {
8
+ AddPayloadEnvelopeProps,
9
+ ColumnWithSource,
10
+ CreateFromBidProps,
11
+ CreateFromBlockProps,
12
+ SourceMeta,
13
+ } from "./types.js";
8
14
 
9
15
  export type PayloadEnvelopeInputState =
10
16
  | {
@@ -64,6 +70,7 @@ export class PayloadEnvelopeInput {
64
70
  readonly proposerIndex: ValidatorIndex;
65
71
  readonly bid: gloas.ExecutionPayloadBid;
66
72
  readonly versionedHashes: VersionedHashes;
73
+ readonly daOutOfRange: boolean;
67
74
 
68
75
  private columnsCache = new Map<ColumnIndex, ColumnWithSource>();
69
76
 
@@ -87,6 +94,7 @@ export class PayloadEnvelopeInput {
87
94
  sampledColumns: ColumnIndex[];
88
95
  custodyColumns: ColumnIndex[];
89
96
  timeCreatedSec: number;
97
+ daOutOfRange: boolean;
90
98
  }) {
91
99
  this.blockRootHex = props.blockRootHex;
92
100
  this.slot = props.slot;
@@ -97,13 +105,14 @@ export class PayloadEnvelopeInput {
97
105
  this.sampledColumns = props.sampledColumns;
98
106
  this.custodyColumns = props.custodyColumns;
99
107
  this.timeCreatedSec = props.timeCreatedSec;
108
+ this.daOutOfRange = props.daOutOfRange;
100
109
  this.payloadEnvelopeDataPromise = createPromise();
101
110
  this.allDataPromise = createPromise();
102
111
  this.columnsDataPromise = createPromise();
103
112
 
104
113
  const noBlobs = props.bid.blobKzgCommitments.length === 0;
105
114
  const noSampledColumns = props.sampledColumns.length === 0;
106
- const hasAllData = noBlobs || noSampledColumns;
115
+ const hasAllData = props.daOutOfRange || noBlobs || noSampledColumns;
107
116
 
108
117
  if (hasAllData) {
109
118
  this.state = {hasPayload: false, hasAllData: true, hasComputedAllData: true};
@@ -125,6 +134,27 @@ export class PayloadEnvelopeInput {
125
134
  sampledColumns: props.sampledColumns,
126
135
  custodyColumns: props.custodyColumns,
127
136
  timeCreatedSec: props.timeCreatedSec,
137
+ daOutOfRange: props.daOutOfRange,
138
+ });
139
+ }
140
+
141
+ /**
142
+ * Create a `PayloadEnvelopeInput` from a state's `latestExecutionPayloadBid` (the bid
143
+ * recorded in beacon state for the latest imported block). Used when seeding the cache
144
+ * for a checkpoint anchor block — we have the bid via state but not the full
145
+ * SignedBeaconBlock body.
146
+ */
147
+ static createFromBid(props: CreateFromBidProps): PayloadEnvelopeInput {
148
+ return new PayloadEnvelopeInput({
149
+ blockRootHex: props.blockRootHex,
150
+ slot: props.slot,
151
+ forkName: props.forkName,
152
+ proposerIndex: props.proposerIndex,
153
+ bid: props.bid,
154
+ sampledColumns: props.sampledColumns,
155
+ custodyColumns: props.custodyColumns,
156
+ timeCreatedSec: props.timeCreatedSec,
157
+ daOutOfRange: props.daOutOfRange,
128
158
  });
129
159
  }
130
160
 
@@ -152,6 +182,7 @@ export class PayloadEnvelopeInput {
152
182
  throw new Error("Payload envelope beacon_block_root mismatch");
153
183
  }
154
184
 
185
+ // TODO GLOAS: track source by metrics, maybe inside the seen cache
155
186
  const source: SourceMeta = {
156
187
  source: props.source,
157
188
  seenTimestampSec: props.seenTimestampSec,
@@ -306,8 +337,11 @@ export class PayloadEnvelopeInput {
306
337
  return this.state.hasAllData;
307
338
  }
308
339
 
340
+ /**
341
+ * Strictly checks missing sampled columns. Does NOT short-circuit on `state.hasAllData`.
342
+ */
309
343
  getMissingSampledColumnMeta(): MissingColumnMeta {
310
- if (this.state.hasAllData) {
344
+ if (this.state.hasComputedAllData) {
311
345
  return {missing: [], versionedHashes: this.versionedHashes};
312
346
  }
313
347
 
@@ -27,6 +27,24 @@ export type CreateFromBlockProps = {
27
27
  sampledColumns: ColumnIndex[];
28
28
  custodyColumns: ColumnIndex[];
29
29
  timeCreatedSec: number;
30
+ daOutOfRange: boolean;
31
+ };
32
+
33
+ /**
34
+ * Used to seed an entry from a state's `latestExecutionPayloadBid` (e.g., when initializing
35
+ * the chain from a checkpoint anchor state — we have the bid via the state but not the
36
+ * full SignedBeaconBlock).
37
+ */
38
+ export type CreateFromBidProps = {
39
+ blockRootHex: RootHex;
40
+ slot: number;
41
+ forkName: ForkName;
42
+ proposerIndex: number;
43
+ bid: gloas.ExecutionPayloadBid;
44
+ sampledColumns: ColumnIndex[];
45
+ custodyColumns: ColumnIndex[];
46
+ timeCreatedSec: number;
47
+ daOutOfRange: boolean;
30
48
  };
31
49
 
32
50
  export type AddPayloadEnvelopeProps = SourceMeta & {
@@ -2,7 +2,7 @@ import {Metrics} from "../../metrics/metrics.js";
2
2
  import {JobItemQueue} from "../../util/queue/index.js";
3
3
  import type {BeaconChain} from "../chain.js";
4
4
  import {PayloadEnvelopeInput} from "../seenCache/seenPayloadEnvelopeInput.js";
5
- import {importExecutionPayload} from "./importExecutionPayload.js";
5
+ import {processExecutionPayload} from "./importExecutionPayload.js";
6
6
  import {ImportPayloadOpts} from "./types.js";
7
7
 
8
8
  // TODO GLOAS: Set to be equal to DEFAULT_MAX_PENDING_UNFINALIZED_PAYLOAD_ENVELOPE_WRITES for now
@@ -30,7 +30,7 @@ export class PayloadEnvelopeProcessor {
30
30
  this.jobQueue = new JobItemQueue<[PayloadEnvelopeInput, ImportPayloadOpts], void>(
31
31
  (payloadInput, opts) => {
32
32
  this.importStatus.set(payloadInput, PayloadEnvelopeImportStatus.importing);
33
- return importExecutionPayload.call(chain, payloadInput, signal, opts);
33
+ return processExecutionPayload.call(chain, payloadInput, signal, opts);
34
34
  },
35
35
  {maxLength: QUEUE_MAX_LENGTH, noYieldIfOneItem: true, signal},
36
36
  metrics?.payloadEnvelopeProcessorQueue ?? undefined