@lodestar/beacon-node 1.50.0-dev.70314c9caa → 1.50.0-dev.79bf6381f8

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 (210) 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/state/index.d.ts.map +1 -1
  8. package/lib/api/impl/beacon/state/index.js +23 -3
  9. package/lib/api/impl/beacon/state/index.js.map +1 -1
  10. package/lib/api/impl/debug/index.d.ts.map +1 -1
  11. package/lib/api/impl/debug/index.js +26 -18
  12. package/lib/api/impl/debug/index.js.map +1 -1
  13. package/lib/api/impl/validator/index.d.ts +1 -0
  14. package/lib/api/impl/validator/index.d.ts.map +1 -1
  15. package/lib/api/impl/validator/index.js +23 -1
  16. package/lib/api/impl/validator/index.js.map +1 -1
  17. package/lib/chain/archiveStore/archiveStore.d.ts +5 -0
  18. package/lib/chain/archiveStore/archiveStore.d.ts.map +1 -1
  19. package/lib/chain/archiveStore/archiveStore.js +14 -24
  20. package/lib/chain/archiveStore/archiveStore.js.map +1 -1
  21. package/lib/chain/archiveStore/historicalState/getHistoricalState.d.ts +2 -2
  22. package/lib/chain/archiveStore/historicalState/getHistoricalState.d.ts.map +1 -1
  23. package/lib/chain/archiveStore/historicalState/getHistoricalState.js +5 -7
  24. package/lib/chain/archiveStore/historicalState/getHistoricalState.js.map +1 -1
  25. package/lib/chain/archiveStore/historicalState/historicalStateRegen.js +1 -1
  26. package/lib/chain/archiveStore/historicalState/historicalStateRegen.js.map +1 -1
  27. package/lib/chain/archiveStore/historicalState/types.d.ts +2 -2
  28. package/lib/chain/archiveStore/historicalState/types.d.ts.map +1 -1
  29. package/lib/chain/archiveStore/historicalState/worker.js +1 -1
  30. package/lib/chain/archiveStore/historicalState/worker.js.map +1 -1
  31. package/lib/chain/archiveStore/interface.d.ts +1 -1
  32. package/lib/chain/archiveStore/interface.d.ts.map +1 -1
  33. package/lib/chain/archiveStore/utils/pruneHistory.d.ts +1 -1
  34. package/lib/chain/archiveStore/utils/pruneHistory.d.ts.map +1 -1
  35. package/lib/chain/archiveStore/utils/pruneHistory.js +2 -1
  36. package/lib/chain/archiveStore/utils/pruneHistory.js.map +1 -1
  37. package/lib/chain/blocks/importBlock.d.ts.map +1 -1
  38. package/lib/chain/blocks/importBlock.js +7 -3
  39. package/lib/chain/blocks/importBlock.js.map +1 -1
  40. package/lib/chain/blocks/verifyBlock.d.ts.map +1 -1
  41. package/lib/chain/blocks/verifyBlock.js +1 -1
  42. package/lib/chain/blocks/verifyBlock.js.map +1 -1
  43. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts +2 -1
  44. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts.map +1 -1
  45. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js +5 -4
  46. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js.map +1 -1
  47. package/lib/chain/chain.d.ts +9 -5
  48. package/lib/chain/chain.d.ts.map +1 -1
  49. package/lib/chain/chain.js +53 -18
  50. package/lib/chain/chain.js.map +1 -1
  51. package/lib/chain/emitter.d.ts +7 -1
  52. package/lib/chain/emitter.d.ts.map +1 -1
  53. package/lib/chain/emitter.js +5 -0
  54. package/lib/chain/emitter.js.map +1 -1
  55. package/lib/chain/errors/envelopeReconstructionError.d.ts +5 -0
  56. package/lib/chain/errors/envelopeReconstructionError.d.ts.map +1 -1
  57. package/lib/chain/errors/envelopeReconstructionError.js +2 -0
  58. package/lib/chain/errors/envelopeReconstructionError.js.map +1 -1
  59. package/lib/chain/forkChoice/index.d.ts.map +1 -1
  60. package/lib/chain/forkChoice/index.js +2 -0
  61. package/lib/chain/forkChoice/index.js.map +1 -1
  62. package/lib/chain/interface.d.ts +3 -2
  63. package/lib/chain/interface.d.ts.map +1 -1
  64. package/lib/chain/opPools/aggregatedAttestationPool.d.ts +4 -2
  65. package/lib/chain/opPools/aggregatedAttestationPool.d.ts.map +1 -1
  66. package/lib/chain/opPools/aggregatedAttestationPool.js +30 -8
  67. package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
  68. package/lib/chain/opPools/proposerPreferencesPool.d.ts +4 -4
  69. package/lib/chain/opPools/proposerPreferencesPool.d.ts.map +1 -1
  70. package/lib/chain/opPools/proposerPreferencesPool.js +14 -11
  71. package/lib/chain/opPools/proposerPreferencesPool.js.map +1 -1
  72. package/lib/chain/options.d.ts +2 -1
  73. package/lib/chain/options.d.ts.map +1 -1
  74. package/lib/chain/options.js +1 -1
  75. package/lib/chain/options.js.map +1 -1
  76. package/lib/chain/produceBlock/computeNewStateRoot.js +1 -1
  77. package/lib/chain/produceBlock/computeNewStateRoot.js.map +1 -1
  78. package/lib/chain/regen/regen.d.ts +2 -0
  79. package/lib/chain/regen/regen.d.ts.map +1 -1
  80. package/lib/chain/regen/regen.js +10 -4
  81. package/lib/chain/regen/regen.js.map +1 -1
  82. package/lib/chain/seenCache/seenGossipBlockInput.d.ts +7 -0
  83. package/lib/chain/seenCache/seenGossipBlockInput.d.ts.map +1 -1
  84. package/lib/chain/seenCache/seenGossipBlockInput.js +21 -0
  85. package/lib/chain/seenCache/seenGossipBlockInput.js.map +1 -1
  86. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +3 -2
  87. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  88. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +13 -13
  89. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  90. package/lib/chain/shufflingCache.d.ts +1 -0
  91. package/lib/chain/shufflingCache.d.ts.map +1 -1
  92. package/lib/chain/shufflingCache.js +4 -0
  93. package/lib/chain/shufflingCache.js.map +1 -1
  94. package/lib/chain/validatorMonitor.d.ts +5 -1
  95. package/lib/chain/validatorMonitor.d.ts.map +1 -1
  96. package/lib/chain/validatorMonitor.js +64 -54
  97. package/lib/chain/validatorMonitor.js.map +1 -1
  98. package/lib/db/beacon.d.ts +2 -0
  99. package/lib/db/beacon.d.ts.map +1 -1
  100. package/lib/db/beacon.js +3 -0
  101. package/lib/db/beacon.js.map +1 -1
  102. package/lib/db/buckets.d.ts +2 -1
  103. package/lib/db/buckets.d.ts.map +1 -1
  104. package/lib/db/buckets.js +1 -0
  105. package/lib/db/buckets.js.map +1 -1
  106. package/lib/db/interface.d.ts +2 -0
  107. package/lib/db/interface.d.ts.map +1 -1
  108. package/lib/db/repositories/blockArchiveIndex.d.ts +2 -2
  109. package/lib/db/repositories/blockArchiveIndex.d.ts.map +1 -1
  110. package/lib/db/repositories/earliestAvailableSlot.d.ts +11 -0
  111. package/lib/db/repositories/earliestAvailableSlot.d.ts.map +1 -0
  112. package/lib/db/repositories/earliestAvailableSlot.js +19 -0
  113. package/lib/db/repositories/earliestAvailableSlot.js.map +1 -0
  114. package/lib/execution/engine/disabled.d.ts +0 -2
  115. package/lib/execution/engine/disabled.d.ts.map +1 -1
  116. package/lib/execution/engine/disabled.js +0 -6
  117. package/lib/execution/engine/disabled.js.map +1 -1
  118. package/lib/execution/engine/http.d.ts +1 -3
  119. package/lib/execution/engine/http.d.ts.map +1 -1
  120. package/lib/execution/engine/http.js +2 -17
  121. package/lib/execution/engine/http.js.map +1 -1
  122. package/lib/execution/engine/interface.d.ts +2 -4
  123. package/lib/execution/engine/interface.d.ts.map +1 -1
  124. package/lib/execution/engine/mock.d.ts +0 -2
  125. package/lib/execution/engine/mock.d.ts.map +1 -1
  126. package/lib/execution/engine/mock.js +0 -8
  127. package/lib/execution/engine/mock.js.map +1 -1
  128. package/lib/execution/engine/types.d.ts +0 -8
  129. package/lib/execution/engine/types.d.ts.map +1 -1
  130. package/lib/execution/engine/types.js.map +1 -1
  131. package/lib/metrics/metrics/lodestar.d.ts +1 -0
  132. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  133. package/lib/metrics/metrics/lodestar.js +4 -0
  134. package/lib/metrics/metrics/lodestar.js.map +1 -1
  135. package/lib/metrics/metrics.d.ts +7 -3
  136. package/lib/metrics/metrics.d.ts.map +1 -1
  137. package/lib/metrics/metrics.js +4 -4
  138. package/lib/metrics/metrics.js.map +1 -1
  139. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  140. package/lib/network/processor/gossipHandlers.js +59 -63
  141. package/lib/network/processor/gossipHandlers.js.map +1 -1
  142. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js +1 -1
  143. package/lib/network/reqresp/handlers/executionPayloadEnvelopesByRoot.js.map +1 -1
  144. package/lib/node/nodejs.d.ts +3 -1
  145. package/lib/node/nodejs.d.ts.map +1 -1
  146. package/lib/node/nodejs.js +27 -4
  147. package/lib/node/nodejs.js.map +1 -1
  148. package/lib/sync/range/batch.d.ts +6 -0
  149. package/lib/sync/range/batch.d.ts.map +1 -1
  150. package/lib/sync/range/batch.js +10 -0
  151. package/lib/sync/range/batch.js.map +1 -1
  152. package/lib/sync/range/chain.d.ts.map +1 -1
  153. package/lib/sync/range/chain.js +5 -1
  154. package/lib/sync/range/chain.js.map +1 -1
  155. package/lib/sync/unknownBlock.d.ts +5 -2
  156. package/lib/sync/unknownBlock.d.ts.map +1 -1
  157. package/lib/sync/unknownBlock.js +44 -20
  158. package/lib/sync/unknownBlock.js.map +1 -1
  159. package/lib/util/execution.d.ts +9 -11
  160. package/lib/util/execution.d.ts.map +1 -1
  161. package/lib/util/execution.js +5 -1
  162. package/lib/util/execution.js.map +1 -1
  163. package/package.json +17 -17
  164. package/src/api/impl/beacon/blocks/index.ts +7 -4
  165. package/src/api/impl/beacon/index.ts +15 -0
  166. package/src/api/impl/beacon/state/index.ts +31 -3
  167. package/src/api/impl/debug/index.ts +28 -19
  168. package/src/api/impl/validator/index.ts +24 -2
  169. package/src/chain/archiveStore/archiveStore.ts +19 -25
  170. package/src/chain/archiveStore/historicalState/getHistoricalState.ts +5 -7
  171. package/src/chain/archiveStore/historicalState/historicalStateRegen.ts +1 -1
  172. package/src/chain/archiveStore/historicalState/types.ts +2 -2
  173. package/src/chain/archiveStore/historicalState/worker.ts +1 -2
  174. package/src/chain/archiveStore/interface.ts +1 -1
  175. package/src/chain/archiveStore/utils/pruneHistory.ts +4 -1
  176. package/src/chain/blocks/importBlock.ts +9 -3
  177. package/src/chain/blocks/verifyBlock.ts +1 -0
  178. package/src/chain/blocks/verifyBlocksStateTransitionOnly.ts +6 -3
  179. package/src/chain/chain.ts +73 -20
  180. package/src/chain/emitter.ts +7 -1
  181. package/src/chain/errors/envelopeReconstructionError.ts +3 -0
  182. package/src/chain/forkChoice/index.ts +2 -0
  183. package/src/chain/interface.ts +3 -2
  184. package/src/chain/opPools/aggregatedAttestationPool.ts +34 -10
  185. package/src/chain/opPools/proposerPreferencesPool.ts +14 -10
  186. package/src/chain/options.ts +3 -3
  187. package/src/chain/produceBlock/computeNewStateRoot.ts +1 -1
  188. package/src/chain/regen/regen.ts +12 -4
  189. package/src/chain/seenCache/seenGossipBlockInput.ts +23 -0
  190. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +20 -13
  191. package/src/chain/shufflingCache.ts +5 -0
  192. package/src/chain/validatorMonitor.ts +75 -57
  193. package/src/db/beacon.ts +3 -0
  194. package/src/db/buckets.ts +1 -0
  195. package/src/db/interface.ts +2 -0
  196. package/src/db/repositories/earliestAvailableSlot.ts +19 -0
  197. package/src/execution/engine/disabled.ts +0 -8
  198. package/src/execution/engine/http.ts +1 -30
  199. package/src/execution/engine/interface.ts +2 -6
  200. package/src/execution/engine/mock.ts +1 -19
  201. package/src/execution/engine/types.ts +0 -10
  202. package/src/metrics/metrics/lodestar.ts +4 -0
  203. package/src/metrics/metrics.ts +21 -6
  204. package/src/network/processor/gossipHandlers.ts +90 -76
  205. package/src/network/reqresp/handlers/executionPayloadEnvelopesByRoot.ts +1 -1
  206. package/src/node/nodejs.ts +35 -3
  207. package/src/sync/range/batch.ts +11 -0
  208. package/src/sync/range/chain.ts +6 -1
  209. package/src/sync/unknownBlock.ts +57 -21
  210. package/src/util/execution.ts +16 -8
package/src/db/buckets.ts CHANGED
@@ -72,6 +72,7 @@ export enum Bucket {
72
72
 
73
73
  gloas_executionPayloadEnvelope = 59, // GLOAS BeaconBlockRoot -> SignedExecutionPayloadEnvelope
74
74
  gloas_executionPayloadEnvelopeArchive = 60, // GLOAS Slot -> SignedExecutionPayloadEnvelope, or 0x00 + SignedExecutionPayloadHeaderEnvelope
75
+ earliestAvailableSlot = 61, // singleton -> Slot
75
76
  }
76
77
 
77
78
  export function getBucketNameByValue<T extends Bucket>(enumValue: T): keyof typeof Bucket {
@@ -3,6 +3,7 @@ import {Slot} from "@lodestar/types";
3
3
  import type {IDataColumnStore} from "./dataColumnStore.js";
4
4
  import type {FlatFileStoreMetrics} from "./flatFileStore/metrics.js";
5
5
  import {CheckpointStateRepository} from "./repositories/checkpointState.js";
6
+ import {EarliestAvailableSlotRepository} from "./repositories/earliestAvailableSlot.js";
6
7
  import {
7
8
  AttesterSlashingRepository,
8
9
  BLSToExecutionChangeRepository,
@@ -46,6 +47,7 @@ export interface IBeaconDb {
46
47
  stateArchive: StateArchiveRepository;
47
48
  // checkpoint states
48
49
  checkpointState: CheckpointStateRepository;
50
+ earliestAvailableSlot: EarliestAvailableSlotRepository;
49
51
 
50
52
  // op pool
51
53
  voluntaryExit: VoluntaryExitRepository;
@@ -0,0 +1,19 @@
1
+ import {Db, encodeKey} from "@lodestar/db";
2
+ import {Slot, ssz} from "@lodestar/types";
3
+ import {Bucket, getBucketNameByValue} from "../buckets.js";
4
+
5
+ export class EarliestAvailableSlotRepository {
6
+ private readonly key = encodeKey(Bucket.earliestAvailableSlot, 0);
7
+ private readonly opts = {bucketId: getBucketNameByValue(Bucket.earliestAvailableSlot)};
8
+
9
+ constructor(private readonly db: Db) {}
10
+
11
+ async get(): Promise<Slot | null> {
12
+ const bytes = await this.db.get(this.key, this.opts);
13
+ return bytes === null ? null : ssz.Slot.deserialize(bytes);
14
+ }
15
+
16
+ async set(slot: Slot): Promise<void> {
17
+ await this.db.put(this.key, ssz.Slot.serialize(slot), this.opts);
18
+ }
19
+ }
@@ -21,18 +21,10 @@ export class ExecutionEngineDisabled implements IExecutionEngine {
21
21
  throw Error("Execution engine disabled");
22
22
  }
23
23
 
24
- getPayloadBodiesByHash(): Promise<never> {
25
- throw Error("Execution engine disabled");
26
- }
27
-
28
24
  getPayloadBodiesByHashV2(): Promise<never> {
29
25
  throw Error("Execution engine disabled");
30
26
  }
31
27
 
32
- getPayloadBodiesByRange(): Promise<never> {
33
- throw Error("Execution engine disabled");
34
- }
35
-
36
28
  getBlobs(): Promise<never> {
37
29
  throw Error("Execution engine disabled");
38
30
  }
@@ -31,13 +31,11 @@ import {
31
31
  BLOB_AND_PROOF_V2_RPC_BYTES,
32
32
  EngineApiRpcParamTypes,
33
33
  EngineApiRpcReturnTypes,
34
- ExecutionPayloadBody,
35
34
  ExecutionPayloadBodyV2,
36
35
  assertReqSizeLimit,
37
36
  deserializeBlobAndProofs,
38
37
  deserializeBlobAndProofsV2,
39
38
  deserializeBlobAndProofsV2IntoBytes,
40
- deserializeExecutionPayloadBody,
41
39
  deserializeExecutionPayloadBodyV2,
42
40
  parseExecutionPayload,
43
41
  serializeBeaconBlockRoot,
@@ -46,7 +44,7 @@ import {
46
44
  serializePayloadAttributes,
47
45
  serializeVersionedHashes,
48
46
  } from "./types.js";
49
- import {bytesToData, getExecutionEngineState, numToQuantity} from "./utils.js";
47
+ import {bytesToData, getExecutionEngineState} from "./utils.js";
50
48
 
51
49
  export type ExecutionEngineModules = {
52
50
  signal: AbortSignal;
@@ -114,7 +112,6 @@ const notifyNewPayloadOpts: ReqOpts = {routeId: "notifyNewPayload"};
114
112
  const forkchoiceUpdatedV1Opts: ReqOpts = {routeId: "forkchoiceUpdated"};
115
113
  const getPayloadOpts: ReqOpts = {routeId: "getPayload"};
116
114
  const getPayloadBodiesByHashOpts: ReqOpts = {routeId: "getPayloadBodiesByHash"};
117
- const getPayloadBodiesByRangeOpts: ReqOpts = {routeId: "getPayloadBodiesByRange"};
118
115
  const getBlobsV1Opts: ReqOpts = {routeId: "getBlobsV1"};
119
116
  const getBlobsV2Opts: ReqOpts = {routeId: "getBlobsV2"};
120
117
  const getClientVersionOpts: ReqOpts = {routeId: "getClientVersion"};
@@ -468,16 +465,6 @@ export class ExecutionEngineHttp implements IExecutionEngine {
468
465
  this.payloadIdCache.prune();
469
466
  }
470
467
 
471
- async getPayloadBodiesByHash(_fork: ForkName, blockHashes: RootHex[]): Promise<(ExecutionPayloadBody | null)[]> {
472
- const method = "engine_getPayloadBodiesByHashV1";
473
- assertReqSizeLimit(blockHashes.length, 32);
474
- const response = await this.rpc.fetchWithRetries<
475
- EngineApiRpcReturnTypes[typeof method],
476
- EngineApiRpcParamTypes[typeof method]
477
- >({method, params: [blockHashes]}, getPayloadBodiesByHashOpts);
478
- return response.map(deserializeExecutionPayloadBody);
479
- }
480
-
481
468
  async getPayloadBodiesByHashV2(blockHashes: RootHex[]): Promise<(ExecutionPayloadBodyV2 | null)[]> {
482
469
  const method = "engine_getPayloadBodiesByHashV2";
483
470
  assertReqSizeLimit(blockHashes.length, 32);
@@ -488,22 +475,6 @@ export class ExecutionEngineHttp implements IExecutionEngine {
488
475
  return response.map(deserializeExecutionPayloadBodyV2);
489
476
  }
490
477
 
491
- async getPayloadBodiesByRange(
492
- _fork: ForkName,
493
- startBlockNumber: number,
494
- blockCount: number
495
- ): Promise<(ExecutionPayloadBody | null)[]> {
496
- const method = "engine_getPayloadBodiesByRangeV1";
497
- assertReqSizeLimit(blockCount, 32);
498
- const start = numToQuantity(startBlockNumber);
499
- const count = numToQuantity(blockCount);
500
- const response = await this.rpc.fetchWithRetries<
501
- EngineApiRpcReturnTypes[typeof method],
502
- EngineApiRpcParamTypes[typeof method]
503
- >({method, params: [start, count]}, getPayloadBodiesByRangeOpts);
504
- return response.map(deserializeExecutionPayloadBody);
505
- }
506
-
507
478
  async getBlobs(
508
479
  fork: ForkPostFulu,
509
480
  versionedHashes: VersionedHashes,
@@ -13,7 +13,7 @@ import {BlobsBundle, ExecutionPayload, ExecutionRequests, Root, RootHex, Wei, ca
13
13
  import {BlobAndProof} from "@lodestar/types/deneb";
14
14
  import {BlobAndProofV2} from "@lodestar/types/fulu";
15
15
  import {PayloadId, PayloadIdCache, WithdrawalV1} from "./payloadIdCache.js";
16
- import {ExecutionPayloadBody, ExecutionPayloadBodyV2} from "./types.js";
16
+ import {ExecutionPayloadBodyV2} from "./types.js";
17
17
  import {DATA} from "./utils.js";
18
18
 
19
19
  export {PayloadIdCache, type PayloadId, type WithdrawalV1};
@@ -170,13 +170,9 @@ export interface IExecutionEngine {
170
170
  shouldOverrideBuilder?: boolean;
171
171
  }>;
172
172
 
173
- getPayloadBodiesByHash(fork: ForkName, blockHash: DATA[]): Promise<(ExecutionPayloadBody | null)[]>;
174
-
175
- /** Amsterdam: like V1 but also returns the block access list (null if the EL no longer has it) */
173
+ /** Amsterdam: payload bodies including the block access list (null if the EL no longer has it) */
176
174
  getPayloadBodiesByHashV2(blockHash: DATA[]): Promise<(ExecutionPayloadBodyV2 | null)[]>;
177
175
 
178
- getPayloadBodiesByRange(fork: ForkName, start: number, count: number): Promise<(ExecutionPayloadBody | null)[]>;
179
-
180
176
  getBlobs(
181
177
  fork: ForkPostFulu,
182
178
  versionedHashes: VersionedHashes,
@@ -22,7 +22,6 @@ import {
22
22
  BlobsBundleRpc,
23
23
  EngineApiRpcParamTypes,
24
24
  EngineApiRpcReturnTypes,
25
- ExecutionPayloadBodyRpc,
26
25
  ExecutionPayloadBodyV2Rpc,
27
26
  ExecutionPayloadRpc,
28
27
  ExecutionRequestsRpc,
@@ -50,7 +49,7 @@ type ExecutionBlock = {
50
49
  blockHash: RootHex;
51
50
  timestamp: number;
52
51
  blockNumber: number;
53
- /** Bodies as received via newPayload, served back by engine_getPayloadBodiesByHash{V1,V2} */
52
+ /** Bodies as received via newPayload, served back by engine_getPayloadBodiesByHashV2 */
54
53
  body: ExecutionPayloadBodyV2Rpc;
55
54
  };
56
55
 
@@ -148,23 +147,13 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend {
148
147
  engine_getPayloadV4: this.getPayloadV5.bind(this),
149
148
  engine_getPayloadV5: this.getPayloadV5.bind(this),
150
149
  engine_getPayloadV6: this.getPayloadV5.bind(this),
151
- engine_getPayloadBodiesByHashV1: this.getPayloadBodiesByHash.bind(this),
152
150
  engine_getPayloadBodiesByHashV2: this.getPayloadBodiesByHashV2.bind(this),
153
- engine_getPayloadBodiesByRangeV1: this.getPayloadBodiesByRange.bind(this),
154
151
  engine_getClientVersionV1: this.getClientVersionV1.bind(this),
155
152
  engine_getBlobsV1: this.getBlobs.bind(this),
156
153
  engine_getBlobsV2: this.getBlobsV2.bind(this),
157
154
  };
158
155
  }
159
156
 
160
- private getPayloadBodiesByHash(
161
- blockHashes: EngineApiRpcParamTypes["engine_getPayloadBodiesByHashV1"][0]
162
- ): EngineApiRpcReturnTypes["engine_getPayloadBodiesByHashV1"] {
163
- return this.getPayloadBodiesByHashV2(blockHashes).map((body) =>
164
- body ? {transactions: body.transactions, withdrawals: body.withdrawals} : null
165
- );
166
- }
167
-
168
157
  private getPayloadBodiesByHashV2(
169
158
  blockHashes: EngineApiRpcParamTypes["engine_getPayloadBodiesByHashV2"][0]
170
159
  ): EngineApiRpcReturnTypes["engine_getPayloadBodiesByHashV2"] {
@@ -172,13 +161,6 @@ export class ExecutionEngineMockBackend implements JsonRpcBackend {
172
161
  return blockHashes.map((hash) => this.validBlocks.get(hash)?.body ?? null);
173
162
  }
174
163
 
175
- private getPayloadBodiesByRange(
176
- _start: EngineApiRpcParamTypes["engine_getPayloadBodiesByRangeV1"][0],
177
- _count: EngineApiRpcParamTypes["engine_getPayloadBodiesByRangeV1"][1]
178
- ): EngineApiRpcReturnTypes["engine_getPayloadBodiesByRangeV1"] {
179
- return [] as ExecutionPayloadBodyRpc[];
180
- }
181
-
182
164
  /**
183
165
  * Mock manipulator to add predefined responses before execution engine client calls
184
166
  */
@@ -88,15 +88,8 @@ export type EngineApiRpcParamTypes = {
88
88
  /**
89
89
  * 1. Array of DATA - Array of block_hash field values of the ExecutionPayload structure
90
90
  * */
91
- engine_getPayloadBodiesByHashV1: DATA[][];
92
91
  engine_getPayloadBodiesByHashV2: DATA[][];
93
92
 
94
- /**
95
- * 1. start: QUANTITY, 64 bits - Starting block number
96
- * 2. count: QUANTITY, 64 bits - Number of blocks to return
97
- */
98
- engine_getPayloadBodiesByRangeV1: [start: QUANTITY, count: QUANTITY];
99
-
100
93
  /**
101
94
  * Object - Instance of ClientVersion
102
95
  */
@@ -148,11 +141,8 @@ export type EngineApiRpcReturnTypes = {
148
141
  engine_getPayloadV5: ExecutionPayloadResponse;
149
142
  engine_getPayloadV6: ExecutionPayloadResponse;
150
143
 
151
- engine_getPayloadBodiesByHashV1: (ExecutionPayloadBodyRpc | null)[];
152
144
  engine_getPayloadBodiesByHashV2: (ExecutionPayloadBodyV2Rpc | null)[];
153
145
 
154
- engine_getPayloadBodiesByRangeV1: (ExecutionPayloadBodyRpc | null)[];
155
-
156
146
  engine_getClientVersionV1: ClientVersionRpc[];
157
147
 
158
148
  engine_getBlobsV1: (BlobAndProofRpc | null)[];
@@ -1281,6 +1281,10 @@ export function createLodestarMetrics(
1281
1281
  name: "lodestar_oppool_aggregated_attestation_pool_packed_attestations_seen_committees_total",
1282
1282
  help: "Total number of committees for which all members are seen when producing packed attestations",
1283
1283
  }),
1284
+ missingShufflingCommittees: register.gauge({
1285
+ name: "lodestar_oppool_aggregated_attestation_pool_packed_attestations_missing_shuffling_committees_total",
1286
+ help: "Total number of committees skipped due to missing shuffling when producing packed attestations",
1287
+ }),
1284
1288
  },
1285
1289
  },
1286
1290
  attestationPool: {
@@ -9,27 +9,42 @@ import {RegistryMetricCreator} from "./utils/registryMetricCreator.js";
9
9
 
10
10
  export type Metrics = BeaconMetrics &
11
11
  ForkChoiceMetrics &
12
- BeaconStateTransitionMetrics &
13
- LodestarMetrics & {register: RegistryMetricCreator; close: () => void};
12
+ LodestarMetrics & {
13
+ /** Null when we use native state transition metrics instead */
14
+ stateTransition: BeaconStateTransitionMetrics | null;
15
+ register: RegistryMetricCreator;
16
+ close: () => void;
17
+ };
18
+
19
+ export type CreateMetricsOptions = {
20
+ /*
21
+ * Toggle inclusion of state transition metrics.
22
+ *
23
+ * False when native state transition is used, so we
24
+ * can grab metrics from the native implementation instead.
25
+ * */
26
+ includeStateTransitionMetrics?: boolean;
27
+ collectNodeMetrics?: boolean;
28
+ };
14
29
 
15
30
  export function createMetrics(
16
31
  opts: MetricsOptions,
17
32
  genesisTime: number,
18
33
  externalRegistries: Registry[] = [],
19
- {collectNodeMetrics = true}: {collectNodeMetrics?: boolean} = {}
34
+ createOpts: CreateMetricsOptions = {}
20
35
  ): Metrics {
21
36
  const register = new RegistryMetricCreator();
22
37
  const beacon = createBeaconMetrics(register);
23
38
  const forkChoice = getForkChoiceMetrics(register);
24
39
  const lodestar = createLodestarMetrics(register, opts.metadata, genesisTime);
25
- const stateTransition = getMetrics(register);
40
+ const stateTransition = createOpts.includeStateTransitionMetrics === false ? null : getMetrics(register);
26
41
 
27
42
  const onUnhandledRejection = (_error: unknown): void => {
28
43
  lodestar.unhandledPromiseRejections.inc();
29
44
  };
30
45
  process.on("unhandledRejection", onUnhandledRejection);
31
46
 
32
- const nodeJsMetricsClose = collectNodeMetrics ? collectNodeJSMetrics(register) : (): void => {};
47
+ const nodeJsMetricsClose = createOpts.collectNodeMetrics === false ? (): void => {} : collectNodeJSMetrics(register);
33
48
  const close = (): void => {
34
49
  process.removeListener("unhandledRejection", onUnhandledRejection);
35
50
  nodeJsMetricsClose();
@@ -46,7 +61,7 @@ export function createMetrics(
46
61
  ...beacon,
47
62
  ...forkChoice,
48
63
  ...lodestar,
49
- ...stateTransition,
64
+ stateTransition,
50
65
  register,
51
66
  close,
52
67
  };
@@ -12,9 +12,10 @@ import {
12
12
  isForkPostElectra,
13
13
  isForkPostGloas,
14
14
  } from "@lodestar/params";
15
- import {computeTimeAtSlot} from "@lodestar/state-transition";
15
+ import {computeTimeAtSlot, signedBlockToSignedHeader} from "@lodestar/state-transition";
16
16
  import {
17
17
  Root,
18
+ RootHex,
18
19
  SignedBeaconBlock,
19
20
  SingleAttestation,
20
21
  Slot,
@@ -78,6 +79,7 @@ import {
78
79
  validateGossipSyncCommittee,
79
80
  validateGossipVoluntaryExit,
80
81
  validateSyncCommitteeGossipContributionAndProof,
82
+ verifyBlockProposerSignature,
81
83
  } from "../../chain/validation/index.js";
82
84
  import {validateLightClientFinalityUpdate} from "../../chain/validation/lightClientFinalityUpdate.js";
83
85
  import {validateLightClientOptimisticUpdate} from "../../chain/validation/lightClientOptimisticUpdate.js";
@@ -148,37 +150,16 @@ export function getGossipHandlers(modules: ValidatorFnsModules, options: GossipH
148
150
  function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHandlerOpts): SequentialGossipHandlers {
149
151
  const {chain, config, metrics, logger, core} = modules;
150
152
 
151
- async function validateBeaconBlock(
153
+ /**
154
+ * Add a gossip block to the seen caches. The proposer signature of the block MUST be verified.
155
+ */
156
+ function cacheSignatureVerifiedBlock(
152
157
  signedBlock: SignedBeaconBlock,
158
+ blockRootHex: RootHex,
153
159
  fork: ForkName,
154
160
  peerIdStr: string,
155
161
  seenTimestampSec: number
156
- ): Promise<IBlockInput> {
157
- const slot = signedBlock.message.slot;
158
- const forkTypes = config.getForkTypes(slot);
159
- const blockRootHex = toRootHex(forkTypes.BeaconBlock.hashTreeRoot(signedBlock.message));
160
- const delaySec = chain.clock.secFromSlot(slot, seenTimestampSec);
161
- const recvToValLatency = Date.now() / 1000 - seenTimestampSec;
162
-
163
- // always set block to seen cache for all forks so that we don't need to download it
164
- // TODO: validate block before adding to cache
165
- // tracked in https://github.com/ChainSafe/lodestar/issues/7957
166
-
167
- const logCtx = {
168
- slot,
169
- root: blockRootHex,
170
- currentSlot: chain.clock.currentSlot,
171
- peerId: peerIdStr,
172
- delaySec,
173
- recvToValLatency,
174
- };
175
-
176
- logger.debug("Received gossip block", {...logCtx});
177
-
178
- // optimistically add gossip block to the seen cache
179
- // if validation fails, we will NOT forward this gossip block to peers
180
- // - if PARENT_BLOCK_UNKNOWN error, blockInput will then be queued inside BlockInputSync. If the gossip block is really invalid, it will be pruned there
181
- // - if other validator errors, blockInput will stay in the seen cache and will be pruned on finalization
162
+ ): BlockInput {
182
163
  const blockInput = chain.seenBlockInputCache.getByBlock({
183
164
  block: signedBlock,
184
165
  blockRootHex,
@@ -187,8 +168,7 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
187
168
  peerIdStr,
188
169
  });
189
170
 
190
- // Optimistically seed the payload-envelope cache too, mirroring seenBlockInputCache above.
191
- // This ensures we have PayloadEnvelopeInput, even through "PARENT_BLOCK_UNKNOWN" error
171
+ // Also seed the payload-envelope cache, so we have PayloadEnvelopeInput even through "PARENT_BLOCK_UNKNOWN" error
192
172
  // see https://github.com/ChainSafe/lodestar/issues/9475
193
173
  if (isForkPostGloas(fork)) {
194
174
  chain.seenPayloadEnvelopeInputCache.add({
@@ -202,8 +182,37 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
202
182
  });
203
183
  }
204
184
 
185
+ return blockInput;
186
+ }
187
+
188
+ async function validateBeaconBlock(
189
+ signedBlock: SignedBeaconBlock,
190
+ fork: ForkName,
191
+ peerIdStr: string,
192
+ seenTimestampSec: number
193
+ ): Promise<IBlockInput> {
194
+ const slot = signedBlock.message.slot;
195
+ const forkTypes = config.getForkTypes(slot);
196
+ const blockRootHex = toRootHex(forkTypes.BeaconBlock.hashTreeRoot(signedBlock.message));
197
+ const delaySec = chain.clock.secFromSlot(slot, seenTimestampSec);
198
+ const recvToValLatency = Date.now() / 1000 - seenTimestampSec;
199
+
200
+ const logCtx = {
201
+ slot,
202
+ root: blockRootHex,
203
+ currentSlot: chain.clock.currentSlot,
204
+ peerId: peerIdStr,
205
+ delaySec,
206
+ recvToValLatency,
207
+ };
208
+
209
+ logger.debug("Received gossip block", {...logCtx});
210
+
211
+ chain.seenBlockInputCache.markValidatingBlock(blockRootHex);
212
+
205
213
  try {
206
214
  const {skippedSlots} = await validateGossipBlock(config, chain, signedBlock, fork);
215
+ const blockInput = cacheSignatureVerifiedBlock(signedBlock, blockRootHex, fork, peerIdStr, seenTimestampSec);
207
216
 
208
217
  const blockInputMeta = blockInput.getLogMeta();
209
218
 
@@ -229,54 +238,54 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
229
238
  if (e instanceof BlockGossipError) {
230
239
  logger.debug("Gossip block has error", {slot, root: blockRootHex, code: e.type.code});
231
240
  if (
232
- (e.type.code === BlockErrorCode.PARENT_BLOCK_UNKNOWN ||
233
- e.type.code === BlockErrorCode.PARENT_PAYLOAD_UNKNOWN) &&
234
- blockInput
241
+ e.type.code === BlockErrorCode.PARENT_BLOCK_UNKNOWN ||
242
+ e.type.code === BlockErrorCode.PARENT_PAYLOAD_UNKNOWN
235
243
  ) {
244
+ // The block is retained for unknown parent sync without full validation. Authenticate it first, this
245
+ // does not need the parent state
246
+ const proposerIndex = signedBlock.message.proposerIndex;
247
+ await verifyBlockProposerSignature(chain, signedBlock, blockRootHex);
248
+ chain.seenBlockProposers.observeBlockRoot(
249
+ slot,
250
+ proposerIndex,
251
+ blockRootHex,
252
+ signedBlockToSignedHeader(config, signedBlock)
253
+ );
254
+
255
+ // Check again after the signature verification so concurrent proposals cannot both be retained
256
+ if (chain.seenBlockProposers.isKnown(slot, proposerIndex)) {
257
+ if (chain.seenBlockProposers.isRepeatProposal(slot, proposerIndex, blockRootHex)) {
258
+ throw new BlockGossipError(GossipAction.IGNORE, {
259
+ code: BlockErrorCode.REPEAT_PROPOSAL,
260
+ proposerIndex,
261
+ root: blockRootHex,
262
+ });
263
+ }
264
+ throw new BlockGossipError(GossipAction.IGNORE, {code: BlockErrorCode.ALREADY_KNOWN, root: blockRootHex});
265
+ }
266
+ chain.seenBlockProposers.add(slot, proposerIndex, blockRootHex);
267
+
268
+ const blockInput = cacheSignatureVerifiedBlock(signedBlock, blockRootHex, fork, peerIdStr, seenTimestampSec);
236
269
  chain.emitter.emit(ChainEvent.blockUnknownParent, {
237
270
  blockInput,
238
271
  peer: peerIdStr,
239
272
  source: BlockInputSource.gossip,
240
273
  });
241
- // throw error (don't prune the blockInput)
242
274
  throw e;
243
275
  }
244
276
 
245
- // IGNORE means the block is acceptable (e.g. FUTURE_SLOT, ALREADY_KNOWN), just not propagated.
246
- // Keep the optimistically-added cache entries; they are pruned on finalization. Only REJECT
247
- // (provably invalid), unexpected errors and repeat proposals that are not imported prune.
248
- if (e.action === GossipAction.IGNORE) {
249
- // Only a signature-verified sibling is imported by the beacon_block handler, any other repeat proposal
250
- // is dropped from the caches and re-downloaded by sync if it ever becomes relevant. Its signature was not
251
- // verified, so only its own entry is removed, never its claimed ancestors
252
- if (
253
- e.type.code === BlockErrorCode.REPEAT_PROPOSAL &&
254
- !chain.seenBlockProposers.hasBlockRoot(slot, signedBlock.message.proposerIndex, blockRootHex)
255
- ) {
256
- chain.seenBlockInputCache.remove(blockRootHex);
257
- if (isForkPostGloas(fork)) {
258
- chain.seenPayloadEnvelopeInputCache.remove(blockRootHex);
259
- }
260
- }
261
- throw e;
277
+ if (e.action === GossipAction.REJECT) {
278
+ chain.persistInvalidSszValue(
279
+ forkTypes.SignedBeaconBlock,
280
+ signedBlock,
281
+ `gossip_reject_slot_${slot}`,
282
+ blockRootHex
283
+ );
262
284
  }
263
-
264
- chain.persistInvalidSszValue(
265
- forkTypes.SignedBeaconBlock,
266
- signedBlock,
267
- `gossip_reject_slot_${slot}`,
268
- blockRootHex
269
- );
270
- }
271
-
272
- // REJECT or unexpected (non-BlockGossipError) error: drop the optimistically-added entries from
273
- // both caches, keeping them consistent. The block may carry any parent root, so only its own entry is removed
274
- chain.seenBlockInputCache.remove(blockRootHex);
275
- if (isForkPostGloas(fork)) {
276
- chain.seenPayloadEnvelopeInputCache.remove(blockRootHex);
277
285
  }
278
286
  throw e;
279
287
  } finally {
288
+ chain.seenBlockInputCache.unmarkValidatingBlock(blockRootHex);
280
289
  // The block received from the network may have established an equivocation, either by conflicting
281
290
  // with a previously observed block root (REPEAT_PROPOSAL) or with a root observed during validation
282
291
  const proposerIndex = signedBlock.message.proposerIndex;
@@ -752,18 +761,23 @@ function getSequentialHandlers(modules: ValidatorFnsModules, options: GossipHand
752
761
  e.type.code === BlockErrorCode.REPEAT_PROPOSAL &&
753
762
  // Only a signature-verified sibling recorded in the seen cache is imported. The cache holds at most two
754
763
  // roots per proposer and slot, which bounds full imports over gossip to one alternate
755
- chain.seenBlockProposers.hasBlockRoot(signedBlock.message.slot, e.type.proposerIndex, e.type.root)
764
+ chain.seenBlockProposers.hasBlockRoot(signedBlock.message.slot, e.type.proposerIndex, e.type.root) &&
765
+ // A sibling with an unknown parent cannot be imported, sync fetches it if its branch becomes relevant
766
+ chain.forkChoice.getBlockHexDefaultStatus(toRootHex(signedBlock.message.parentRoot)) !== null
756
767
  ) {
757
- // blockInput was optimistically seeded in validateBeaconBlock and retained on IGNORE
758
- const blockInput = chain.seenBlockInputCache.get(e.type.root);
759
- if (blockInput) {
760
- // We're returning IGNORE (thrown below), so this block is not forwarded to peers. Unlike the
761
- // happy path there is no rush to forward, so we don't need to wrap in callInNextEventLoop.
762
- chain.serializedCache.set(signedBlock, serializedData);
763
- // this is technically not a valid gossip block but gossip validation is a cheap subset of checks
764
- // this runs the full state transition, so importing an equivocating-but-valid block here is safe.
765
- handleValidBeaconBlock(blockInput, peerIdStr, seenTimestampSec);
766
- }
768
+ const blockInput = cacheSignatureVerifiedBlock(
769
+ signedBlock,
770
+ e.type.root,
771
+ topic.boundary.fork,
772
+ peerIdStr,
773
+ seenTimestampSec
774
+ );
775
+ // We're returning IGNORE (thrown below), so this block is not forwarded to peers. Unlike the
776
+ // happy path there is no rush to forward, so we don't need to wrap in callInNextEventLoop.
777
+ chain.serializedCache.set(signedBlock, serializedData);
778
+ // this is technically not a valid gossip block but gossip validation is a cheap subset of checks
779
+ // this runs the full state transition, so importing an equivocating-but-valid block here is safe.
780
+ handleValidBeaconBlock(blockInput, peerIdStr, seenTimestampSec);
767
781
  }
768
782
  // rethrow so gossipValidatorFn maps IGNORE -> TopicValidatorResult.Ignore (message not forwarded)
769
783
  throw e;
@@ -53,7 +53,7 @@ export async function* onExecutionPayloadEnvelopesByRoot(
53
53
  const batch = requests.slice(i, i + MAX_BODIES_PER_REQUEST);
54
54
  let envelopesBytes: (Uint8Array | null)[];
55
55
  try {
56
- // By-root allows omission, so a mismatched envelope is left out rather than failing the response.
56
+ // By-root allows omission, so an envelope that cannot be rebuilt is left out rather than failing the response.
57
57
  envelopesBytes = await chain.getSerializedExecutionPayloadEnvelopes(batch, "omit");
58
58
  } catch (e) {
59
59
  if (e instanceof EnvelopeReconstructionError) {
@@ -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;