@lodestar/beacon-node 1.47.0-dev.be9d5b774d → 1.47.0-dev.beabd3a65c

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 (213) hide show
  1. package/lib/api/impl/beacon/blocks/index.d.ts.map +1 -1
  2. package/lib/api/impl/beacon/blocks/index.js +3 -2
  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 +8 -1
  6. package/lib/api/impl/beacon/pool/index.js.map +1 -1
  7. package/lib/api/impl/beacon/state/utils.d.ts +2 -1
  8. package/lib/api/impl/beacon/state/utils.d.ts.map +1 -1
  9. package/lib/api/impl/beacon/state/utils.js.map +1 -1
  10. package/lib/api/impl/events/index.d.ts.map +1 -1
  11. package/lib/api/impl/events/index.js +2 -0
  12. package/lib/api/impl/events/index.js.map +1 -1
  13. package/lib/api/rest/base.d.ts.map +1 -1
  14. package/lib/api/rest/base.js +7 -0
  15. package/lib/api/rest/base.js.map +1 -1
  16. package/lib/chain/blocks/importExecutionPayload.d.ts +3 -2
  17. package/lib/chain/blocks/importExecutionPayload.d.ts.map +1 -1
  18. package/lib/chain/blocks/importExecutionPayload.js +11 -9
  19. package/lib/chain/blocks/importExecutionPayload.js.map +1 -1
  20. package/lib/chain/blocks/index.d.ts.map +1 -1
  21. package/lib/chain/blocks/index.js +14 -6
  22. package/lib/chain/blocks/index.js.map +1 -1
  23. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts +2 -1
  24. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.d.ts.map +1 -1
  25. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js +6 -2
  26. package/lib/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.js.map +1 -1
  27. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts +14 -5
  28. package/lib/chain/blocks/payloadEnvelopeInput/types.d.ts.map +1 -1
  29. package/lib/chain/blocks/payloadEnvelopeInput/types.js +5 -0
  30. package/lib/chain/blocks/payloadEnvelopeInput/types.js.map +1 -1
  31. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.d.ts.map +1 -1
  32. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js +22 -12
  33. package/lib/chain/blocks/verifyBlocksStateTransitionOnly.js.map +1 -1
  34. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts +2 -2
  35. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.d.ts.map +1 -1
  36. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js +2 -2
  37. package/lib/chain/blocks/verifyExecutionPayloadEnvelope.js.map +1 -1
  38. package/lib/chain/bls/index.d.ts +1 -1
  39. package/lib/chain/bls/index.d.ts.map +1 -1
  40. package/lib/chain/bls/interface.d.ts +5 -5
  41. package/lib/chain/bls/interface.d.ts.map +1 -1
  42. package/lib/chain/bls/multithread/index.d.ts +5 -11
  43. package/lib/chain/bls/multithread/index.d.ts.map +1 -1
  44. package/lib/chain/bls/multithread/index.js +116 -101
  45. package/lib/chain/bls/multithread/index.js.map +1 -1
  46. package/lib/chain/bls/multithread/jobItem.d.ts +5 -19
  47. package/lib/chain/bls/multithread/jobItem.d.ts.map +1 -1
  48. package/lib/chain/bls/multithread/jobItem.js +10 -65
  49. package/lib/chain/bls/multithread/jobItem.js.map +1 -1
  50. package/lib/chain/bls/multithread/types.d.ts +29 -8
  51. package/lib/chain/bls/multithread/types.d.ts.map +1 -1
  52. package/lib/chain/bls/multithread/types.js +12 -0
  53. package/lib/chain/bls/multithread/types.js.map +1 -1
  54. package/lib/chain/bls/multithread/utils.d.ts +4 -0
  55. package/lib/chain/bls/multithread/utils.d.ts.map +1 -1
  56. package/lib/chain/bls/multithread/utils.js +10 -0
  57. package/lib/chain/bls/multithread/utils.js.map +1 -1
  58. package/lib/chain/bls/multithread/worker.js +49 -23
  59. package/lib/chain/bls/multithread/worker.js.map +1 -1
  60. package/lib/chain/bls/singleThread.d.ts +4 -10
  61. package/lib/chain/bls/singleThread.d.ts.map +1 -1
  62. package/lib/chain/bls/singleThread.js +8 -45
  63. package/lib/chain/bls/singleThread.js.map +1 -1
  64. package/lib/chain/bls/utils.d.ts +4 -4
  65. package/lib/chain/bls/utils.d.ts.map +1 -1
  66. package/lib/chain/bls/utils.js +18 -19
  67. package/lib/chain/bls/utils.js.map +1 -1
  68. package/lib/chain/chain.d.ts +2 -1
  69. package/lib/chain/chain.d.ts.map +1 -1
  70. package/lib/chain/chain.js +12 -5
  71. package/lib/chain/chain.js.map +1 -1
  72. package/lib/chain/errors/blockError.d.ts +1 -0
  73. package/lib/chain/errors/blockError.d.ts.map +1 -1
  74. package/lib/chain/errors/blockError.js +6 -1
  75. package/lib/chain/errors/blockError.js.map +1 -1
  76. package/lib/chain/interface.d.ts +2 -1
  77. package/lib/chain/interface.d.ts.map +1 -1
  78. package/lib/chain/interface.js.map +1 -1
  79. package/lib/chain/opPools/aggregatedAttestationPool.js +1 -1
  80. package/lib/chain/opPools/aggregatedAttestationPool.js.map +1 -1
  81. package/lib/chain/opPools/attestationPool.d.ts +1 -1
  82. package/lib/chain/opPools/attestationPool.d.ts.map +1 -1
  83. package/lib/chain/opPools/attestationPool.js +1 -1
  84. package/lib/chain/opPools/attestationPool.js.map +1 -1
  85. package/lib/chain/opPools/payloadAttestationPool.js +3 -3
  86. package/lib/chain/opPools/payloadAttestationPool.js.map +1 -1
  87. package/lib/chain/opPools/syncCommitteeMessagePool.js +1 -1
  88. package/lib/chain/opPools/syncCommitteeMessagePool.js.map +1 -1
  89. package/lib/chain/opPools/syncContributionAndProofPool.js +1 -1
  90. package/lib/chain/opPools/syncContributionAndProofPool.js.map +1 -1
  91. package/lib/chain/opPools/utils.d.ts +1 -1
  92. package/lib/chain/opPools/utils.d.ts.map +1 -1
  93. package/lib/chain/opPools/utils.js +1 -1
  94. package/lib/chain/opPools/utils.js.map +1 -1
  95. package/lib/chain/seenCache/seenAttesters.d.ts +9 -5
  96. package/lib/chain/seenCache/seenAttesters.d.ts.map +1 -1
  97. package/lib/chain/seenCache/seenAttesters.js +25 -4
  98. package/lib/chain/seenCache/seenAttesters.js.map +1 -1
  99. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts +28 -1
  100. package/lib/chain/seenCache/seenPayloadEnvelopeInput.d.ts.map +1 -1
  101. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js +121 -13
  102. package/lib/chain/seenCache/seenPayloadEnvelopeInput.js.map +1 -1
  103. package/lib/chain/validation/attestation.d.ts.map +1 -1
  104. package/lib/chain/validation/attestation.js +1 -4
  105. package/lib/chain/validation/attestation.js.map +1 -1
  106. package/lib/chain/validation/attesterSlashing.d.ts.map +1 -1
  107. package/lib/chain/validation/attesterSlashing.js +1 -1
  108. package/lib/chain/validation/attesterSlashing.js.map +1 -1
  109. package/lib/chain/validation/executionPayloadBid.d.ts.map +1 -1
  110. package/lib/chain/validation/executionPayloadBid.js +1 -2
  111. package/lib/chain/validation/executionPayloadBid.js.map +1 -1
  112. package/lib/chain/validation/executionPayloadEnvelope.js +1 -1
  113. package/lib/chain/validation/executionPayloadEnvelope.js.map +1 -1
  114. package/lib/chain/validation/payloadAttestationMessage.d.ts.map +1 -1
  115. package/lib/chain/validation/payloadAttestationMessage.js +5 -14
  116. package/lib/chain/validation/payloadAttestationMessage.js.map +1 -1
  117. package/lib/chain/validation/proposerPreferences.js +2 -2
  118. package/lib/chain/validation/proposerPreferences.js.map +1 -1
  119. package/lib/chain/validation/proposerSlashing.js +1 -1
  120. package/lib/chain/validation/proposerSlashing.js.map +1 -1
  121. package/lib/metrics/metrics/lodestar.d.ts +45 -20
  122. package/lib/metrics/metrics/lodestar.d.ts.map +1 -1
  123. package/lib/metrics/metrics/lodestar.js +87 -51
  124. package/lib/metrics/metrics/lodestar.js.map +1 -1
  125. package/lib/network/gossip/topic.d.ts +13 -0
  126. package/lib/network/gossip/topic.d.ts.map +1 -1
  127. package/lib/network/gossip/topic.js +37 -0
  128. package/lib/network/gossip/topic.js.map +1 -1
  129. package/lib/network/network.d.ts.map +1 -1
  130. package/lib/network/network.js +22 -43
  131. package/lib/network/network.js.map +1 -1
  132. package/lib/network/processor/gossipHandlers.d.ts.map +1 -1
  133. package/lib/network/processor/gossipHandlers.js +5 -1
  134. package/lib/network/processor/gossipHandlers.js.map +1 -1
  135. package/lib/network/util.d.ts +0 -1
  136. package/lib/network/util.d.ts.map +1 -1
  137. package/lib/network/util.js +0 -4
  138. package/lib/network/util.js.map +1 -1
  139. package/lib/node/nodejs.d.ts +2 -1
  140. package/lib/node/nodejs.d.ts.map +1 -1
  141. package/lib/node/nodejs.js.map +1 -1
  142. package/lib/sync/range/batch.d.ts +23 -5
  143. package/lib/sync/range/batch.d.ts.map +1 -1
  144. package/lib/sync/range/batch.js +61 -22
  145. package/lib/sync/range/batch.js.map +1 -1
  146. package/lib/sync/range/chain.d.ts +2 -1
  147. package/lib/sync/range/chain.d.ts.map +1 -1
  148. package/lib/sync/range/chain.js +23 -10
  149. package/lib/sync/range/chain.js.map +1 -1
  150. package/lib/sync/unknownBlock.d.ts.map +1 -1
  151. package/lib/sync/unknownBlock.js +7 -13
  152. package/lib/sync/unknownBlock.js.map +1 -1
  153. package/lib/sync/utils/downloadByRange.d.ts.map +1 -1
  154. package/lib/sync/utils/downloadByRange.js +16 -11
  155. package/lib/sync/utils/downloadByRange.js.map +1 -1
  156. package/lib/sync/utils/downloadByRoot.d.ts.map +1 -1
  157. package/lib/sync/utils/downloadByRoot.js +3 -1
  158. package/lib/sync/utils/downloadByRoot.js.map +1 -1
  159. package/package.json +35 -35
  160. package/src/api/impl/beacon/blocks/index.ts +3 -2
  161. package/src/api/impl/beacon/pool/index.ts +7 -1
  162. package/src/api/impl/beacon/state/utils.ts +2 -1
  163. package/src/api/impl/events/index.ts +3 -1
  164. package/src/api/rest/base.ts +7 -0
  165. package/src/chain/blocks/importExecutionPayload.ts +12 -11
  166. package/src/chain/blocks/index.ts +18 -6
  167. package/src/chain/blocks/payloadEnvelopeInput/payloadEnvelopeInput.ts +8 -2
  168. package/src/chain/blocks/payloadEnvelopeInput/types.ts +17 -4
  169. package/src/chain/blocks/verifyBlocksStateTransitionOnly.ts +25 -16
  170. package/src/chain/blocks/verifyExecutionPayloadEnvelope.ts +1 -9
  171. package/src/chain/bls/index.ts +1 -1
  172. package/src/chain/bls/interface.ts +7 -3
  173. package/src/chain/bls/multithread/index.ts +148 -120
  174. package/src/chain/bls/multithread/jobItem.ts +12 -82
  175. package/src/chain/bls/multithread/types.ts +33 -8
  176. package/src/chain/bls/multithread/utils.ts +11 -0
  177. package/src/chain/bls/multithread/worker.ts +85 -27
  178. package/src/chain/bls/singleThread.ts +11 -55
  179. package/src/chain/bls/utils.ts +23 -24
  180. package/src/chain/chain.ts +13 -6
  181. package/src/chain/errors/blockError.ts +8 -2
  182. package/src/chain/interface.ts +2 -1
  183. package/src/chain/opPools/aggregatedAttestationPool.ts +1 -1
  184. package/src/chain/opPools/attestationPool.ts +1 -1
  185. package/src/chain/opPools/payloadAttestationPool.ts +3 -3
  186. package/src/chain/opPools/syncCommitteeMessagePool.ts +1 -1
  187. package/src/chain/opPools/syncContributionAndProofPool.ts +1 -1
  188. package/src/chain/opPools/utils.ts +1 -1
  189. package/src/chain/seenCache/seenAttesters.ts +31 -5
  190. package/src/chain/seenCache/seenPayloadEnvelopeInput.ts +143 -14
  191. package/src/chain/validation/attestation.ts +1 -7
  192. package/src/chain/validation/attesterSlashing.ts +1 -8
  193. package/src/chain/validation/executionPayloadBid.ts +1 -2
  194. package/src/chain/validation/executionPayloadEnvelope.ts +0 -1
  195. package/src/chain/validation/payloadAttestationMessage.ts +6 -17
  196. package/src/chain/validation/proposerPreferences.ts +3 -3
  197. package/src/chain/validation/proposerSlashing.ts +1 -1
  198. package/src/metrics/metrics/lodestar.ts +97 -54
  199. package/src/network/gossip/topic.ts +38 -0
  200. package/src/network/network.ts +27 -55
  201. package/src/network/processor/gossipHandlers.ts +5 -1
  202. package/src/network/util.ts +0 -5
  203. package/src/node/nodejs.ts +2 -1
  204. package/src/sync/range/batch.ts +83 -28
  205. package/src/sync/range/chain.ts +26 -11
  206. package/src/sync/unknownBlock.ts +8 -15
  207. package/src/sync/utils/downloadByRange.ts +21 -12
  208. package/src/sync/utils/downloadByRoot.ts +3 -1
  209. package/lib/chain/bls/maybeBatch.d.ts +0 -12
  210. package/lib/chain/bls/maybeBatch.d.ts.map +0 -1
  211. package/lib/chain/bls/maybeBatch.js +0 -35
  212. package/lib/chain/bls/maybeBatch.js.map +0 -1
  213. package/src/chain/bls/maybeBatch.ts +0 -45
@@ -1,18 +1,32 @@
1
1
  import {ChainForkConfig} from "@lodestar/config";
2
2
  import {CheckpointWithHex, IForkChoice, PayloadStatus, ProtoBlock} from "@lodestar/fork-choice";
3
+ import {ForkPostGloas, SLOTS_PER_EPOCH, isForkPostGloas} from "@lodestar/params";
3
4
  import {computeStartSlotAtEpoch} from "@lodestar/state-transition";
4
- import {RootHex} from "@lodestar/types";
5
- import {Logger} from "@lodestar/utils";
5
+ import {RootHex, SignedBeaconBlock} from "@lodestar/types";
6
+ import {Logger, fromHex} from "@lodestar/utils";
7
+ import {IBeaconDb} from "../../db/index.js";
6
8
  import {Metrics} from "../../metrics/metrics.js";
9
+ import {MAX_LOOK_AHEAD_EPOCHS} from "../../sync/constants.js";
7
10
  import {IClock} from "../../util/clock.js";
11
+ import {CustodyConfig} from "../../util/dataColumns.js";
8
12
  import {SerializedCache} from "../../util/serializedCache.js";
9
13
  import {isDaOutOfRange} from "../blocks/blockInput/index.js";
10
- import {CreateFromBidProps, CreateFromBlockProps, PayloadEnvelopeInput} from "../blocks/payloadEnvelopeInput/index.js";
14
+ import {
15
+ CreateFromBidProps,
16
+ CreateFromBlockProps,
17
+ PayloadEnvelopeInput,
18
+ PayloadEnvelopeInputPruneReason,
19
+ PayloadEnvelopeInputSource,
20
+ } from "../blocks/payloadEnvelopeInput/index.js";
11
21
  import {ChainEvent, ChainEventEmitter} from "../emitter.js";
22
+ import {SeenBlockInput} from "./seenGossipBlockInput.js";
12
23
 
13
24
  export type {PayloadEnvelopeInputState} from "../blocks/payloadEnvelopeInput/index.js";
14
25
  export {PayloadEnvelopeInput} from "../blocks/payloadEnvelopeInput/index.js";
15
26
 
27
+ // Bound this cache by this max size, this is the same to SeenBlockInput
28
+ const MAX_PAYLOAD_ENVELOPE_INPUT_CACHE_SIZE = (MAX_LOOK_AHEAD_EPOCHS + 1) * SLOTS_PER_EPOCH;
29
+
16
30
  export type SeenPayloadEnvelopeInputModules = {
17
31
  config: ChainForkConfig;
18
32
  clock: IClock;
@@ -20,6 +34,9 @@ export type SeenPayloadEnvelopeInputModules = {
20
34
  chainEvents: ChainEventEmitter;
21
35
  signal: AbortSignal;
22
36
  serializedCache: SerializedCache;
37
+ db: IBeaconDb;
38
+ seenBlockInputCache: SeenBlockInput;
39
+ custodyConfig: CustodyConfig;
23
40
  metrics: Metrics | null;
24
41
  logger?: Logger;
25
42
  };
@@ -40,9 +57,14 @@ export class SeenPayloadEnvelopeInput {
40
57
  private readonly chainEvents: ChainEventEmitter;
41
58
  private readonly signal: AbortSignal;
42
59
  private readonly serializedCache: SerializedCache;
60
+ private readonly db: IBeaconDb;
61
+ private readonly seenBlockInputCache: SeenBlockInput;
62
+ private readonly custodyConfig: CustodyConfig;
43
63
  private readonly metrics: Metrics | null;
44
64
  private readonly logger?: Logger;
45
65
  private payloadInputs = new Map<RootHex, PayloadEnvelopeInput>();
66
+ // Dedup concurrent DB reloads of the same root so callers share one reconstructed object.
67
+ private readonly reloading = new Map<RootHex, Promise<PayloadEnvelopeInput | undefined>>();
46
68
 
47
69
  constructor({
48
70
  config,
@@ -51,6 +73,9 @@ export class SeenPayloadEnvelopeInput {
51
73
  chainEvents,
52
74
  signal,
53
75
  serializedCache,
76
+ db,
77
+ seenBlockInputCache,
78
+ custodyConfig,
54
79
  metrics,
55
80
  logger,
56
81
  }: SeenPayloadEnvelopeInputModules) {
@@ -60,6 +85,9 @@ export class SeenPayloadEnvelopeInput {
60
85
  this.chainEvents = chainEvents;
61
86
  this.signal = signal;
62
87
  this.serializedCache = serializedCache;
88
+ this.db = db;
89
+ this.seenBlockInputCache = seenBlockInputCache;
90
+ this.custodyConfig = custodyConfig;
63
91
  this.metrics = metrics;
64
92
  this.logger = logger;
65
93
 
@@ -86,7 +114,7 @@ export class SeenPayloadEnvelopeInput {
86
114
  let deletedCount = 0;
87
115
  for (const [, input] of this.payloadInputs) {
88
116
  if (input.slot < finalizedSlot) {
89
- this.evictPayloadInput(input);
117
+ this.evictPayloadInput(input, "finalized");
90
118
  deletedCount++;
91
119
  }
92
120
  }
@@ -110,12 +138,13 @@ export class SeenPayloadEnvelopeInput {
110
138
  const daOutOfRange = isDaOutOfRange(this.config, props.forkName, props.block.message.slot, this.clock.currentEpoch);
111
139
  const input = PayloadEnvelopeInput.createFromBlock({...props, daOutOfRange});
112
140
  this.payloadInputs.set(props.blockRootHex, input);
113
- this.metrics?.seenCache.payloadEnvelopeInput.created.inc();
141
+ this.metrics?.seenCache.payloadEnvelopeInput.created.inc({source: props.source});
114
142
  this.logger?.verbose("SeenPayloadEnvelopeInput.add created new entry", {
115
143
  slot: input.slot,
116
144
  root: props.blockRootHex,
117
145
  daOutOfRange,
118
146
  });
147
+ this.pruneToMaxSize();
119
148
  return input;
120
149
  }
121
150
 
@@ -131,12 +160,13 @@ export class SeenPayloadEnvelopeInput {
131
160
  const daOutOfRange = isDaOutOfRange(this.config, props.forkName, props.slot, this.clock.currentEpoch);
132
161
  const input = PayloadEnvelopeInput.createFromBid({...props, daOutOfRange});
133
162
  this.payloadInputs.set(props.blockRootHex, input);
134
- this.metrics?.seenCache.payloadEnvelopeInput.created.inc();
163
+ this.metrics?.seenCache.payloadEnvelopeInput.created.inc({source: props.source});
135
164
  this.logger?.verbose("SeenPayloadEnvelopeInput.addFromBid created new entry", {
136
165
  slot: input.slot,
137
166
  root: props.blockRootHex,
138
167
  daOutOfRange,
139
168
  });
169
+ this.pruneToMaxSize();
140
170
  return input;
141
171
  }
142
172
 
@@ -144,6 +174,80 @@ export class SeenPayloadEnvelopeInput {
144
174
  return this.payloadInputs.get(blockRootHex);
145
175
  }
146
176
 
177
+ /**
178
+ * Like `get()`, but on a cache miss reconstruct the shell (bid + versionedHashes) from the block
179
+ * in `seenBlockInputCache` or the hot DB.
180
+ * This api is meant for BlockInputSync when a late/weird payloads for old blocks
181
+ *
182
+ * NOTE: the reconstructed entry is always EMPTY even when the block is actually FULL (its
183
+ * payload envelope + columns persisted in the DB). The consumer should consult fork choice if it needs to.
184
+ */
185
+ async getOrReload(blockRootHex: RootHex): Promise<PayloadEnvelopeInput | undefined> {
186
+ const existing = this.payloadInputs.get(blockRootHex);
187
+ if (existing !== undefined) {
188
+ return existing;
189
+ }
190
+
191
+ // Without this dedup, two concurrent misses each db.block.get + createFromBlock a DIFFERENT shell
192
+ // for the same root; processPayloadEnvelopeJob's WeakMap (keyed by object) can't dedup the import.
193
+ const inflight = this.reloading.get(blockRootHex);
194
+ if (inflight !== undefined) {
195
+ return inflight;
196
+ }
197
+ const promise = this.reloadFromDb(blockRootHex);
198
+ this.reloading.set(blockRootHex, promise);
199
+ try {
200
+ return await promise;
201
+ } finally {
202
+ this.reloading.delete(blockRootHex);
203
+ }
204
+ }
205
+
206
+ private async reloadFromDb(blockRootHex: RootHex): Promise<PayloadEnvelopeInput | undefined> {
207
+ // Only recover unfinalized, fork-choice-known blocks. Do not read the finalized archive. The gate
208
+ // also filters out un-imported blocks that may sit in seenBlockInputCache before validation.
209
+ if (!this.forkChoice.hasBlockHex(blockRootHex)) {
210
+ return undefined;
211
+ }
212
+
213
+ // In-memory first: persistBlockInput writes db.block THEN prunes seenBlockInputCache, so a
214
+ // just-imported block whose async write (unfinalizedBlockWrites) has not flushed yet is still here;
215
+ // older blocks (already pruned from the cache) fall through to the hot db.
216
+ const cachedBlockInput = this.seenBlockInputCache.get(blockRootHex);
217
+ const block = cachedBlockInput?.hasBlock()
218
+ ? cachedBlockInput.getBlock()
219
+ : await this.db.block.get(fromHex(blockRootHex));
220
+ if (block == null) {
221
+ return undefined;
222
+ }
223
+
224
+ const forkName = this.config.getForkName(block.message.slot);
225
+ if (!isForkPostGloas(forkName)) {
226
+ return undefined;
227
+ }
228
+
229
+ const daOutOfRange = isDaOutOfRange(this.config, forkName, block.message.slot, this.clock.currentEpoch);
230
+ const input = PayloadEnvelopeInput.createFromBlock({
231
+ blockRootHex,
232
+ block: block as SignedBeaconBlock<ForkPostGloas>,
233
+ forkName,
234
+ sampledColumns: this.custodyConfig.sampledColumns,
235
+ custodyColumns: this.custodyConfig.custodyColumns,
236
+ seenTimestampSec: Date.now() / 1000,
237
+ source: PayloadEnvelopeInputSource.reload,
238
+ daOutOfRange,
239
+ });
240
+ this.payloadInputs.set(blockRootHex, input);
241
+ this.metrics?.seenCache.payloadEnvelopeInput.created.inc({source: PayloadEnvelopeInputSource.reload});
242
+ this.logger?.verbose("SeenPayloadEnvelopeInput.getOrReload reconstructed entry from db", {
243
+ slot: input.slot,
244
+ root: blockRootHex,
245
+ });
246
+ // Set above (entry is at the back of the insertion order), so the cap never evicts what we just reloaded.
247
+ this.pruneToMaxSize();
248
+ return input;
249
+ }
250
+
147
251
  hasPayload(blockRootHex: RootHex): boolean {
148
252
  return this.payloadInputs.get(blockRootHex)?.hasPayloadEnvelope() ?? false;
149
253
  }
@@ -155,8 +259,7 @@ export class SeenPayloadEnvelopeInput {
155
259
  prune(blockRootHex: RootHex): void {
156
260
  const input = this.payloadInputs.get(blockRootHex);
157
261
  if (input) {
158
- this.evictPayloadInput(input);
159
- this.logger?.verbose("SeenPayloadEnvelopeInput.prune deleted", {slot: input.slot, root: blockRootHex});
262
+ this.evictPayloadInput(input, "prune");
160
263
  }
161
264
  }
162
265
 
@@ -170,17 +273,43 @@ export class SeenPayloadEnvelopeInput {
170
273
  // ...and don't evict while columns are still being gathered: writeDataColumnsToDb awaits the
171
274
  // same hasComputedAllData() before persisting. Such entries are pruned by a later call.
172
275
  if (input?.hasComputedAllData()) {
173
- this.evictPayloadInput(input);
174
- this.logger?.verbose("SeenPayloadEnvelopeInput.pruneBelowParent deleted", {
175
- slot: block.slot,
176
- root: block.blockRoot,
177
- });
276
+ this.evictPayloadInput(input, "belowParent");
178
277
  }
179
278
  }
180
279
  }
181
280
  }
182
281
 
183
- private evictPayloadInput(payloadInput: PayloadEnvelopeInput): void {
282
+ /**
283
+ * Bound this cache to have at most MAX_PAYLOAD_ENVELOPE_INPUT_CACHE_SIZE items.
284
+ * Evicts by insertion order so a just-reloaded old-slot entry is not evicted right after.
285
+ * On unstable network, we may need to query an evicted item, UnknownBlockInput will recover
286
+ * it from db via getOrReload() api. Runs after every single insert, so it evicts ~1 per call.
287
+ */
288
+ private pruneToMaxSize(): void {
289
+ let evicted = 0;
290
+ for (const input of this.payloadInputs.values()) {
291
+ if (this.payloadInputs.size <= MAX_PAYLOAD_ENVELOPE_INPUT_CACHE_SIZE) {
292
+ break;
293
+ }
294
+ this.evictPayloadInput(input, "cap");
295
+ evicted++;
296
+ }
297
+ if (evicted > 0) {
298
+ this.logger?.debug("SeenPayloadEnvelopeInput.pruneToMaxSize evicted", {
299
+ evicted,
300
+ size: this.payloadInputs.size,
301
+ max: MAX_PAYLOAD_ENVELOPE_INPUT_CACHE_SIZE,
302
+ });
303
+ }
304
+ }
305
+
306
+ private evictPayloadInput(payloadInput: PayloadEnvelopeInput, reason: PayloadEnvelopeInputPruneReason): void {
307
+ this.metrics?.seenCache.payloadEnvelopeInput.pruned.inc({reason});
308
+ this.logger?.debug("SeenPayloadEnvelopeInput evicted", {
309
+ slot: payloadInput.slot,
310
+ root: payloadInput.blockRootHex,
311
+ reason,
312
+ });
184
313
  this.serializedCache.delete(payloadInput.getSerializedCacheKeys());
185
314
  this.payloadInputs.delete(payloadInput.blockRootHex);
186
315
  }
@@ -142,13 +142,7 @@ export async function validateGossipAttestationsSameAttData(
142
142
  const batchableBls = signatureSets.length >= chain.opts.minSameMessageSignatureSetsToBatch;
143
143
  if (batchableBls) {
144
144
  // all signature sets should have same signing root since we filtered in network processor
145
- signatureValids = await chain.bls.verifySignatureSetsSameMessage(
146
- signatureSets.map((set) => {
147
- const publicKey = chain.pubkeyCache.getOrThrow(set.index);
148
- return {publicKey, signature: set.signature};
149
- }),
150
- signatureSets[0].signingRoot
151
- );
145
+ signatureValids = await chain.bls.verifySignatureSetsSameMessage(signatureSets, signatureSets[0].signingRoot);
152
146
  } else {
153
147
  // don't want to block the main thread if there are too few signatures
154
148
  signatureValids = await Promise.all(
@@ -44,14 +44,7 @@ export async function validateAttesterSlashing(
44
44
  // [REJECT] All of the conditions within process_attester_slashing pass validation.
45
45
  try {
46
46
  // verifySignature = false, verified in batch below
47
- assertValidAttesterSlashing(
48
- chain.config,
49
- chain.pubkeyCache,
50
- state.slot,
51
- state.validatorCount,
52
- attesterSlashing,
53
- false
54
- );
47
+ assertValidAttesterSlashing(chain.config, state.slot, state.validatorCount, attesterSlashing, false);
55
48
  } catch (e) {
56
49
  throw new AttesterSlashingError(GossipAction.REJECT, {
57
50
  code: AttesterSlashingErrorCode.INVALID,
@@ -1,4 +1,3 @@
1
- import {PublicKey} from "@chainsafe/blst";
2
1
  import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice";
3
2
  import {PAYLOAD_BUILDER_VERSION} from "@lodestar/params";
4
3
  import {
@@ -345,7 +344,7 @@ async function validateExecutionPayloadBid(
345
344
 
346
345
  // [REJECT] `signed_execution_payload_bid.signature` is valid with respect to the `bid.builder_index`.
347
346
  const signatureSet = createSingleSignatureSetFromComponents(
348
- PublicKey.fromBytes(builder.pubkey),
347
+ builder.pubkey,
349
348
  getExecutionPayloadBidSigningRoot(chain.config, bid),
350
349
  signedExecutionPayloadBid.signature
351
350
  );
@@ -170,7 +170,6 @@ async function validateExecutionPayloadEnvelope(
170
170
  // by `verify_execution_payload_envelope_signature`.
171
171
  const signatureSet = getExecutionPayloadEnvelopeSignatureSet(
172
172
  chain.config,
173
- chain.pubkeyCache,
174
173
  blockState,
175
174
  executionPayloadEnvelope,
176
175
  payloadInput.proposerIndex
@@ -1,6 +1,5 @@
1
1
  import {
2
- computeEpochAtSlot,
3
- createSingleSignatureSetFromComponents,
2
+ createIndexedSignatureSetFromComponents,
4
3
  getPayloadAttestationDataSigningRoot,
5
4
  isStatePostGloas,
6
5
  } from "@lodestar/state-transition";
@@ -36,7 +35,6 @@ async function validatePayloadAttestationMessage(
36
35
  prioritizeBls = false
37
36
  ): Promise<PayloadAttestationValidationResult> {
38
37
  const {data, validatorIndex} = payloadAttestationMessage;
39
- const epoch = computeEpochAtSlot(data.slot);
40
38
 
41
39
  // [IGNORE] The message's slot is for the current slot (with a `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance), i.e. `data.slot == current_slot`.
42
40
  if (!chain.clock.isCurrentSlotGivenGossipDisparity(data.slot)) {
@@ -48,9 +46,8 @@ async function validatePayloadAttestationMessage(
48
46
  }
49
47
 
50
48
  // [IGNORE] The `payload_attestation_message` is the first valid message received
51
- // from the validator with index `payload_attestation_message.validator_index`.
52
- // A single validator can participate PTC at most once per epoch
53
- if (chain.seenPayloadAttesters.isKnown(epoch, validatorIndex)) {
49
+ // for the slot from the validator with index `payload_attestation_message.validator_index`.
50
+ if (chain.seenPayloadAttesters.isKnown(data.slot, validatorIndex)) {
54
51
  throw new PayloadAttestationError(GossipAction.IGNORE, {
55
52
  code: PayloadAttestationErrorCode.PAYLOAD_ATTESTATION_ALREADY_KNOWN,
56
53
  validatorIndex,
@@ -114,16 +111,8 @@ async function validatePayloadAttestationMessage(
114
111
  }
115
112
 
116
113
  // [REJECT] `payload_attestation_message.signature` is valid with respect to the validator's public key.
117
- const validatorPubkey = chain.pubkeyCache.get(validatorIndex);
118
- if (!validatorPubkey) {
119
- throw new PayloadAttestationError(GossipAction.REJECT, {
120
- code: PayloadAttestationErrorCode.INVALID_ATTESTER,
121
- attesterIndex: validatorIndex,
122
- });
123
- }
124
-
125
- const signatureSet = createSingleSignatureSetFromComponents(
126
- validatorPubkey,
114
+ const signatureSet = createIndexedSignatureSetFromComponents(
115
+ validatorIndex,
127
116
  getPayloadAttestationDataSigningRoot(chain.config, data),
128
117
  payloadAttestationMessage.signature
129
118
  );
@@ -135,7 +124,7 @@ async function validatePayloadAttestationMessage(
135
124
  }
136
125
 
137
126
  // Valid
138
- chain.seenPayloadAttesters.add(epoch, validatorIndex);
127
+ chain.seenPayloadAttesters.add(data.slot, validatorIndex);
139
128
 
140
129
  return {
141
130
  attDataRootHex: toRootHex(ssz.gloas.PayloadAttestationData.hashTreeRoot(data)),
@@ -3,7 +3,7 @@ import {GENESIS_EPOCH, GENESIS_SLOT, MIN_SEED_LOOKAHEAD, SLOTS_PER_EPOCH, isFork
3
3
  import {
4
4
  computeEpochAtSlot,
5
5
  computeStartSlotAtEpoch,
6
- createSingleSignatureSetFromComponents,
6
+ createIndexedSignatureSetFromComponents,
7
7
  getProposerPreferencesSigningRoot,
8
8
  } from "@lodestar/state-transition";
9
9
  import {Epoch, Slot, ValidatorIndex, gloas} from "@lodestar/types";
@@ -139,8 +139,8 @@ export async function validateGossipProposerPreferences(
139
139
  }
140
140
 
141
141
  // [REJECT] `signed_proposer_preferences.signature` is valid with respect to the validator's public key.
142
- const signatureSet = createSingleSignatureSetFromComponents(
143
- chain.pubkeyCache.getOrThrow(validatorIndex),
142
+ const signatureSet = createIndexedSignatureSetFromComponents(
143
+ validatorIndex,
144
144
  getProposerPreferencesSigningRoot(chain.config, preferences),
145
145
  signedProposerPreferences.signature
146
146
  );
@@ -37,7 +37,7 @@ async function validateProposerSlashing(
37
37
  try {
38
38
  const proposer = state.getValidator(proposerSlashing.signedHeader1.message.proposerIndex);
39
39
  // verifySignature = false, verified in batch below
40
- assertValidProposerSlashing(chain.config, chain.pubkeyCache, state.slot, proposerSlashing, proposer, false);
40
+ assertValidProposerSlashing(chain.config, state.slot, proposerSlashing, proposer, false);
41
41
  } catch (e) {
42
42
  throw new ProposerSlashingError(GossipAction.REJECT, {
43
43
  code: ProposerSlashingErrorCode.INVALID,
@@ -4,7 +4,10 @@ import {ArchiveStoreTask} from "../../chain/archiveStore/archiveStore.js";
4
4
  import {FrequencyStateArchiveStep} from "../../chain/archiveStore/strategies/frequencyStateArchiveStrategy.js";
5
5
  import {BlockInputSource} from "../../chain/blocks/blockInput/index.js";
6
6
  import {PayloadErrorCode} from "../../chain/blocks/importExecutionPayload.js";
7
- import {PayloadEnvelopeInputSource} from "../../chain/blocks/payloadEnvelopeInput/index.js";
7
+ import {
8
+ PayloadEnvelopeInputPruneReason,
9
+ PayloadEnvelopeInputSource,
10
+ } from "../../chain/blocks/payloadEnvelopeInput/index.js";
8
11
  import {JobQueueItemType} from "../../chain/bls/index.js";
9
12
  import {AttestationErrorCode, BlockErrorCode} from "../../chain/errors/index.js";
10
13
  import {
@@ -31,6 +34,10 @@ import {RegistryMetricCreator} from "../utils/registryMetricCreator.js";
31
34
 
32
35
  export type LodestarMetrics = ReturnType<typeof createLodestarMetrics>;
33
36
 
37
+ type BlsJobOutcome = "valid" | "invalid" | "prepError" | "verifyError" | "workerError";
38
+ type BlsBufferFlushReason = "size" | "timeout";
39
+ type BlsVerificationCallOperation = "batch" | "single" | "fallback" | "same_message";
40
+
34
41
  /**
35
42
  * Extra Lodestar custom metrics
36
43
  */
@@ -396,86 +403,108 @@ export function createLodestarMetrics(
396
403
  // BLS verifier thread pool and queue
397
404
 
398
405
  bls: {
399
- aggregatedPubkeys: register.gauge({
406
+ aggregatedPubkeys: register.counter({
400
407
  name: "lodestar_bls_aggregated_pubkeys_total",
401
- help: "Total aggregated pubkeys for BLS validation",
408
+ help: "Total validator public keys used as inputs to aggregate signature sets",
409
+ }),
410
+ pubkeyCacheSize: register.gauge({
411
+ name: "lodestar_bls_pubkey_cache_size",
412
+ help: "Current number of validator public keys in the native cache",
413
+ }),
414
+ pubkeyCacheCapacity: register.gauge({
415
+ name: "lodestar_bls_pubkey_cache_capacity",
416
+ help: "Number of validator public keys the native cache can hold without growing",
402
417
  }),
403
418
  },
404
419
 
405
420
  blsThreadPool: {
406
- jobsWorkerTime: register.gauge<{workerId: number}>({
421
+ jobsWorkerTime: register.counter<{workerId: number}>({
407
422
  name: "lodestar_bls_thread_pool_time_seconds_sum",
408
- help: "Total time spent verifying signature sets measured on the worker",
423
+ help: "Cumulative wall time spent processing BLS dispatch groups by worker",
409
424
  labelNames: ["workerId"],
410
425
  }),
411
- successJobsSignatureSetsCount: register.gauge({
426
+ successJobsSignatureSetsCount: register.counter({
412
427
  name: "lodestar_bls_thread_pool_success_jobs_signature_sets_count",
413
- help: "Count of total verified signature sets",
414
- }),
415
- errorAggregateSignatureSetsCount: register.gauge<{type: JobQueueItemType}>({
416
- name: "lodestar_bls_thread_pool_error_aggregate_signature_sets_count",
417
- help: "Count of error when aggregating pubkeys or signatures",
418
- labelNames: ["type"],
428
+ help: "Count of signature sets completed without an operational error",
419
429
  }),
420
- errorJobsSignatureSetsCount: register.gauge({
430
+ errorJobsSignatureSetsCount: register.counter({
421
431
  name: "lodestar_bls_thread_pool_error_jobs_signature_sets_count",
422
- help: "Count of total error-ed signature sets",
432
+ help: "Count of signature sets that ended in an input, binding, or worker error",
423
433
  }),
424
- jobWaitTime: register.histogram({
434
+ jobWaitTime: register.histogram<{type: JobQueueItemType}>({
425
435
  name: "lodestar_bls_thread_pool_queue_job_wait_time_seconds",
426
- help: "Time from job added to the queue to starting the job in seconds",
427
- buckets: [0.01, 0.02, 0.1, 0.3, 0.5, 1],
436
+ help: "Time from adding a BLS job until it is selected for a worker dispatch group",
437
+ labelNames: ["type"],
438
+ buckets: [0.005, 0.01, 0.025, 0.05, 0.1, 0.2, 0.5, 1, 2],
439
+ }),
440
+ jobDuration: register.histogram<{type: JobQueueItemType}>({
441
+ name: "lodestar_bls_thread_pool_job_duration_seconds",
442
+ help: "End-to-end duration of a BLS job from submission through completion",
443
+ labelNames: ["type"],
444
+ buckets: [0.005, 0.01, 0.025, 0.05, 0.1, 0.2, 0.5, 1, 2],
445
+ }),
446
+ jobResults: register.counter<{type: JobQueueItemType; outcome: BlsJobOutcome}>({
447
+ name: "lodestar_bls_thread_pool_job_results_total",
448
+ help: "Count of completed BLS jobs by cryptographic or operational outcome",
449
+ labelNames: ["type", "outcome"],
428
450
  }),
429
451
  queueLength: register.gauge({
430
452
  name: "lodestar_bls_thread_pool_queue_length",
431
- help: "Count of total block processor queue length",
453
+ help: "Count of ready BLS jobs waiting for a worker",
454
+ }),
455
+ bufferedQueueLength: register.gauge({
456
+ name: "lodestar_bls_thread_pool_buffered_queue_length",
457
+ help: "Count of BLS jobs waiting in the intentional batching buffer",
432
458
  }),
433
459
  workersBusy: register.gauge({
434
460
  name: "lodestar_bls_thread_pool_workers_busy",
435
461
  help: "Count of current busy workers",
436
462
  }),
437
- totalJobsGroupsStarted: register.gauge({
463
+ totalJobsGroupsStarted: register.counter({
438
464
  name: "lodestar_bls_thread_pool_job_groups_started_total",
439
- help: "Count of total jobs groups started in bls thread pool, job groups include +1 jobs",
465
+ help: "Count of worker dispatch groups started by the BLS thread pool",
440
466
  }),
441
- totalJobsStarted: register.gauge<{type: JobQueueItemType}>({
467
+ totalJobsStarted: register.counter<{type: JobQueueItemType}>({
442
468
  name: "lodestar_bls_thread_pool_jobs_started_total",
443
- help: "Count of total jobs started in bls thread pool, jobs include +1 signature sets",
469
+ help: "Count of jobs started by the BLS thread pool",
444
470
  labelNames: ["type"],
445
471
  }),
446
- totalSigSetsStarted: register.gauge<{type: JobQueueItemType}>({
472
+ totalSigSetsStarted: register.counter<{type: JobQueueItemType}>({
447
473
  name: "lodestar_bls_thread_pool_sig_sets_started_total",
448
- help: "Count of total signature sets started in bls thread pool, sig sets include 1 pk, msg, sig",
474
+ help: "Count of signature sets started by the BLS thread pool",
449
475
  labelNames: ["type"],
450
476
  }),
451
477
  // Re-verifying a batch means doing double work. This number must be very low or it can be a waste of CPU resources
452
- batchRetries: register.gauge({
478
+ batchRetries: register.counter({
453
479
  name: "lodestar_bls_thread_pool_batch_retries_total",
454
- help: "Count of total batches that failed and had to be verified again.",
480
+ help: "Count of combined batches that failed and required per-job fallback",
455
481
  }),
456
482
  // To count how many sigs are being validated with the optimization of batching them
457
- batchSigsSuccess: register.gauge({
483
+ batchSigsSuccess: register.counter({
458
484
  name: "lodestar_bls_thread_pool_batch_sigs_success_total",
459
- help: "Count of total batches that failed and had to be verified again.",
485
+ help: "Count of signature sets accepted by combined batch verification without fallback",
460
486
  }),
461
- sameMessageRetryJobs: register.gauge({
462
- name: "lodestar_bls_thread_pool_same_message_jobs_retries_total",
463
- help: "Count of total same message jobs that failed and had to be verified again.",
487
+ bufferFlushes: register.counter<{reason: BlsBufferFlushReason}>({
488
+ name: "lodestar_bls_thread_pool_buffer_flushes_total",
489
+ help: "Count of batching-buffer flushes by trigger",
490
+ labelNames: ["reason"],
464
491
  }),
465
- sameMessageRetrySets: register.gauge({
466
- name: "lodestar_bls_thread_pool_same_message_sets_retries_total",
467
- help: "Count of total same message sets that failed and had to be verified again.",
492
+ bufferedSignatureSets: register.histogram({
493
+ name: "lodestar_bls_thread_pool_buffered_signature_sets",
494
+ help: "Count of signature sets included in each batching-buffer flush",
495
+ buckets: [1, 8, 16, 24, 28, 32, 36, 40, 44, 48, 64, 128],
468
496
  }),
469
497
  // To measure the time cost of main thread <-> worker message passing
470
498
  latencyToWorker: register.histogram({
471
499
  name: "lodestar_bls_thread_pool_latency_to_worker",
472
500
  help: "Time from sending the job to the worker and the worker receiving it",
473
- buckets: [0.001, 0.003, 0.01, 0.03, 0.1],
501
+ // The dashboard treats 20ms as slow; values above 100ms only need severe-stall classification.
502
+ buckets: [0.00025, 0.001, 0.005, 0.02, 0.1],
474
503
  }),
475
504
  latencyFromWorker: register.histogram({
476
505
  name: "lodestar_bls_thread_pool_latency_from_worker",
477
506
  help: "Time from the worker sending the result and the main thread receiving it",
478
- buckets: [0.001, 0.003, 0.01, 0.03, 0.1],
507
+ buckets: [0.00025, 0.001, 0.005, 0.02, 0.1],
479
508
  }),
480
509
  mainThreadDurationInThreadPool: register.histogram({
481
510
  name: "lodestar_bls_thread_pool_main_thread_time_seconds",
@@ -485,32 +514,40 @@ export function createLodestarMetrics(
485
514
  }),
486
515
  timePerSigSet: register.histogram({
487
516
  name: "lodestar_bls_worker_thread_time_per_sigset_seconds",
488
- help: "Time to verify each sigset with worker thread mode",
517
+ help: "Average BLS worker dispatch wall time per original signature set",
489
518
  // Time per sig ~0.9ms on good machines
490
- buckets: [0.5e-3, 0.75e-3, 1e-3, 1.5e-3, 2e-3, 5e-3],
491
- }),
492
- totalSigSets: register.gauge({
519
+ buckets: [0.5e-3, 0.75e-3, 1e-3, 1.5e-3, 2e-3, 5e-3, 10e-3, 20e-3, 50e-3, 100e-3],
520
+ }),
521
+ workRequestPreparationDuration: register.histogram({
522
+ name: "lodestar_bls_thread_pool_work_request_preparation_duration_seconds",
523
+ help: "Main-thread time spent converting one worker dispatch group to binding inputs",
524
+ // Normal requests take microseconds; the dashboard treats 1ms as a main-thread stall.
525
+ buckets: [0.000005, 0.000025, 0.0001, 0.0005, 0.001, 0.005, 0.025],
526
+ }),
527
+ verificationCallDuration: register.histogram<{operation: BlsVerificationCallOperation}>({
528
+ name: "lodestar_bls_thread_pool_verification_call_duration_seconds",
529
+ help: "Duration of one worker-side lodestar-z verification binding call, including input conversion",
530
+ labelNames: ["operation"],
531
+ // Verification ranges from sub-millisecond calls to large batches; above 500ms is uniformly severe.
532
+ buckets: [0.00025, 0.001, 0.005, 0.02, 0.1, 0.5],
533
+ }),
534
+ verificationCallSignatureSets: register.counter<{operation: BlsVerificationCallOperation}>({
535
+ name: "lodestar_bls_thread_pool_verification_call_signature_sets_total",
536
+ help: "Count of signature sets passed to worker-side lodestar-z verification binding calls",
537
+ labelNames: ["operation"],
538
+ }),
539
+ totalSigSets: register.counter({
493
540
  name: "lodestar_bls_thread_pool_sig_sets_total",
494
541
  help: "Count of total signature sets",
495
542
  }),
496
- prioritizedSigSets: register.gauge({
543
+ prioritizedSigSets: register.counter({
497
544
  name: "lodestar_bls_thread_pool_prioritized_sig_sets_total",
498
545
  help: "Count of total prioritized signature sets",
499
546
  }),
500
- batchableSigSets: register.gauge({
547
+ batchableSigSets: register.counter({
501
548
  name: "lodestar_bls_thread_pool_batchable_sig_sets_total",
502
549
  help: "Count of total batchable signature sets",
503
550
  }),
504
- aggregateWithRandomnessAsyncDuration: register.histogram({
505
- name: "lodestar_bls_thread_pool_aggregate_with_randomness_async_time_seconds",
506
- help: "Total time performing aggregateWithRandomness async",
507
- buckets: [0.001, 0.005, 0.01, 0.1, 0.3],
508
- }),
509
- pubkeysAggregationMainThreadDuration: register.histogram({
510
- name: "lodestar_bls_thread_pool_pubkeys_aggregation_main_thread_time_seconds",
511
- help: "Total time spent aggregating pubkeys on main thread",
512
- buckets: [0.001, 0.005, 0.01, 0.1],
513
- }),
514
551
  },
515
552
 
516
553
  // BLS time on single thread mode
@@ -1609,9 +1646,15 @@ export function createLodestarMetrics(
1609
1646
  name: "lodestar_seen_payload_envelope_input_cache_serialized_object_refs",
1610
1647
  help: "Number of serialized-cache object refs retained by cached PayloadEnvelopeInputs",
1611
1648
  }),
1612
- created: register.counter({
1649
+ created: register.counter<{source: PayloadEnvelopeInputSource}>({
1613
1650
  name: "lodestar_seen_payload_envelope_input_cache_items_created_total",
1614
- help: "Number of PayloadEnvelopeInputs created",
1651
+ help: "Number of PayloadEnvelopeInputs created by source",
1652
+ labelNames: ["source"],
1653
+ }),
1654
+ pruned: register.counter<{reason: PayloadEnvelopeInputPruneReason}>({
1655
+ name: "lodestar_seen_payload_envelope_input_cache_items_pruned_total",
1656
+ help: "Number of PayloadEnvelopeInputs evicted by reason",
1657
+ labelNames: ["reason"],
1615
1658
  }),
1616
1659
  },
1617
1660
  },