@lodestar/beacon-node 1.43.0-dev.6b7eebbf6d → 1.43.0-dev.6f485b1b61

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 (288) 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 +23 -6
  23. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  24. package/lib/chain/blocks/importExecutionPayload.js +57 -24
  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 -25
  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 +4 -3
  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 +2 -2
  57. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -1
  58. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +12 -8
  59. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -1
  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.map +1 -1
  64. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js +1 -10
  65. package/lib/chain/blocks/writePayloadEnvelopeInputToDb.js.map +1 -1
  66. package/lib/chain/chain.d.ts +5 -3
  67. package/lib/chain/chain.d.ts.map +1 -1
  68. package/lib/chain/chain.js +42 -12
  69. package/lib/chain/chain.js.map +1 -1
  70. package/lib/chain/emitter.d.ts +0 -11
  71. package/lib/chain/emitter.d.ts.map +1 -1
  72. package/lib/chain/emitter.js +0 -4
  73. package/lib/chain/emitter.js.map +1 -1
  74. package/lib/chain/errors/blockError.d.ts +8 -1
  75. package/lib/chain/errors/blockError.d.ts.map +1 -1
  76. package/lib/chain/errors/blockError.js +2 -0
  77. package/lib/chain/errors/blockError.js.map +1 -1
  78. package/lib/chain/errors/executionPayloadBid.d.ts +5 -0
  79. package/lib/chain/errors/executionPayloadBid.d.ts.map +1 -1
  80. package/lib/chain/errors/executionPayloadBid.js +1 -0
  81. package/lib/chain/errors/executionPayloadBid.js.map +1 -1
  82. package/lib/chain/errors/index.d.ts +1 -0
  83. package/lib/chain/errors/index.d.ts.map +1 -1
  84. package/lib/chain/errors/index.js +1 -0
  85. package/lib/chain/errors/index.js.map +1 -1
  86. package/lib/chain/errors/proposerPreferences.d.ts +40 -0
  87. package/lib/chain/errors/proposerPreferences.d.ts.map +1 -0
  88. package/lib/chain/errors/proposerPreferences.js +14 -0
  89. package/lib/chain/errors/proposerPreferences.js.map +1 -0
  90. package/lib/chain/initState.d.ts.map +1 -1
  91. package/lib/chain/initState.js +6 -1
  92. package/lib/chain/initState.js.map +1 -1
  93. package/lib/chain/interface.d.ts +5 -3
  94. package/lib/chain/interface.d.ts.map +1 -1
  95. package/lib/chain/interface.js.map +1 -1
  96. package/lib/chain/opPools/payloadAttestationPool.d.ts +3 -2
  97. package/lib/chain/opPools/payloadAttestationPool.d.ts.map +1 -1
  98. package/lib/chain/opPools/payloadAttestationPool.js +26 -4
  99. package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
  100. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  101. package/lib/chain/prepareNextSlot.js +31 -13
  102. package/lib/chain/prepareNextSlot.js.map +1 -1
  103. package/lib/chain/produceBlock/produceBlockBody.d.ts +11 -1
  104. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  105. package/lib/chain/produceBlock/produceBlockBody.js +47 -15
  106. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  107. package/lib/chain/regen/interface.d.ts +1 -0
  108. package/lib/chain/regen/interface.d.ts.map +1 -1
  109. package/lib/chain/regen/interface.js +1 -0
  110. package/lib/chain/regen/interface.js.map +1 -1
  111. package/lib/chain/regen/queued.d.ts.map +1 -1
  112. package/lib/chain/regen/queued.js +1 -4
  113. package/lib/chain/regen/queued.js.map +1 -1
  114. package/lib/chain/regen/regen.d.ts.map +1 -1
  115. package/lib/chain/regen/regen.js +1 -4
  116. package/lib/chain/regen/regen.js.map +1 -1
  117. package/lib/chain/seenCache/index.d.ts +1 -0
  118. package/lib/chain/seenCache/index.d.ts.map +1 -1
  119. package/lib/chain/seenCache/index.js +1 -0
  120. package/lib/chain/seenCache/index.js.map +1 -1
  121. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +24 -7
  122. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  123. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +69 -17
  124. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  125. package/lib/chain/seenCache/seenProposerPreferences.d.ts +16 -0
  126. package/lib/chain/seenCache/seenProposerPreferences.d.ts.map +1 -0
  127. package/lib/chain/seenCache/seenProposerPreferences.js +26 -0
  128. package/lib/chain/seenCache/seenProposerPreferences.js.map +1 -0
  129. package/lib/chain/validation/block.d.ts.map +1 -1
  130. package/lib/chain/validation/block.js +1 -0
  131. package/lib/chain/validation/block.js.map +1 -1
  132. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  133. package/lib/chain/validation/executionPayloadBid.js +24 -9
  134. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  135. package/lib/chain/validation/proposerPreferences.d.ts +8 -0
  136. package/lib/chain/validation/proposerPreferences.d.ts.map +1 -0
  137. package/lib/chain/validation/proposerPreferences.js +91 -0
  138. package/lib/chain/validation/proposerPreferences.js.map +1 -0
  139. package/lib/metrics/metrics/lodestar.d.ts +1 -0
  140. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  141. package/lib/metrics/metrics/lodestar.js +4 -0
  142. package/lib/metrics/metrics/lodestar.js.map +1 -1
  143. package/lib/network/gossip/interface.d.ts +7 -1
  144. package/lib/network/gossip/interface.d.ts.map +1 -1
  145. package/lib/network/gossip/interface.js +1 -0
  146. package/lib/network/gossip/interface.js.map +1 -1
  147. package/lib/network/gossip/scoringParameters.d.ts.map +1 -1
  148. package/lib/network/gossip/scoringParameters.js +12 -1
  149. package/lib/network/gossip/scoringParameters.js.map +1 -1
  150. package/lib/network/gossip/topic.d.ts +10 -0
  151. package/lib/network/gossip/topic.d.ts.map +1 -1
  152. package/lib/network/gossip/topic.js +6 -0
  153. package/lib/network/gossip/topic.js.map +1 -1
  154. package/lib/network/interface.d.ts +1 -0
  155. package/lib/network/interface.d.ts.map +1 -1
  156. package/lib/network/network.d.ts +1 -0
  157. package/lib/network/network.d.ts.map +1 -1
  158. package/lib/network/network.js +5 -0
  159. package/lib/network/network.js.map +1 -1
  160. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  161. package/lib/network/processor/gossipHandlers.js +38 -16
  162. package/lib/network/processor/gossipHandlers.js.map +1 -1
  163. package/lib/network/processor/gossipQueues/index.d.ts.map +1 -1
  164. package/lib/network/processor/gossipQueues/index.js +5 -0
  165. package/lib/network/processor/gossipQueues/index.js.map +1 -1
  166. package/lib/network/processor/index.d.ts.map +1 -1
  167. package/lib/network/processor/index.js +6 -5
  168. package/lib/network/processor/index.js.map +1 -1
  169. package/lib/network/reqresp/handlers/beaconBlocksByRange.d.ts.map +1 -1
  170. package/lib/network/reqresp/handlers/beaconBlocksByRange.js +14 -6
  171. package/lib/network/reqresp/handlers/beaconBlocksByRange.js.map +1 -1
  172. package/lib/network/reqresp/handlers/blobSidecarsByRange.d.ts.map +1 -1
  173. package/lib/network/reqresp/handlers/blobSidecarsByRange.js +11 -5
  174. package/lib/network/reqresp/handlers/blobSidecarsByRange.js.map +1 -1
  175. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.d.ts.map +1 -1
  176. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js +17 -5
  177. package/lib/network/reqresp/handlers/dataColumnSidecarsByRange.js.map +1 -1
  178. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.d.ts.map +1 -1
  179. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js +7 -4
  180. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRange.js.map +1 -1
  181. package/lib/node/nodejs.js +2 -2
  182. package/lib/node/nodejs.js.map +1 -1
  183. package/lib/sync/constants.d.ts +3 -1
  184. package/lib/sync/constants.d.ts.map +1 -1
  185. package/lib/sync/constants.js +3 -4
  186. package/lib/sync/constants.js.map +1 -1
  187. package/lib/sync/range/batch.d.ts +35 -5
  188. package/lib/sync/range/batch.d.ts.map +1 -1
  189. package/lib/sync/range/batch.js +240 -59
  190. package/lib/sync/range/batch.js.map +1 -1
  191. package/lib/sync/range/chain.d.ts +19 -4
  192. package/lib/sync/range/chain.d.ts.map +1 -1
  193. package/lib/sync/range/chain.js +64 -11
  194. package/lib/sync/range/chain.js.map +1 -1
  195. package/lib/sync/range/range.d.ts.map +1 -1
  196. package/lib/sync/range/range.js +31 -9
  197. package/lib/sync/range/range.js.map +1 -1
  198. package/lib/sync/sync.d.ts.map +1 -1
  199. package/lib/sync/sync.js +13 -0
  200. package/lib/sync/sync.js.map +1 -1
  201. package/lib/sync/types.d.ts +34 -0
  202. package/lib/sync/types.d.ts.map +1 -1
  203. package/lib/sync/types.js +34 -0
  204. package/lib/sync/types.js.map +1 -1
  205. package/lib/sync/unknownBlock.d.ts +29 -1
  206. package/lib/sync/unknownBlock.d.ts.map +1 -1
  207. package/lib/sync/unknownBlock.js +738 -61
  208. package/lib/sync/unknownBlock.js.map +1 -1
  209. package/lib/sync/utils/downloadByRange.d.ts +67 -10
  210. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  211. package/lib/sync/utils/downloadByRange.js +211 -26
  212. package/lib/sync/utils/downloadByRange.js.map +1 -1
  213. package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
  214. package/lib/sync/utils/downloadByRoot.js +16 -2
  215. package/lib/sync/utils/downloadByRoot.js.map +1 -1
  216. package/lib/sync/utils/pendingBlocksTree.d.ts +0 -1
  217. package/lib/sync/utils/pendingBlocksTree.d.ts.map +1 -1
  218. package/lib/sync/utils/pendingBlocksTree.js +0 -9
  219. package/lib/sync/utils/pendingBlocksTree.js.map +1 -1
  220. package/lib/util/sszBytes.d.ts.map +1 -1
  221. package/lib/util/sszBytes.js +8 -6
  222. package/lib/util/sszBytes.js.map +1 -1
  223. package/package.json +16 -15
  224. package/src/api/impl/beacon/blocks/index.ts +21 -5
  225. package/src/api/impl/beacon/pool/index.ts +83 -1
  226. package/src/api/impl/debug/index.ts +0 -1
  227. package/src/api/impl/lodestar/index.ts +1 -1
  228. package/src/api/impl/validator/index.ts +82 -1
  229. package/src/chain/blocks/blockInput/blockInput.ts +4 -1
  230. package/src/chain/blocks/importBlock.ts +16 -48
  231. package/src/chain/blocks/importExecutionPayload.ts +76 -30
  232. package/src/chain/blocks/index.ts +71 -22
  233. package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +37 -3
  234. package/src/chain/blocks/payloadEnvelopeInput/types.ts +18 -0
  235. package/src/chain/blocks/payloadEnvelopeProcessor.ts +2 -2
  236. package/src/chain/blocks/types.ts +4 -3
  237. package/src/chain/blocks/utils/chainSegment.ts +114 -17
  238. package/src/chain/blocks/verifyBlock.ts +70 -9
  239. package/src/chain/blocks/verifyBlocksExecutionPayloads.ts +6 -4
  240. package/src/chain/blocks/verifyBlocksSanityChecks.ts +26 -7
  241. package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +16 -8
  242. package/src/chain/blocks/verifyPayloadsDataAvailability.ts +7 -4
  243. package/src/chain/blocks/writePayloadEnvelopeInputToDb.ts +8 -17
  244. package/src/chain/chain.ts +55 -10
  245. package/src/chain/emitter.ts +0 -11
  246. package/src/chain/errors/blockError.ts +4 -1
  247. package/src/chain/errors/executionPayloadBid.ts +6 -0
  248. package/src/chain/errors/index.ts +1 -0
  249. package/src/chain/errors/proposerPreferences.ts +47 -0
  250. package/src/chain/initState.ts +9 -1
  251. package/src/chain/interface.ts +9 -1
  252. package/src/chain/opPools/payloadAttestationPool.ts +29 -8
  253. package/src/chain/prepareNextSlot.ts +36 -14
  254. package/src/chain/produceBlock/produceBlockBody.ts +57 -14
  255. package/src/chain/regen/interface.ts +1 -0
  256. package/src/chain/regen/queued.ts +2 -7
  257. package/src/chain/regen/regen.ts +2 -7
  258. package/src/chain/seenCache/index.ts +1 -0
  259. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +89 -21
  260. package/src/chain/seenCache/seenProposerPreferences.ts +32 -0
  261. package/src/chain/validation/block.ts +1 -0
  262. package/src/chain/validation/executionPayloadBid.ts +25 -8
  263. package/src/chain/validation/proposerPreferences.ts +110 -0
  264. package/src/metrics/metrics/lodestar.ts +4 -0
  265. package/src/network/gossip/interface.ts +6 -0
  266. package/src/network/gossip/scoringParameters.ts +14 -1
  267. package/src/network/gossip/topic.ts +6 -0
  268. package/src/network/interface.ts +1 -0
  269. package/src/network/network.ts +11 -0
  270. package/src/network/processor/gossipHandlers.ts +53 -17
  271. package/src/network/processor/gossipQueues/index.ts +5 -0
  272. package/src/network/processor/index.ts +6 -5
  273. package/src/network/reqresp/handlers/beaconBlocksByRange.ts +14 -6
  274. package/src/network/reqresp/handlers/blobSidecarsByRange.ts +11 -5
  275. package/src/network/reqresp/handlers/dataColumnSidecarsByRange.ts +17 -5
  276. package/src/network/reqresp/handlers/executionPayloadEnvelopesByRange.ts +7 -4
  277. package/src/node/nodejs.ts +2 -2
  278. package/src/sync/constants.ts +4 -4
  279. package/src/sync/range/batch.ts +320 -67
  280. package/src/sync/range/chain.ts +89 -14
  281. package/src/sync/range/range.ts +34 -9
  282. package/src/sync/sync.ts +13 -1
  283. package/src/sync/types.ts +72 -0
  284. package/src/sync/unknownBlock.ts +928 -65
  285. package/src/sync/utils/downloadByRange.ts +378 -39
  286. package/src/sync/utils/downloadByRoot.ts +24 -2
  287. package/src/sync/utils/pendingBlocksTree.ts +0 -15
  288. package/src/util/sszBytes.ts +8 -6
@@ -1,17 +1,19 @@
1
1
  import {ChainForkConfig} from "@lodestar/config";
2
- import {ForkName, isForkPostDeneb, isForkPostFulu} from "@lodestar/params";
3
- import {Epoch, RootHex, Slot, phase0} from "@lodestar/types";
4
- import {LodestarError} from "@lodestar/utils";
2
+ import {ForkName, isForkPostDeneb, isForkPostFulu, isForkPostGloas} from "@lodestar/params";
3
+ import {Epoch, RootHex, SignedBeaconBlock, Slot, gloas, phase0} from "@lodestar/types";
4
+ import {LodestarError, byteArrayEquals, prettyPrintIndices, toRootHex} from "@lodestar/utils";
5
5
  import {isBlockInputColumns} from "../../chain/blocks/blockInput/blockInput.js";
6
6
  import {IBlockInput} from "../../chain/blocks/blockInput/types.js";
7
7
  import {isDaOutOfRange} from "../../chain/blocks/blockInput/utils.js";
8
+ import {PayloadEnvelopeInput} from "../../chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js";
8
9
  import {BlockError, BlockErrorCode} from "../../chain/errors/index.js";
10
+ import {ZERO_HASH} from "../../constants/constants.js";
9
11
  import {PeerSyncMeta} from "../../network/peers/peersData.js";
10
12
  import {IClock} from "../../util/clock.js";
11
13
  import {CustodyConfig} from "../../util/dataColumns.js";
12
14
  import {PeerIdStr} from "../../util/peerId.js";
13
15
  import {MAX_BATCH_DOWNLOAD_ATTEMPTS, MAX_BATCH_PROCESSING_ATTEMPTS} from "../constants.js";
14
- import {DownloadByRangeRequests} from "../utils/downloadByRange.js";
16
+ import {DownloadByRangeRequests, ParentPayloadCommitments} from "../utils/downloadByRange.js";
15
17
  import {getBatchSlotRange, hashBlocks} from "./utils/index.js";
16
18
 
17
19
  /**
@@ -46,25 +48,68 @@ export type Attempt = {
46
48
  export type AwaitingDownloadState = {
47
49
  status: BatchStatus.AwaitingDownload;
48
50
  blocks: IBlockInput[];
51
+ payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null;
49
52
  };
50
53
 
51
54
  export type DownloadSuccessState = {
52
55
  status: BatchStatus.AwaitingProcessing;
53
56
  blocks: IBlockInput[];
57
+ payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null;
54
58
  };
55
59
 
56
60
  export type BatchState =
57
61
  | AwaitingDownloadState
58
- | {status: BatchStatus.Downloading; peer: PeerIdStr; blocks: IBlockInput[]}
62
+ | {
63
+ status: BatchStatus.Downloading;
64
+ peer: PeerIdStr;
65
+ blocks: IBlockInput[];
66
+ payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null;
67
+ }
59
68
  | DownloadSuccessState
60
- | {status: BatchStatus.Processing; blocks: IBlockInput[]; attempt: Attempt}
61
- | {status: BatchStatus.AwaitingValidation; blocks: IBlockInput[]; attempt: Attempt};
69
+ | {
70
+ status: BatchStatus.Processing;
71
+ blocks: IBlockInput[];
72
+ payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null;
73
+ attempt: Attempt;
74
+ }
75
+ | {
76
+ status: BatchStatus.AwaitingValidation;
77
+ blocks: IBlockInput[];
78
+ payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null;
79
+ attempt: Attempt;
80
+ };
62
81
 
63
82
  export type BatchMetadata = {
83
+ // Batch-level slot window (always present)
64
84
  startEpoch: Epoch;
85
+ startSlot: Slot;
86
+ count: number;
65
87
  status: BatchStatus;
88
+
89
+ // Per-type outstanding request shapes; only present when that sub-request exists.
90
+ // Format: "startSlot=<n>,count=<n>" (plus ",cols=<indices>" for columns).
91
+ blocksReq?: string;
92
+ blobsReq?: string;
93
+ columnsReq?: string;
94
+ envelopesReq?: string;
95
+
96
+ // Retry counters
97
+ downloadAttempts: number;
98
+ processingAttempts: number;
99
+
100
+ // Cumulative peer attribution for failed attempts (only present when non-empty)
101
+ failedDownloadPeers?: string;
102
+ failedProcessingPeers?: string;
66
103
  };
67
104
 
105
+ function formatRangeReq(req: {startSlot: Slot; count: number}): string {
106
+ return `startSlot=${req.startSlot},count=${req.count}`;
107
+ }
108
+
109
+ function formatColumnsReq(req: {startSlot: Slot; count: number; columns: number[]}): string {
110
+ return `startSlot=${req.startSlot},count=${req.count},cols=${prettyPrintIndices(req.columns)}`;
111
+ }
112
+
68
113
  /**
69
114
  * Batches are downloaded at the first block of the epoch.
70
115
  *
@@ -85,7 +130,7 @@ export class Batch {
85
130
  /** Block, blob and column requests that are used to determine the best peer and are used in downloadByRange */
86
131
  requests: DownloadByRangeRequests;
87
132
  /** State of the batch. */
88
- state: BatchState = {status: BatchStatus.AwaitingDownload, blocks: []};
133
+ state: BatchState = {status: BatchStatus.AwaitingDownload, blocks: [], payloadEnvelopes: null};
89
134
  /** Peers that provided good data */
90
135
  goodPeers: PeerIdStr[] = [];
91
136
  /** The `Attempts` that have been made and failed to send us this batch. */
@@ -97,8 +142,18 @@ export class Batch {
97
142
  private readonly config: ChainForkConfig;
98
143
  private readonly clock: IClock;
99
144
  private readonly custodyConfig: CustodyConfig;
100
-
101
- constructor(startEpoch: Epoch, config: ChainForkConfig, clock: IClock, custodyConfig: CustodyConfig) {
145
+ private readonly isFirstBatchInChain: boolean;
146
+ private readonly latestBid: gloas.ExecutionPayloadBid | undefined;
147
+
148
+ constructor(
149
+ startEpoch: Epoch,
150
+ config: ChainForkConfig,
151
+ clock: IClock,
152
+ custodyConfig: CustodyConfig,
153
+ isFirstBatchInChain: boolean,
154
+ latestBid: gloas.ExecutionPayloadBid | undefined,
155
+ targetSlot: Slot
156
+ ) {
102
157
  this.config = config;
103
158
  this.clock = clock;
104
159
  this.custodyConfig = custodyConfig;
@@ -107,10 +162,40 @@ export class Batch {
107
162
  this.forkName = this.config.getForkName(startSlot);
108
163
  this.startEpoch = startEpoch;
109
164
  this.startSlot = startSlot;
110
- this.count = count;
165
+ this.count = Math.min(count, targetSlot - startSlot + 1);
166
+ this.isFirstBatchInChain = isFirstBatchInChain;
167
+ this.latestBid = latestBid;
111
168
  this.requests = this.getRequests([]);
112
169
  }
113
170
 
171
+ private shouldDownloadParentEnvelope(firstBlock?: SignedBeaconBlock): boolean {
172
+ if (!this.isFirstBatchInChain) return false;
173
+
174
+ if (this.startSlot === 0 || !isForkPostGloas(this.config.getForkName(this.startSlot - 1))) {
175
+ return false;
176
+ }
177
+
178
+ // we only know if we should download parent envelope if firstBlock is downloaded
179
+ if (firstBlock === undefined) return false;
180
+ if (this.latestBid === undefined) return false;
181
+ const firstBlockBidParentHash = (firstBlock.message.body as gloas.BeaconBlockBody).signedExecutionPayloadBid.message
182
+ .parentBlockHash;
183
+ return byteArrayEquals(firstBlockBidParentHash, this.latestBid.blockHash);
184
+ }
185
+
186
+ getParentPayloadCommitments(parentBlockRoot: Uint8Array): ParentPayloadCommitments {
187
+ if (this.latestBid === undefined) {
188
+ throw new Error(
189
+ `Coding error: getParentPayloadCommitments called without latestBid for parentBlockRoot=${toRootHex(parentBlockRoot)}`
190
+ );
191
+ }
192
+ return {
193
+ blockRoot: parentBlockRoot,
194
+ blockRootHex: toRootHex(parentBlockRoot),
195
+ kzgCommitments: this.latestBid.blobKzgCommitments,
196
+ };
197
+ }
198
+
114
199
  /**
115
200
  * Builds ByRange requests for block, blobs and columns
116
201
  */
@@ -129,37 +214,36 @@ export class Batch {
129
214
  count: this.count,
130
215
  step: 1,
131
216
  };
132
- if (isForkPostFulu(this.forkName) && withinValidRequestWindow) {
133
- return {
134
- blocksRequest,
135
- columnsRequest: {
136
- startSlot: this.startSlot,
137
- count: this.count,
138
- columns: this.custodyConfig.sampledColumns,
139
- },
140
- };
217
+ const requests: DownloadByRangeRequests = {blocksRequest};
218
+
219
+ // Post-Gloas envelopes are required for block processing, independent of DA retention window.
220
+ if (isForkPostGloas(this.forkName)) {
221
+ requests.envelopesRequest = {startSlot: this.startSlot, count: this.count};
141
222
  }
142
- if (isForkPostDeneb(this.forkName) && withinValidRequestWindow) {
143
- return {
144
- blocksRequest,
145
- blobsRequest: {
146
- startSlot: this.startSlot,
147
- count: this.count,
148
- },
223
+
224
+ if (isForkPostFulu(this.forkName) && withinValidRequestWindow) {
225
+ requests.columnsRequest = {
226
+ startSlot: this.startSlot,
227
+ count: this.count,
228
+ columns: this.custodyConfig.sampledColumns,
149
229
  };
230
+ } else if (isForkPostDeneb(this.forkName) && withinValidRequestWindow) {
231
+ requests.blobsRequest = {startSlot: this.startSlot, count: this.count};
150
232
  }
151
- return {
152
- blocksRequest,
153
- };
233
+
234
+ return requests;
154
235
  }
155
236
 
156
237
  // subsequent request where part of the epoch has already been downloaded. Need to figure out what is the beginning
157
238
  // of the range where download needs to resume
158
239
  let blockStartSlot = this.startSlot;
159
240
  let dataStartSlot = this.startSlot;
241
+ let envelopeStartSlot = this.startSlot;
160
242
  const neededColumns = new Set<number>();
243
+ const envelopesBySlot = this.state.payloadEnvelopes ?? new Map<Slot, PayloadEnvelopeInput>();
161
244
 
162
245
  // ensure blocks are in slot-wise order
246
+ const isPostGloas = isForkPostGloas(this.forkName);
163
247
  for (const blockInput of blocks) {
164
248
  const blockSlot = blockInput.slot;
165
249
  // check if block/data is present (hasBlock/hasAllData). If present then check if startSlot is the same as
@@ -175,14 +259,36 @@ export class Batch {
175
259
  if (blockInput.hasBlock() && blockStartSlot === blockSlot) {
176
260
  blockStartSlot = blockSlot + 1;
177
261
  }
178
- if (!blockInput.hasAllData()) {
179
- if (isBlockInputColumns(blockInput)) {
180
- for (const index of blockInput.getMissingSampledColumnMeta().missing) {
262
+
263
+ // Range sync uses hasComputedAllData (all sampled columns physically present), not hasAllData
264
+ // which flips at the reconstruction threshold. Sync never triggers reconstruction, so accepting
265
+ // a half-downloaded block here makes writeBlockInputToDb later block on waitForComputedAllData.
266
+ if (isPostGloas) {
267
+ // Post-Gloas: column data lives on PayloadEnvelopeInput, not on BlockInputNoData.
268
+ const payloadInput = envelopesBySlot.get(blockSlot);
269
+ if (blockInput.hasBlock() && envelopeStartSlot === blockSlot && payloadInput?.hasPayloadEnvelope()) {
270
+ envelopeStartSlot = blockSlot + 1;
271
+ }
272
+ if (payloadInput && !payloadInput.hasComputedAllData()) {
273
+ for (const index of payloadInput.getMissingSampledColumnMeta().missing) {
181
274
  neededColumns.add(index);
182
275
  }
276
+ } else if (payloadInput?.hasComputedAllData() && dataStartSlot === blockSlot) {
277
+ // Only advance dataStartSlot when we know columns for this slot are complete. If
278
+ // payloadInput is missing entirely we cannot tell, so stop here so the next round
279
+ // re-requests columns (and envelopes) starting at this slot.
280
+ dataStartSlot = blockSlot + 1;
281
+ }
282
+ } else {
283
+ if (isBlockInputColumns(blockInput) ? !blockInput.hasComputedAllData() : !blockInput.hasAllData()) {
284
+ if (isBlockInputColumns(blockInput)) {
285
+ for (const index of blockInput.getMissingSampledColumnMeta().missing) {
286
+ neededColumns.add(index);
287
+ }
288
+ }
289
+ } else if (dataStartSlot === blockSlot) {
290
+ dataStartSlot = blockSlot + 1;
183
291
  }
184
- } else if (dataStartSlot === blockSlot) {
185
- dataStartSlot = blockSlot + 1;
186
292
  }
187
293
  }
188
294
 
@@ -202,11 +308,15 @@ export class Batch {
202
308
  // range of 40 - 63, startSlot will be inclusive but subtraction will exclusive so need to + 1
203
309
  const count = endSlot - dataStartSlot + 1;
204
310
  if (isForkPostFulu(this.forkName) && withinValidRequestWindow) {
205
- requests.columnsRequest = {
206
- count,
207
- startSlot: dataStartSlot,
208
- columns: Array.from(neededColumns),
209
- };
311
+ // Skip the column re-request when we have no specific column indices outstanding.
312
+ // Peer rejects an empty `columns` list
313
+ if (neededColumns.size > 0) {
314
+ requests.columnsRequest = {
315
+ count,
316
+ startSlot: dataStartSlot,
317
+ columns: Array.from(neededColumns),
318
+ };
319
+ }
210
320
  } else if (isForkPostDeneb(this.forkName) && withinValidRequestWindow) {
211
321
  requests.blobsRequest = {
212
322
  count,
@@ -216,6 +326,43 @@ export class Batch {
216
326
  // dataSlot will still have a value but do not create a request for preDeneb forks
217
327
  }
218
328
 
329
+ if (isForkPostGloas(this.forkName) && envelopeStartSlot <= endSlot) {
330
+ requests.envelopesRequest = {
331
+ startSlot: envelopeStartSlot,
332
+ count: endSlot - envelopeStartSlot + 1,
333
+ };
334
+ }
335
+
336
+ // Only the first batch of a SyncChain may need the dangling-parent payload by-root.
337
+ if (blocks.length > 0 && this.shouldDownloadParentEnvelope(blocks[0].getBlock())) {
338
+ // shouldDownloadParentEnvelope() = true means there are at least 1 block
339
+ const parentRoot = blocks[0].getBlock().message.parentRoot;
340
+ if (!byteArrayEquals(parentRoot, ZERO_HASH)) {
341
+ const parentRootHex = toRootHex(parentRoot);
342
+ let parentPayloadInput: PayloadEnvelopeInput | undefined;
343
+ if (this.state.payloadEnvelopes) {
344
+ for (const pi of this.state.payloadEnvelopes.values()) {
345
+ if (pi.blockRootHex === parentRootHex) {
346
+ parentPayloadInput = pi;
347
+ break;
348
+ }
349
+ }
350
+ }
351
+
352
+ const needsEnvelope = !parentPayloadInput?.hasPayloadEnvelope();
353
+ const missingColumns = parentPayloadInput
354
+ ? parentPayloadInput.getMissingSampledColumnMeta().missing
355
+ : this.custodyConfig.sampledColumns;
356
+
357
+ if (needsEnvelope || missingColumns.length > 0) {
358
+ requests.parentPayloadRequest = {
359
+ ...(needsEnvelope ? {envelopeBlockRoot: parentRoot} : {}),
360
+ ...(missingColumns.length > 0 ? {blockRoot: parentRoot, columns: missingColumns} : {}),
361
+ };
362
+ }
363
+ }
364
+ }
365
+
219
366
  return requests;
220
367
  }
221
368
 
@@ -227,24 +374,28 @@ export class Batch {
227
374
  return this.requests;
228
375
  }
229
376
 
230
- // post-fulu we need to ensure that we only request columns that the peer has advertised
231
- const {columnsRequest} = this.requests;
232
- if (columnsRequest == null) {
233
- return this.requests;
234
- }
377
+ // post-fulu we need to ensure that we only request columns that the peer has advertised.
378
+ const {columnsRequest, parentPayloadRequest} = this.requests;
235
379
 
236
380
  const peerColumns = new Set(peer.custodyColumns ?? []);
237
- const requestedColumns = columnsRequest.columns.filter((c) => peerColumns.has(c));
238
- if (requestedColumns.length === columnsRequest.columns.length) {
239
- return this.requests;
240
- }
381
+ const filteredColumnsRequest =
382
+ columnsRequest != null ? columnsRequest.columns.filter((c) => peerColumns.has(c)) : null;
383
+ const parentColumns = parentPayloadRequest?.columns;
384
+ const filteredParentColumns = parentColumns != null ? parentColumns.filter((c) => peerColumns.has(c)) : null;
385
+
386
+ const updatedColumnRequest =
387
+ columnsRequest != null && filteredColumnsRequest != null
388
+ ? {columnsRequest: {...columnsRequest, columns: filteredColumnsRequest}}
389
+ : {};
390
+ const updatedParentPayloadRequest =
391
+ parentPayloadRequest != null && filteredParentColumns != null
392
+ ? {parentPayloadRequest: {...parentPayloadRequest, columns: filteredParentColumns}}
393
+ : {};
241
394
 
242
395
  return {
243
396
  ...this.requests,
244
- columnsRequest: {
245
- ...columnsRequest,
246
- columns: requestedColumns,
247
- },
397
+ ...updatedColumnRequest,
398
+ ...updatedParentPayloadRequest,
248
399
  };
249
400
  }
250
401
 
@@ -256,13 +407,36 @@ export class Batch {
256
407
  }
257
408
 
258
409
  getMetadata(): BatchMetadata {
259
- return {startEpoch: this.startEpoch, status: this.state.status};
410
+ const {blocksRequest, blobsRequest, columnsRequest, envelopesRequest} = this.requests;
411
+ const failedProcessingPeerList = this.failedProcessingAttempts.flatMap((a) => a.peers);
412
+ return {
413
+ startEpoch: this.startEpoch,
414
+ startSlot: this.startSlot,
415
+ count: this.count,
416
+ status: this.state.status,
417
+ ...(blocksRequest && {blocksReq: formatRangeReq(blocksRequest)}),
418
+ ...(blobsRequest && {blobsReq: formatRangeReq(blobsRequest)}),
419
+ ...(columnsRequest && {columnsReq: formatColumnsReq(columnsRequest)}),
420
+ ...(envelopesRequest && {envelopesReq: formatRangeReq(envelopesRequest)}),
421
+ downloadAttempts: this.failedDownloadAttempts.length,
422
+ processingAttempts: this.failedProcessingAttempts.length,
423
+ ...(this.failedDownloadAttempts.length > 0 && {
424
+ failedDownloadPeers: this.failedDownloadAttempts.join(","),
425
+ }),
426
+ ...(failedProcessingPeerList.length > 0 && {
427
+ failedProcessingPeers: failedProcessingPeerList.join(","),
428
+ }),
429
+ };
260
430
  }
261
431
 
262
432
  getBlocks(): IBlockInput[] {
263
433
  return this.state.blocks;
264
434
  }
265
435
 
436
+ getPayloadEnvelopes(): Map<Slot, PayloadEnvelopeInput> | null {
437
+ return this.state.payloadEnvelopes;
438
+ }
439
+
266
440
  /**
267
441
  * AwaitingDownload -> Downloading
268
442
  */
@@ -271,13 +445,22 @@ export class Batch {
271
445
  throw new BatchError(this.wrongStatusErrorType(BatchStatus.AwaitingDownload));
272
446
  }
273
447
 
274
- this.state = {status: BatchStatus.Downloading, peer, blocks: this.state.blocks};
448
+ this.state = {
449
+ status: BatchStatus.Downloading,
450
+ peer,
451
+ blocks: this.state.blocks,
452
+ payloadEnvelopes: this.state.payloadEnvelopes,
453
+ };
275
454
  }
276
455
 
277
456
  /**
278
457
  * Downloading -> AwaitingProcessing
279
458
  */
280
- downloadingSuccess(peer: PeerIdStr, blocks: IBlockInput[]): DownloadSuccessState {
459
+ downloadingSuccess(
460
+ peer: PeerIdStr,
461
+ blocks: IBlockInput[],
462
+ payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null
463
+ ): DownloadSuccessState {
281
464
  if (this.state.status !== BatchStatus.Downloading) {
282
465
  throw new BatchError(this.wrongStatusErrorType(BatchStatus.Downloading));
283
466
  }
@@ -291,7 +474,11 @@ export class Batch {
291
474
  const slots = new Set<number>();
292
475
  for (const block of blocks) {
293
476
  slots.add(block.slot);
294
- if (!block.hasBlockAndAllData()) {
477
+ const dataComplete = isBlockInputColumns(block)
478
+ ? // by_range needs to download all columns
479
+ block.hasBlock() && block.hasComputedAllData()
480
+ : block.hasBlockAndAllData();
481
+ if (!dataComplete) {
295
482
  allComplete = false;
296
483
  }
297
484
  }
@@ -305,11 +492,47 @@ export class Batch {
305
492
  status: this.state.status,
306
493
  });
307
494
  }
495
+ const newPayloadEnvelopes = payloadEnvelopes ?? this.state.payloadEnvelopes;
496
+
497
+ if (allComplete && isForkPostGloas(this.forkName)) {
498
+ for (const block of blocks) {
499
+ const payloadInput = newPayloadEnvelopes?.get(block.slot);
500
+ // by_range needs every block's envelope and all sampled columns.
501
+ if (!payloadInput?.hasPayloadEnvelope() || !payloadInput.hasComputedAllData()) {
502
+ allComplete = false;
503
+ break;
504
+ }
505
+ }
506
+ }
507
+
508
+ // First batch of a sync chain must additionally have the dangling-parent payload fully
509
+ // present, otherwise `processBlocks` will throw PARENT_PAYLOAD_UNKNOWN. The parent's
510
+ // `PayloadEnvelopeInput` is identified by `blockRootHex` matching `blocks[0].parentRoot`.
511
+ if (allComplete && blocks.length > 0 && this.shouldDownloadParentEnvelope(blocks[0].getBlock())) {
512
+ const parentRoot = blocks[0].getBlock().message.parentRoot;
513
+ // Genesis has no parent payload — nothing to wait for.
514
+ if (!byteArrayEquals(parentRoot, ZERO_HASH)) {
515
+ const parentRootHex = toRootHex(parentRoot);
516
+ let parentPayloadComplete = false;
517
+ if (newPayloadEnvelopes) {
518
+ for (const payloadInput of newPayloadEnvelopes.values()) {
519
+ if (payloadInput.blockRootHex === parentRootHex) {
520
+ parentPayloadComplete = payloadInput.hasPayloadEnvelope() && payloadInput.hasComputedAllData();
521
+ break;
522
+ }
523
+ }
524
+ }
525
+ if (!parentPayloadComplete) {
526
+ allComplete = false;
527
+ }
528
+ }
529
+ }
530
+
308
531
  if (allComplete) {
309
- this.state = {status: BatchStatus.AwaitingProcessing, blocks};
532
+ this.state = {status: BatchStatus.AwaitingProcessing, blocks, payloadEnvelopes: newPayloadEnvelopes};
310
533
  } else {
534
+ this.state = {status: BatchStatus.AwaitingDownload, blocks, payloadEnvelopes: newPayloadEnvelopes};
311
535
  this.requests = this.getRequests(blocks);
312
- this.state = {status: BatchStatus.AwaitingDownload, blocks};
313
536
  }
314
537
 
315
538
  return this.state as DownloadSuccessState;
@@ -328,25 +551,50 @@ export class Batch {
328
551
  throw new BatchError(this.errorType({code: BatchErrorCode.MAX_DOWNLOAD_ATTEMPTS}));
329
552
  }
330
553
 
331
- this.state = {status: BatchStatus.AwaitingDownload, blocks: this.state.blocks};
554
+ this.state = {
555
+ status: BatchStatus.AwaitingDownload,
556
+ blocks: this.state.blocks,
557
+ payloadEnvelopes: this.state.payloadEnvelopes,
558
+ };
559
+ }
560
+
561
+ /**
562
+ * Downloading -> AwaitingDownload (without counting as a failed attempt).
563
+ * Used when the peer rate-limited us — the request was never actually served.
564
+ */
565
+ downloadingRateLimited(): void {
566
+ if (this.state.status !== BatchStatus.Downloading) {
567
+ throw new BatchError(this.wrongStatusErrorType(BatchStatus.Downloading));
568
+ }
569
+
570
+ this.state = {
571
+ status: BatchStatus.AwaitingDownload,
572
+ blocks: this.state.blocks,
573
+ payloadEnvelopes: this.state.payloadEnvelopes,
574
+ };
332
575
  }
333
576
 
334
577
  /**
335
578
  * AwaitingProcessing -> Processing
336
579
  */
337
- startProcessing(): IBlockInput[] {
580
+ startProcessing(): {
581
+ blocks: IBlockInput[];
582
+ payloadEnvelopes: Map<Slot, PayloadEnvelopeInput> | null;
583
+ peers: PeerIdStr[];
584
+ } {
338
585
  if (this.state.status !== BatchStatus.AwaitingProcessing) {
339
586
  throw new BatchError(this.wrongStatusErrorType(BatchStatus.AwaitingProcessing));
340
587
  }
341
588
 
342
589
  const blocks = this.state.blocks;
590
+ const payloadEnvelopes = this.state.payloadEnvelopes;
343
591
  const hash = hashBlocks(blocks, this.config); // tracks blocks to report peer on processing error
344
592
  // Reset goodPeers in case another download attempt needs to be made. When Attempt is successful or not the peers
345
593
  // that the data came from will be handled by the Attempt that goes for processing
346
594
  const peers = this.goodPeers;
347
595
  this.goodPeers = [];
348
- this.state = {status: BatchStatus.Processing, blocks, attempt: {peers, hash}};
349
- return blocks;
596
+ this.state = {status: BatchStatus.Processing, blocks, payloadEnvelopes, attempt: {peers, hash}};
597
+ return {blocks, payloadEnvelopes, peers};
350
598
  }
351
599
 
352
600
  /**
@@ -357,7 +605,12 @@ export class Batch {
357
605
  throw new BatchError(this.wrongStatusErrorType(BatchStatus.Processing));
358
606
  }
359
607
 
360
- this.state = {status: BatchStatus.AwaitingValidation, blocks: this.state.blocks, attempt: this.state.attempt};
608
+ this.state = {
609
+ status: BatchStatus.AwaitingValidation,
610
+ blocks: this.state.blocks,
611
+ payloadEnvelopes: this.state.payloadEnvelopes,
612
+ attempt: this.state.attempt,
613
+ };
361
614
  }
362
615
 
363
616
  /**
@@ -408,7 +661,7 @@ export class Batch {
408
661
 
409
662
  // remove any downloaded blocks and re-attempt
410
663
  // TODO(fulu): need to remove the bad blocks from the SeenBlockInputCache
411
- this.state = {status: BatchStatus.AwaitingDownload, blocks: []};
664
+ this.state = {status: BatchStatus.AwaitingDownload, blocks: [], payloadEnvelopes: null};
412
665
  }
413
666
 
414
667
  private onProcessingError(attempt: Attempt): void {
@@ -419,12 +672,12 @@ export class Batch {
419
672
 
420
673
  // remove any downloaded blocks and re-attempt
421
674
  // TODO(fulu): need to remove the bad blocks from the SeenBlockInputCache
422
- this.state = {status: BatchStatus.AwaitingDownload, blocks: []};
675
+ this.state = {status: BatchStatus.AwaitingDownload, blocks: [], payloadEnvelopes: null};
423
676
  }
424
677
 
425
678
  /** Helper to construct typed BatchError. Stack traces are correct as the error is thrown above */
426
679
  private errorType(type: BatchErrorType): BatchErrorType & BatchErrorMetadata {
427
- return {...type, ...this.getMetadata()};
680
+ return {...type, startEpoch: this.startEpoch, status: this.state.status};
428
681
  }
429
682
 
430
683
  private wrongStatusErrorType(expectedStatus: BatchStatus): BatchErrorType & BatchErrorMetadata {