@lodestar/beacon-node 1.39.0-dev.171bfe3042 → 1.39.0-dev.219c3c247e

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.
@@ -1,11 +1,4 @@
1
- import {
2
- BeaconStateAllForks,
3
- EpochShuffling,
4
- IShufflingCache,
5
- ShufflingBuildProps,
6
- computeEpochShuffling,
7
- computeEpochShufflingAsync,
8
- } from "@lodestar/state-transition";
1
+ import {CachedBeaconStateAllForks, EpochShuffling} from "@lodestar/state-transition";
9
2
  import {Epoch, RootHex} from "@lodestar/types";
10
3
  import {LodestarError, Logger, MapDef, pruneSetToMax} from "@lodestar/utils";
11
4
  import {Metrics} from "../metrics/metrics.js";
@@ -53,7 +46,7 @@ export type ShufflingCacheOpts = {
53
46
  * - if a shuffling is not available (which does not happen with default chain option of maxSkipSlots = 32), track a promise to make sure we don't compute the same shuffling twice
54
47
  * - skip computing shuffling when loading state bytes from disk
55
48
  */
56
- export class ShufflingCache implements IShufflingCache {
49
+ export class ShufflingCache {
57
50
  /** LRU cache implemented as a map, pruned every time we add an item */
58
51
  private readonly itemsByDecisionRootByEpoch: MapDef<Epoch, Map<RootHex, CacheItem>> = new MapDef(
59
52
  () => new Map<RootHex, CacheItem>()
@@ -136,60 +129,20 @@ export class ShufflingCache implements IShufflingCache {
136
129
  }
137
130
 
138
131
  /**
139
- * Gets a cached shuffling via the epoch and decision root. If the shuffling is not
140
- * available it will build it synchronously and return the shuffling.
141
- *
142
- * NOTE: If a shuffling is already queued and not calculated it will build and resolve
143
- * the promise but the already queued build will happen at some later time
132
+ * Process a state to extract and cache all shufflings (previous, current, next).
133
+ * Uses the stored decision roots from epochCtx.
144
134
  */
145
- getSync<T extends ShufflingBuildProps | undefined>(
146
- epoch: Epoch,
147
- decisionRoot: RootHex,
148
- buildProps?: T
149
- ): T extends ShufflingBuildProps ? EpochShuffling : EpochShuffling | null {
150
- const cacheItem = this.itemsByDecisionRootByEpoch.getOrDefault(epoch).get(decisionRoot);
151
- if (!cacheItem) {
152
- this.metrics?.shufflingCache.miss.inc();
153
- } else if (isShufflingCacheItem(cacheItem)) {
154
- this.metrics?.shufflingCache.hit.inc();
155
- return cacheItem.shuffling;
156
- } else if (buildProps) {
157
- // TODO: (@matthewkeil) This should possible log a warning??
158
- this.metrics?.shufflingCache.shufflingPromiseNotResolvedAndThrownAway.inc();
159
- } else {
160
- this.metrics?.shufflingCache.shufflingPromiseNotResolved.inc();
161
- }
135
+ processState(state: CachedBeaconStateAllForks): void {
136
+ const {epochCtx} = state;
162
137
 
163
- let shuffling: EpochShuffling | null = null;
164
- if (buildProps) {
165
- const timer = this.metrics?.shufflingCache.shufflingCalculationTime.startTimer({source: "getSync"});
166
- shuffling = computeEpochShuffling(buildProps.state, buildProps.activeIndices, epoch);
167
- timer?.();
168
- this.set(shuffling, decisionRoot);
169
- }
170
- return shuffling as T extends ShufflingBuildProps ? EpochShuffling : EpochShuffling | null;
171
- }
138
+ // Cache previous shuffling
139
+ this.set(epochCtx.previousShuffling, epochCtx.previousDecisionRoot);
172
140
 
173
- /**
174
- * Queue asynchronous build for an EpochShuffling, triggered from state-transition
175
- */
176
- build(epoch: number, decisionRoot: string, state: BeaconStateAllForks, activeIndices: Uint32Array): void {
177
- this.insertPromise(epoch, decisionRoot);
178
- /**
179
- * TODO: (@matthewkeil) This will get replaced by a proper build queue and a worker to do calculations
180
- * on a NICE thread
181
- */
182
- const timer = this.metrics?.shufflingCache.shufflingCalculationTime.startTimer({source: "build"});
183
- computeEpochShufflingAsync(state, activeIndices, epoch)
184
- .then((shuffling) => {
185
- this.set(shuffling, decisionRoot);
186
- })
187
- .catch((err) =>
188
- this.logger?.error(`error building shuffling for epoch ${epoch} at decisionRoot ${decisionRoot}`, {}, err)
189
- )
190
- .finally(() => {
191
- timer?.();
192
- });
141
+ // Cache current shuffling
142
+ this.set(epochCtx.currentShuffling, epochCtx.currentDecisionRoot);
143
+
144
+ // Cache next shuffling
145
+ this.set(epochCtx.nextShuffling, epochCtx.nextDecisionRoot);
193
146
  }
194
147
 
195
148
  /**
@@ -207,7 +160,8 @@ export class ShufflingCache implements IShufflingCache {
207
160
  (Date.now() - cacheItem.timeInsertedMs) / 1000
208
161
  );
209
162
  } else {
210
- this.metrics?.shufflingCache.shufflingBuiltMultipleTimes.inc();
163
+ this.metrics?.shufflingCache.shufflingSetMultipleTimes.inc();
164
+ return;
211
165
  }
212
166
  }
213
167
  // set the shuffling
@@ -1308,33 +1308,19 @@ export function createLodestarMetrics(
1308
1308
  name: "lodestar_shuffling_cache_miss_count",
1309
1309
  help: "Count of shuffling cache miss",
1310
1310
  }),
1311
- shufflingBuiltMultipleTimes: register.gauge({
1312
- name: "lodestar_shuffling_cache_recalculated_shuffling_count",
1313
- help: "Count of shuffling that were build multiple times",
1314
- }),
1315
- shufflingPromiseNotResolvedAndThrownAway: register.gauge({
1316
- name: "lodestar_shuffling_cache_promise_not_resolved_and_thrown_away_count",
1317
- help: "Count of shuffling cache promises that were discarded and the shuffling was built synchronously",
1311
+ shufflingSetMultipleTimes: register.gauge({
1312
+ name: "lodestar_shuffling_cache_set_multiple_times_count",
1313
+ help: "Count of shuffling that were set multiple times",
1318
1314
  }),
1319
1315
  shufflingPromiseNotResolved: register.gauge({
1320
1316
  name: "lodestar_shuffling_cache_promise_not_resolved_count",
1321
1317
  help: "Count of shuffling cache promises that were requested before the promise was resolved",
1322
1318
  }),
1323
- nextShufflingNotOnEpochCache: register.gauge({
1324
- name: "lodestar_shuffling_cache_next_shuffling_not_on_epoch_cache",
1325
- help: "The next shuffling was not on the epoch cache before the epoch transition",
1326
- }),
1327
1319
  shufflingPromiseResolutionTime: register.histogram({
1328
1320
  name: "lodestar_shuffling_cache_promise_resolution_time_seconds",
1329
1321
  help: "Time from promise insertion until promise resolution when shuffling was ready in seconds",
1330
1322
  buckets: [0.5, 1, 1.5, 2],
1331
1323
  }),
1332
- shufflingCalculationTime: register.histogram<{source: "build" | "getSync"}>({
1333
- name: "lodestar_shuffling_cache_shuffling_calculation_time_seconds",
1334
- help: "Run time of shuffling calculation",
1335
- buckets: [0.5, 0.75, 1, 1.25, 1.5],
1336
- labelNames: ["source"],
1337
- }),
1338
1324
  },
1339
1325
 
1340
1326
  seenCache: {