@lodestar/beacon-node 1.50.0-dev.7f24e06bb6 → 1.50.0-dev.82f05c43ff

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 (285) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +6 -1
  3. package/lib/api/impl/beacon/blocks/index.js.map +1 -1
  4. package/lib/api/impl/beacon/index.d.ts.map +1 -1
  5. package/lib/api/impl/beacon/index.js +13 -0
  6. package/lib/api/impl/beacon/index.js.map +1 -1
  7. package/lib/api/impl/beacon/pool/index.js +4 -4
  8. package/lib/api/impl/beacon/pool/index.js.map +1 -1
  9. package/lib/api/impl/beacon/state/index.d.ts.map +1 -1
  10. package/lib/api/impl/beacon/state/index.js +23 -3
  11. package/lib/api/impl/beacon/state/index.js.map +1 -1
  12. package/lib/api/impl/debug/index.d.ts.map +1 -1
  13. package/lib/api/impl/debug/index.js +26 -18
  14. package/lib/api/impl/debug/index.js.map +1 -1
  15. package/lib/api/impl/validator/index.d.ts +1 -0
  16. package/lib/api/impl/validator/index.d.ts.map +1 -1
  17. package/lib/api/impl/validator/index.js +23 -1
  18. package/lib/api/impl/validator/index.js.map +1 -1
  19. package/lib/chain/archiveStore/archiveStore.d.ts +6 -0
  20. package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
  21. package/lib/chain/archiveStore/archiveStore.js +18 -24
  22. package/lib/chain/archiveStore/archiveStore.js.map +1 -1
  23. package/lib/chain/archiveStore/historicalState/getHistoricalState.d.ts +2 -2
  24. package/lib/chain/archiveStore/historicalState/getHistoricalState.d.ts.map +1 -1
  25. package/lib/chain/archiveStore/historicalState/getHistoricalState.js +5 -7
  26. package/lib/chain/archiveStore/historicalState/getHistoricalState.js.map +1 -1
  27. package/lib/chain/archiveStore/historicalState/historicalStateRegen.js +1 -1
  28. package/lib/chain/archiveStore/historicalState/historicalStateRegen.js.map +1 -1
  29. package/lib/chain/archiveStore/historicalState/types.d.ts +2 -2
  30. package/lib/chain/archiveStore/historicalState/types.d.ts.map +1 -1
  31. package/lib/chain/archiveStore/historicalState/worker.js +1 -1
  32. package/lib/chain/archiveStore/historicalState/worker.js.map +1 -1
  33. package/lib/chain/archiveStore/interface.d.ts +1 -1
  34. package/lib/chain/archiveStore/interface.d.ts.map +1 -1
  35. package/lib/chain/archiveStore/utils/pruneHistory.d.ts +4 -1
  36. package/lib/chain/archiveStore/utils/pruneHistory.d.ts.map +1 -1
  37. package/lib/chain/archiveStore/utils/pruneHistory.js +5 -3
  38. package/lib/chain/archiveStore/utils/pruneHistory.js.map +1 -1
  39. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  40. package/lib/chain/blocks/importBlock.js +11 -3
  41. package/lib/chain/blocks/importBlock.js.map +1 -1
  42. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +2 -1
  43. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
  44. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  45. package/lib/chain/blocks/verifyBlock.js +1 -1
  46. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  47. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts +2 -1
  48. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts.map +1 -1
  49. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js +5 -4
  50. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js.map +1 -1
  51. package/lib/chain/chain.d.ts +9 -5
  52. package/lib/chain/chain.d.ts.map +1 -1
  53. package/lib/chain/chain.js +56 -21
  54. package/lib/chain/chain.js.map +1 -1
  55. package/lib/chain/emitter.d.ts +7 -1
  56. package/lib/chain/emitter.d.ts.map +1 -1
  57. package/lib/chain/emitter.js +5 -0
  58. package/lib/chain/emitter.js.map +1 -1
  59. package/lib/chain/errors/envelopeReconstructionError.d.ts +5 -0
  60. package/lib/chain/errors/envelopeReconstructionError.d.ts.map +1 -1
  61. package/lib/chain/errors/envelopeReconstructionError.js +2 -0
  62. package/lib/chain/errors/envelopeReconstructionError.js.map +1 -1
  63. package/lib/chain/errors/gossipValidation.d.ts +3 -1
  64. package/lib/chain/errors/gossipValidation.d.ts.map +1 -1
  65. package/lib/chain/errors/gossipValidation.js +2 -0
  66. package/lib/chain/errors/gossipValidation.js.map +1 -1
  67. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  68. package/lib/chain/forkChoice/index.js +2 -0
  69. package/lib/chain/forkChoice/index.js.map +1 -1
  70. package/lib/chain/initState.d.ts +2 -9
  71. package/lib/chain/initState.d.ts.map +1 -1
  72. package/lib/chain/initState.js +5 -38
  73. package/lib/chain/initState.js.map +1 -1
  74. package/lib/chain/interface.d.ts +3 -2
  75. package/lib/chain/interface.d.ts.map +1 -1
  76. package/lib/chain/opPools/aggregatedAttestationPool.d.ts +4 -2
  77. package/lib/chain/opPools/aggregatedAttestationPool.d.ts.map +1 -1
  78. package/lib/chain/opPools/aggregatedAttestationPool.js +30 -8
  79. package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
  80. package/lib/chain/opPools/opPool.d.ts +5 -4
  81. package/lib/chain/opPools/opPool.d.ts.map +1 -1
  82. package/lib/chain/opPools/opPool.js +62 -18
  83. package/lib/chain/opPools/opPool.js.map +1 -1
  84. package/lib/chain/opPools/proposerPreferencesPool.d.ts +4 -4
  85. package/lib/chain/opPools/proposerPreferencesPool.d.ts.map +1 -1
  86. package/lib/chain/opPools/proposerPreferencesPool.js +14 -11
  87. package/lib/chain/opPools/proposerPreferencesPool.js.map +1 -1
  88. package/lib/chain/opPools/utils.d.ts +4 -1
  89. package/lib/chain/opPools/utils.d.ts.map +1 -1
  90. package/lib/chain/opPools/utils.js +11 -1
  91. package/lib/chain/opPools/utils.js.map +1 -1
  92. package/lib/chain/options.d.ts +2 -1
  93. package/lib/chain/options.d.ts.map +1 -1
  94. package/lib/chain/options.js +1 -1
  95. package/lib/chain/options.js.map +1 -1
  96. package/lib/chain/prepareNextSlot.d.ts.map +1 -1
  97. package/lib/chain/prepareNextSlot.js +5 -2
  98. package/lib/chain/prepareNextSlot.js.map +1 -1
  99. package/lib/chain/produceBlock/computeNewStateRoot.js +1 -1
  100. package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
  101. package/lib/chain/produceBlock/produceBlockBody.d.ts +3 -1
  102. package/lib/chain/produceBlock/produceBlockBody.d.ts.map +1 -1
  103. package/lib/chain/produceBlock/produceBlockBody.js +6 -2
  104. package/lib/chain/produceBlock/produceBlockBody.js.map +1 -1
  105. package/lib/chain/regen/regen.d.ts +2 -0
  106. package/lib/chain/regen/regen.d.ts.map +1 -1
  107. package/lib/chain/regen/regen.js +10 -4
  108. package/lib/chain/regen/regen.js.map +1 -1
  109. package/lib/chain/seenCache/seenGossipBlockInput.d.ts +7 -0
  110. package/lib/chain/seenCache/seenGossipBlockInput.d.ts.map +1 -1
  111. package/lib/chain/seenCache/seenGossipBlockInput.js +21 -0
  112. package/lib/chain/seenCache/seenGossipBlockInput.js.map +1 -1
  113. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +9 -2
  114. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  115. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +23 -13
  116. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  117. package/lib/chain/shufflingCache.d.ts +1 -0
  118. package/lib/chain/shufflingCache.d.ts.map +1 -1
  119. package/lib/chain/shufflingCache.js +4 -0
  120. package/lib/chain/shufflingCache.js.map +1 -1
  121. package/lib/chain/validation/attesterSlashing.d.ts +4 -4
  122. package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
  123. package/lib/chain/validation/attesterSlashing.js +3 -0
  124. package/lib/chain/validation/attesterSlashing.js.map +1 -1
  125. package/lib/chain/validation/proposerSlashing.d.ts +3 -3
  126. package/lib/chain/validation/proposerSlashing.d.ts.map +1 -1
  127. package/lib/chain/validation/proposerSlashing.js +3 -0
  128. package/lib/chain/validation/proposerSlashing.js.map +1 -1
  129. package/lib/chain/validatorMonitor.d.ts +5 -1
  130. package/lib/chain/validatorMonitor.d.ts.map +1 -1
  131. package/lib/chain/validatorMonitor.js +64 -54
  132. package/lib/chain/validatorMonitor.js.map +1 -1
  133. package/lib/db/beacon.d.ts +2 -0
  134. package/lib/db/beacon.d.ts.map +1 -1
  135. package/lib/db/beacon.js +5 -0
  136. package/lib/db/beacon.js.map +1 -1
  137. package/lib/db/buckets.d.ts +2 -1
  138. package/lib/db/buckets.d.ts.map +1 -1
  139. package/lib/db/buckets.js +1 -0
  140. package/lib/db/buckets.js.map +1 -1
  141. package/lib/db/interface.d.ts +2 -0
  142. package/lib/db/interface.d.ts.map +1 -1
  143. package/lib/db/repositories/blockArchiveIndex.d.ts +2 -2
  144. package/lib/db/repositories/blockArchiveIndex.d.ts.map +1 -1
  145. package/lib/db/repositories/earliestAvailableSlot.d.ts +11 -0
  146. package/lib/db/repositories/earliestAvailableSlot.d.ts.map +1 -0
  147. package/lib/db/repositories/earliestAvailableSlot.js +19 -0
  148. package/lib/db/repositories/earliestAvailableSlot.js.map +1 -0
  149. package/lib/db/repositories/proposerSlashing.d.ts +1 -0
  150. package/lib/db/repositories/proposerSlashing.d.ts.map +1 -1
  151. package/lib/db/repositories/proposerSlashing.js +5 -1
  152. package/lib/db/repositories/proposerSlashing.js.map +1 -1
  153. package/lib/execution/engine/disabled.d.ts +0 -2
  154. package/lib/execution/engine/disabled.d.ts.map +1 -1
  155. package/lib/execution/engine/disabled.js +0 -6
  156. package/lib/execution/engine/disabled.js.map +1 -1
  157. package/lib/execution/engine/http.d.ts +1 -3
  158. package/lib/execution/engine/http.d.ts.map +1 -1
  159. package/lib/execution/engine/http.js +2 -17
  160. package/lib/execution/engine/http.js.map +1 -1
  161. package/lib/execution/engine/interface.d.ts +2 -4
  162. package/lib/execution/engine/interface.d.ts.map +1 -1
  163. package/lib/execution/engine/mock.d.ts +0 -2
  164. package/lib/execution/engine/mock.d.ts.map +1 -1
  165. package/lib/execution/engine/mock.js +0 -8
  166. package/lib/execution/engine/mock.js.map +1 -1
  167. package/lib/execution/engine/types.d.ts +0 -8
  168. package/lib/execution/engine/types.d.ts.map +1 -1
  169. package/lib/execution/engine/types.js.map +1 -1
  170. package/lib/index.d.ts +1 -1
  171. package/lib/index.d.ts.map +1 -1
  172. package/lib/index.js +1 -1
  173. package/lib/index.js.map +1 -1
  174. package/lib/metrics/metrics/lodestar.d.ts +1 -0
  175. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  176. package/lib/metrics/metrics/lodestar.js +4 -0
  177. package/lib/metrics/metrics/lodestar.js.map +1 -1
  178. package/lib/metrics/metrics.d.ts +7 -3
  179. package/lib/metrics/metrics.d.ts.map +1 -1
  180. package/lib/metrics/metrics.js +4 -4
  181. package/lib/metrics/metrics.js.map +1 -1
  182. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  183. package/lib/network/processor/gossipHandlers.js +66 -67
  184. package/lib/network/processor/gossipHandlers.js.map +1 -1
  185. package/lib/network/processor/gossipValidatorFn.d.ts +7 -3
  186. package/lib/network/processor/gossipValidatorFn.d.ts.map +1 -1
  187. package/lib/network/processor/gossipValidatorFn.js +7 -3
  188. package/lib/network/processor/gossipValidatorFn.js.map +1 -1
  189. package/lib/network/processor/index.d.ts +9 -0
  190. package/lib/network/processor/index.d.ts.map +1 -1
  191. package/lib/network/processor/index.js +77 -10
  192. package/lib/network/processor/index.js.map +1 -1
  193. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.d.ts.map +1 -1
  194. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js +41 -26
  195. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js.map +1 -1
  196. package/lib/node/nodejs.d.ts +3 -1
  197. package/lib/node/nodejs.d.ts.map +1 -1
  198. package/lib/node/nodejs.js +27 -4
  199. package/lib/node/nodejs.js.map +1 -1
  200. package/lib/sync/range/batch.d.ts +6 -0
  201. package/lib/sync/range/batch.d.ts.map +1 -1
  202. package/lib/sync/range/batch.js +11 -0
  203. package/lib/sync/range/batch.js.map +1 -1
  204. package/lib/sync/range/chain.d.ts.map +1 -1
  205. package/lib/sync/range/chain.js +6 -1
  206. package/lib/sync/range/chain.js.map +1 -1
  207. package/lib/sync/range/range.d.ts.map +1 -1
  208. package/lib/sync/range/range.js +50 -18
  209. package/lib/sync/range/range.js.map +1 -1
  210. package/lib/sync/unknownBlock.d.ts +14 -7
  211. package/lib/sync/unknownBlock.d.ts.map +1 -1
  212. package/lib/sync/unknownBlock.js +132 -66
  213. package/lib/sync/unknownBlock.js.map +1 -1
  214. package/lib/sync/utils/downloadByRange.d.ts +8 -0
  215. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  216. package/lib/sync/utils/downloadByRange.js +32 -9
  217. package/lib/sync/utils/downloadByRange.js.map +1 -1
  218. package/lib/util/execution.d.ts +11 -11
  219. package/lib/util/execution.d.ts.map +1 -1
  220. package/lib/util/execution.js +6 -2
  221. package/lib/util/execution.js.map +1 -1
  222. package/package.json +17 -17
  223. package/src/api/impl/beacon/blocks/index.ts +7 -4
  224. package/src/api/impl/beacon/index.ts +15 -0
  225. package/src/api/impl/beacon/pool/index.ts +4 -4
  226. package/src/api/impl/beacon/state/index.ts +31 -3
  227. package/src/api/impl/debug/index.ts +28 -19
  228. package/src/api/impl/validator/index.ts +24 -2
  229. package/src/chain/archiveStore/archiveStore.ts +26 -26
  230. package/src/chain/archiveStore/historicalState/getHistoricalState.ts +5 -7
  231. package/src/chain/archiveStore/historicalState/historicalStateRegen.ts +1 -1
  232. package/src/chain/archiveStore/historicalState/types.ts +2 -2
  233. package/src/chain/archiveStore/historicalState/worker.ts +1 -2
  234. package/src/chain/archiveStore/interface.ts +1 -1
  235. package/src/chain/archiveStore/utils/pruneHistory.ts +9 -4
  236. package/src/chain/blocks/importBlock.ts +13 -3
  237. package/src/chain/blocks/payloadEnvelopeInput/types.ts +2 -1
  238. package/src/chain/blocks/verifyBlock.ts +1 -0
  239. package/src/chain/blocks/verifyBlocksStateTransitionOnly.ts +6 -3
  240. package/src/chain/chain.ts +76 -23
  241. package/src/chain/emitter.ts +7 -1
  242. package/src/chain/errors/envelopeReconstructionError.ts +3 -0
  243. package/src/chain/errors/gossipValidation.ts +2 -0
  244. package/src/chain/forkChoice/index.ts +2 -0
  245. package/src/chain/initState.ts +8 -60
  246. package/src/chain/interface.ts +3 -2
  247. package/src/chain/opPools/aggregatedAttestationPool.ts +34 -10
  248. package/src/chain/opPools/opPool.ts +91 -18
  249. package/src/chain/opPools/proposerPreferencesPool.ts +14 -10
  250. package/src/chain/opPools/utils.ts +31 -3
  251. package/src/chain/options.ts +3 -3
  252. package/src/chain/prepareNextSlot.ts +6 -3
  253. package/src/chain/produceBlock/computeNewStateRoot.ts +1 -1
  254. package/src/chain/produceBlock/produceBlockBody.ts +8 -1
  255. package/src/chain/regen/regen.ts +12 -4
  256. package/src/chain/seenCache/seenGossipBlockInput.ts +23 -0
  257. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +31 -13
  258. package/src/chain/shufflingCache.ts +5 -0
  259. package/src/chain/validation/attesterSlashing.ts +7 -4
  260. package/src/chain/validation/proposerSlashing.ts +7 -4
  261. package/src/chain/validatorMonitor.ts +75 -57
  262. package/src/db/beacon.ts +5 -0
  263. package/src/db/buckets.ts +1 -0
  264. package/src/db/interface.ts +2 -0
  265. package/src/db/repositories/earliestAvailableSlot.ts +19 -0
  266. package/src/db/repositories/proposerSlashing.ts +6 -1
  267. package/src/execution/engine/disabled.ts +0 -8
  268. package/src/execution/engine/http.ts +1 -30
  269. package/src/execution/engine/interface.ts +2 -6
  270. package/src/execution/engine/mock.ts +1 -19
  271. package/src/execution/engine/types.ts +0 -10
  272. package/src/index.ts +1 -1
  273. package/src/metrics/metrics/lodestar.ts +4 -0
  274. package/src/metrics/metrics.ts +21 -6
  275. package/src/network/processor/gossipHandlers.ts +97 -80
  276. package/src/network/processor/gossipValidatorFn.ts +13 -3
  277. package/src/network/processor/index.ts +89 -10
  278. package/src/network/reqresp/handlers/executionPayloadEnvelopesByRoot.ts +42 -28
  279. package/src/node/nodejs.ts +35 -3
  280. package/src/sync/range/batch.ts +12 -0
  281. package/src/sync/range/chain.ts +7 -1
  282. package/src/sync/range/range.ts +50 -18
  283. package/src/sync/unknownBlock.ts +156 -71
  284. package/src/sync/utils/downloadByRange.ts +47 -8
  285. package/src/util/execution.ts +17 -9
@@ -6,6 +6,7 @@ import {toRootHex} from "@lodestar/utils";
6
6
  import {EnvelopeReconstructionError} from "../../../chain/errors/index.js";
7
7
  import {IBeaconChain} from "../../../chain/index.js";
8
8
  import {IBeaconDb} from "../../../db/index.js";
9
+ import {MAX_BODIES_PER_REQUEST} from "../../../util/execution.js";
9
10
  import {ExecutionPayloadEnvelopesByRootRequest} from "../../../util/types.js";
10
11
  import {prettyPrintPeerId} from "../../util.js";
11
12
 
@@ -19,10 +20,15 @@ export async function* onExecutionPayloadEnvelopesByRoot(
19
20
  // The gloas req/resp spec uses MIN_EPOCHS_FOR_BLOCK_REQUESTS to define the minimum range peers MUST serve.
20
21
  // Archival nodes may still serve older retained payloads to allow genesis sync.
21
22
 
22
- // Resolve slots first so archived header envelopes are rebuilt in one EL batch, not one call per root
23
+ // Resolve slots first so archived envelopes can be reconstructed in EL batches.
24
+ // Duplicate roots are served once, since each archived envelope costs an EL fetch and a rebuild.
23
25
  const requests: {blockSlot: Slot; blockRootHex: RootHex}[] = [];
26
+ const seenRoots = new Set<RootHex>();
24
27
  for (const root of requestBody) {
25
28
  const rootHex = toRootHex(root);
29
+ if (seenRoots.has(rootHex)) continue;
30
+ seenRoots.add(rootHex);
31
+
26
32
  const block = chain.forkChoice.getBlockHexDefaultStatus(rootHex);
27
33
  // If the block is not in fork choice, it may be finalized. Attempt to find its slot in block archive
28
34
  const slot = block ? block.slot : await db.blockArchive.getSlotByRoot(root);
@@ -41,35 +47,43 @@ export async function* onExecutionPayloadEnvelopesByRoot(
41
47
  requests.push({blockSlot: slot, blockRootHex: rootHex});
42
48
  }
43
49
 
44
- let envelopesBytes: (Uint8Array | null)[];
45
- try {
46
- // by-root allows omission, so a mismatched envelope is left out rather than failing the response
47
- envelopesBytes = await chain.getSerializedExecutionPayloadEnvelopes(requests, "omit");
48
- } catch (e) {
49
- if (e instanceof EnvelopeReconstructionError) {
50
- throw new ResponseError(
51
- RespStatus.RESOURCE_UNAVAILABLE,
52
- `Failed to reconstruct archived envelopes: ${e.message}`
53
- );
50
+ // Yield between EL batches so the first response does not wait for the entire request.
51
+ let yielded = 0;
52
+ for (let i = 0; i < requests.length; i += MAX_BODIES_PER_REQUEST) {
53
+ const batch = requests.slice(i, i + MAX_BODIES_PER_REQUEST);
54
+ let envelopesBytes: (Uint8Array | null)[];
55
+ try {
56
+ // By-root allows omission, so an envelope that cannot be rebuilt is left out rather than failing the response.
57
+ envelopesBytes = await chain.getSerializedExecutionPayloadEnvelopes(batch, "omit");
58
+ } catch (e) {
59
+ if (e instanceof EnvelopeReconstructionError) {
60
+ // By-root permits partial responses, so an EL failure can end the response here.
61
+ if (yielded > 0) return;
62
+ throw new ResponseError(
63
+ RespStatus.RESOURCE_UNAVAILABLE,
64
+ `Failed to reconstruct archived envelopes: ${e.message}`
65
+ );
66
+ }
67
+ throw e;
54
68
  }
55
- throw e;
56
- }
57
69
 
58
- for (let i = 0; i < requests.length; i++) {
59
- const {blockSlot, blockRootHex} = requests[i];
60
- const envelopeBytes = envelopesBytes[i];
61
- if (envelopeBytes) {
62
- yield {
63
- data: envelopeBytes,
64
- boundary: chain.config.getForkBoundaryAtEpoch(computeEpochAtSlot(blockSlot)),
65
- };
66
- } else {
67
- chain.logger.debug("Cannot serve ExecutionPayloadEnvelopesByRoot: envelope not found", {
68
- slot: blockSlot,
69
- root: blockRootHex,
70
- peer: prettyPrintPeerId(peerId),
71
- client: peerClient,
72
- });
70
+ for (let j = 0; j < batch.length; j++) {
71
+ const {blockSlot, blockRootHex} = batch[j];
72
+ const envelopeBytes = envelopesBytes[j];
73
+ if (envelopeBytes) {
74
+ yielded++;
75
+ yield {
76
+ data: envelopeBytes,
77
+ boundary: chain.config.getForkBoundaryAtEpoch(computeEpochAtSlot(blockSlot)),
78
+ };
79
+ } else {
80
+ chain.logger.debug("Cannot serve ExecutionPayloadEnvelopesByRoot: envelope not found", {
81
+ slot: blockSlot,
82
+ root: blockRootHex,
83
+ peer: prettyPrintPeerId(peerId),
84
+ client: peerClient,
85
+ });
86
+ }
73
87
  }
74
88
  }
75
89
  }
@@ -1,6 +1,12 @@
1
1
  import {setMaxListeners} from "node:events";
2
2
  import {PrivateKey} from "@libp2p/interface";
3
3
  import {Registry} from "prom-client";
4
+ import {
5
+ init as initNativeMetrics,
6
+ registerLocalValidator as registerNativeLocalValidator,
7
+ scrapeMetrics as scrapeNativeMetrics,
8
+ unregisterLocalValidator as unregisterNativeLocalValidator,
9
+ } from "@chainsafe/lodestar-z/metrics";
4
10
  import {type PubkeyCache} from "@chainsafe/lodestar-z/pubkeys";
5
11
  import {hasher} from "@chainsafe/persistent-merkle-tree";
6
12
  import {BeaconApiMethods} from "@lodestar/api/beacon/server";
@@ -8,6 +14,7 @@ import {BeaconConfig} from "@lodestar/config";
8
14
  import type {LoggerNode} from "@lodestar/logger/node";
9
15
  import {ZERO_HASH_HEX} from "@lodestar/params";
10
16
  import {IBeaconStateView, isStatePostBellatrix, isStatePostGloas} from "@lodestar/state-transition";
17
+ import {Slot} from "@lodestar/types";
11
18
  import {sleep, toRootHex} from "@lodestar/utils";
12
19
  import {ProcessShutdownCallback} from "@lodestar/validator";
13
20
  import {BeaconRestApiServer, getApi} from "../api/index.js";
@@ -55,6 +62,7 @@ export type BeaconNodeInitModules = {
55
62
  peerStoreDir?: string;
56
63
  anchorState: IBeaconStateView;
57
64
  isAnchorStateFinalized: boolean;
65
+ earliestAvailableSlot: Slot;
58
66
  metricsRegistries?: Registry[];
59
67
  };
60
68
 
@@ -153,6 +161,7 @@ export class BeaconNode {
153
161
  peerStoreDir,
154
162
  anchorState,
155
163
  isAnchorStateFinalized,
164
+ earliestAvailableSlot,
156
165
  metricsRegistries = [],
157
166
  }: BeaconNodeInitModules): Promise<T> {
158
167
  if (hasher.name !== "hashtree") {
@@ -171,7 +180,13 @@ export class BeaconNode {
171
180
  // monitoring relies on metrics data
172
181
  opts.monitoring.endpoint
173
182
  ) {
174
- metrics = createMetrics(opts.metrics, anchorState.genesisTime, metricsRegistries);
183
+ if (opts.chain.nativeStateTransition) {
184
+ initNativeMetrics();
185
+ }
186
+
187
+ metrics = createMetrics(opts.metrics, anchorState.genesisTime, metricsRegistries, {
188
+ includeStateTransitionMetrics: !opts.chain.nativeStateTransition,
189
+ });
175
190
  initBeaconMetrics(metrics, anchorState);
176
191
  // Since the db is instantiated before this, metrics must be injected manually afterwards
177
192
  db.setMetrics(metrics.db, metrics.flatFileStore);
@@ -185,7 +200,13 @@ export class BeaconNode {
185
200
  config,
186
201
  anchorState.genesisTime,
187
202
  logger.child({module: LoggerModule.vmon}),
188
- opts.validatorMonitor
203
+ opts.validatorMonitor,
204
+ opts.chain.nativeStateTransition
205
+ ? {
206
+ registerLocalValidator: registerNativeLocalValidator,
207
+ unregisterLocalValidator: unregisterNativeLocalValidator,
208
+ }
209
+ : null
189
210
  )
190
211
  : null;
191
212
 
@@ -248,6 +269,7 @@ export class BeaconNode {
248
269
  validatorMonitor,
249
270
  anchorState,
250
271
  isAnchorStateFinalized,
272
+ earliestAvailableSlot,
251
273
  executionEngine: initializeExecutionEngine(executionEngineOpts, {
252
274
  metrics,
253
275
  signal,
@@ -303,7 +325,17 @@ export class BeaconNode {
303
325
  const metricsServer = opts.metrics.enabled
304
326
  ? await getHttpMetricsServer(opts.metrics, {
305
327
  register: (metrics as Metrics).register,
306
- getOtherMetrics: async () => Promise.all([network.scrapeMetrics(), chain.archiveStore.scrapeMetrics()]),
328
+ getOtherMetrics: async () => {
329
+ const otherMetrics = await Promise.all([network.scrapeMetrics(), chain.archiveStore.scrapeMetrics()]);
330
+ if (opts.chain.nativeStateTransition) {
331
+ try {
332
+ otherMetrics.push(scrapeNativeMetrics());
333
+ } catch (e) {
334
+ logger.warn("Failed to scrape native state-transition metrics", {}, e as Error);
335
+ }
336
+ }
337
+ return otherMetrics;
338
+ },
307
339
  logger: logger.child({module: LoggerModule.metrics}),
308
340
  })
309
341
  : null;
@@ -224,6 +224,7 @@ export class Batch {
224
224
  return {
225
225
  blockRoot: parentBlockRoot,
226
226
  blockRootHex: toRootHex(parentBlockRoot),
227
+ blockHash: this.latestBid.blockHash,
227
228
  kzgCommitments: this.latestBid.blobKzgCommitments,
228
229
  };
229
230
  }
@@ -773,6 +774,7 @@ export class Batch {
773
774
  // remove any downloaded blocks and re-attempt
774
775
  // TODO(fulu): need to remove the bad blocks from the SeenBlockInputCache
775
776
  this.state = {status: BatchStatus.AwaitingDownload, blocks: [], payloadEnvelopes: null};
777
+ this.resetRequests();
776
778
  }
777
779
 
778
780
  private onProcessingError(attempt: FailedAttempt): void {
@@ -784,6 +786,16 @@ export class Batch {
784
786
  // remove any downloaded blocks and re-attempt
785
787
  // TODO(fulu): need to remove the bad blocks from the SeenBlockInputCache
786
788
  this.state = {status: BatchStatus.AwaitingDownload, blocks: [], payloadEnvelopes: null};
789
+ this.resetRequests();
790
+ }
791
+
792
+ /**
793
+ * After a partial download `requests` only cover the data still missing from the downloaded blocks,
794
+ * e.g. a single column. Once those blocks are dropped, request the whole batch again, otherwise
795
+ * every peer fails the retry for lack of blocks to validate the data against.
796
+ */
797
+ private resetRequests(): void {
798
+ this.requests = this.getRequests([]);
787
799
  }
788
800
 
789
801
  /** Helper to construct typed BatchError. Stack traces are correct as the error is thrown above */
@@ -225,6 +225,9 @@ export class SyncChain {
225
225
  Math.floor((localFinalizedEpoch - this.lastEpochWithProcessBlocks) / EPOCHS_PER_BATCH) * EPOCHS_PER_BATCH;
226
226
  this.advanceChain(lastEpochWithProcessBlocksAligned);
227
227
 
228
+ // stopSyncing() cleared the retry timer, but peers can still be in rate limit backoff
229
+ this.scheduleRateLimitBackoffRetry();
230
+
228
231
  // Potentially download new batches and process pending
229
232
  this.triggerBatchDownloader();
230
233
  this.triggerBatchProcessor();
@@ -417,8 +420,10 @@ export class SyncChain {
417
420
  this.rateLimitBackoffTimeout = setTimeout(
418
421
  () => {
419
422
  this.rateLimitBackoffTimeout = undefined;
420
- this.triggerBatchDownloader();
423
+ // Must run before the downloader, it drops expired peers without triggering a download. If it ran
424
+ // after, a backoff expiring in between would leave the peer idle with no retry scheduled.
421
425
  this.scheduleRateLimitBackoffRetry();
426
+ this.triggerBatchDownloader();
422
427
  },
423
428
  Math.max(0, retryAt - now)
424
429
  );
@@ -581,6 +586,7 @@ export class SyncChain {
581
586
  case DownloadByRangeErrorCode.OUT_OF_RANGE_BLOCKS:
582
587
  case DownloadByRangeErrorCode.PARENT_ROOT_MISMATCH:
583
588
  case DownloadByRangeErrorCode.INVALID_ENVELOPE_BEACON_BLOCK_ROOT:
589
+ case DownloadByRangeErrorCode.INVALID_ENVELOPE_BLOCK_HASH:
584
590
  case DownloadByRangeErrorCode.INVALID_CHAIN_SEGMENT:
585
591
  case BlobSidecarErrorCode.INCLUSION_PROOF_INVALID:
586
592
  case BlobSidecarErrorCode.INVALID_KZG_PROOF_BATCH:
@@ -5,6 +5,7 @@ import {IBeaconStateViewGloas, computeStartSlotAtEpoch, isStatePostGloas} from "
5
5
  import {Epoch, Status, fulu} from "@lodestar/types";
6
6
  import {Logger, prettyPrintIndices, toRootHex} from "@lodestar/utils";
7
7
  import {IBlockInput} from "../../chain/blocks/blockInput/types.js";
8
+ import {PayloadError, PayloadErrorCode} from "../../chain/blocks/importExecutionPayload.js";
8
9
  import {AttestationImportOpt, ImportBlockOpts} from "../../chain/blocks/index.js";
9
10
  import {assertLinearChainSegment} from "../../chain/blocks/utils/chainSegment.js";
10
11
  import {BlockError} from "../../chain/errors/index.js";
@@ -207,22 +208,50 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
207
208
  blsVerifyOnMainThread: false,
208
209
  };
209
210
 
210
- if (this.opts?.disableProcessAsChainSegment) {
211
- // Should only be used for debugging or testing
212
- for (const block of blocks) {
213
- await this.chain.processBlock(block, flags);
214
- const payloadEnvelope = payloadEnvelopes?.get(block.slot);
215
- if (payloadEnvelope?.hasPayloadEnvelope()) {
216
- await this.chain.processExecutionPayload(payloadEnvelope);
211
+ try {
212
+ if (this.opts?.disableProcessAsChainSegment) {
213
+ // Should only be used for debugging or testing
214
+ for (const block of blocks) {
215
+ await this.chain.processBlock(block, flags);
216
+ const payloadEnvelope = payloadEnvelopes?.get(block.slot);
217
+ if (payloadEnvelope?.hasPayloadEnvelope()) {
218
+ await this.chain.processExecutionPayload(payloadEnvelope);
219
+ }
220
+ }
221
+ } else {
222
+ const {orphaned, skipped} = await this.chain.processChainSegment(blocks, payloadEnvelopes, flags);
223
+ // We log orphaned payloads to work with different clients
224
+ // in the future, consider applying penalties in certain conditions
225
+ // make sure the payload source was from range sync in that case
226
+ for (const {slot, payloadEnvelopeInput} of orphaned) {
227
+ const {peerIdStr, source} = payloadEnvelopeInput.getPayloadEnvelopeSource();
228
+ let client = "unknown";
229
+ if (peerIdStr !== undefined) {
230
+ try {
231
+ client = this.getConnectedPeerSyncMeta(peerIdStr).client;
232
+ } catch {
233
+ // peer disconnected since serving the envelope, keep "unknown"
234
+ }
235
+ }
236
+ this.logger.debug("Orphaned payload envelope in range sync batch", {
237
+ slot,
238
+ root: payloadEnvelopeInput.blockRootHex,
239
+ peer: peerIdStr ?? "unknown",
240
+ source,
241
+ client,
242
+ skipped,
243
+ });
217
244
  }
218
245
  }
219
- } else {
220
- const {orphaned, skipped} = await this.chain.processChainSegment(blocks, payloadEnvelopes, flags);
221
- // We log orphaned payloads to work with different clients
222
- // in the future, consider applying penalties in certain conditions
223
- // make sure the payload source was from range sync in that case
224
- for (const {slot, payloadEnvelopeInput} of orphaned) {
225
- const {peerIdStr, source} = payloadEnvelopeInput.getPayloadEnvelopeSource();
246
+ } catch (e) {
247
+ if (
248
+ e instanceof PayloadError &&
249
+ (e.type.code === PayloadErrorCode.INVALID_SIGNATURE ||
250
+ e.type.code === PayloadErrorCode.ENVELOPE_VERIFICATION_ERROR ||
251
+ e.type.code === PayloadErrorCode.EXECUTION_ENGINE_INVALID)
252
+ ) {
253
+ const {payloadInput} = e;
254
+ const {peerIdStr, source} = payloadInput.getPayloadEnvelopeSource();
226
255
  let client = "unknown";
227
256
  if (peerIdStr !== undefined) {
228
257
  try {
@@ -231,15 +260,18 @@ export class RangeSync extends (EventEmitter as {new (): RangeSyncEmitter}) {
231
260
  // peer disconnected since serving the envelope, keep "unknown"
232
261
  }
233
262
  }
234
- this.logger.debug("Orphaned payload envelope in range sync batch", {
235
- slot,
236
- root: payloadEnvelopeInput.blockRootHex,
263
+ this.logger.debug("Removing invalid payload envelope in range sync batch", {
264
+ slot: payloadInput.slot,
265
+ root: payloadInput.blockRootHex,
237
266
  peer: peerIdStr ?? "unknown",
238
267
  source,
239
268
  client,
240
- skipped,
269
+ code: e.type.code,
241
270
  });
271
+ // The batch is downloaded again, it would otherwise reuse the cached envelope and fail the same way
272
+ this.chain.seenPayloadEnvelopeInputCache.removeInvalid(payloadInput);
242
273
  }
274
+ throw e;
243
275
  }
244
276
  };
245
277