diff --git a/packages/api/src/beacon/routes/lodestar.ts b/packages/api/src/beacon/routes/lodestar.ts index 3c12fa1d4b80..527199d95dad 100644 --- a/packages/api/src/beacon/routes/lodestar.ts +++ b/packages/api/src/beacon/routes/lodestar.ts @@ -98,7 +98,7 @@ export type Api = { getRegenQueueItems(): Promise>; /** Dump all items in the block processor queue */ getBlockProcessorQueueItems(): Promise>; - /** Dump a summary of the states in the StateContextCache */ + /** Dump a summary of the states in the block state cache and checkpoint state cache */ getStateCacheItems(): Promise>; /** Dump peer gossip stats by peer */ getGossipPeerScoreStats(): Promise>; diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 44568b0d942b..047f7741c2f2 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -80,7 +80,7 @@ import {BlockInput} from "./blocks/types.js"; import {SeenAttestationDatas} from "./seenCache/seenAttestationData.js"; import {BlockRewards, computeBlockRewards} from "./rewards/blockRewards.js"; import {ShufflingCache} from "./shufflingCache.js"; -import {StateContextCache} from "./stateCache/stateContextCache.js"; +import {BlockStateCacheImpl} from "./stateCache/blockStateCacheImpl.js"; import {SeenGossipBlockInput} from "./seenCache/index.js"; import {InMemoryCheckpointStateCache} from "./stateCache/inMemoryCheckpointsCache.js"; import {FIFOBlockStateCache} from "./stateCache/fifoBlockStateCache.js"; @@ -247,9 +247,9 @@ export class BeaconChain implements IBeaconChain { this.index2pubkey = cachedState.epochCtx.index2pubkey; const fileDataStore = opts.nHistoricalStatesFileDataStore ?? false; - const stateCache = this.opts.nHistoricalStates + const blockStateCache = this.opts.nHistoricalStates ? new FIFOBlockStateCache(this.opts, {metrics}) - : new StateContextCache({metrics}); + : new BlockStateCacheImpl({metrics}); const checkpointStateCache = this.opts.nHistoricalStates ? new PersistentCheckpointStateCache( { @@ -257,7 +257,7 @@ export class BeaconChain implements IBeaconChain { logger, clock, shufflingCache: this.shufflingCache, - blockStateCache: stateCache, + blockStateCache, bufferPool: new BufferPool(anchorState.type.tree_serializedSize(anchorState.node), metrics), datastore: fileDataStore ? // debug option if we want to investigate any issues with the DB @@ -269,8 +269,8 @@ export class BeaconChain implements IBeaconChain { ) : new InMemoryCheckpointStateCache({metrics}); const {checkpoint} = computeAnchorCheckpoint(config, anchorState); - stateCache.add(cachedState); - stateCache.setHeadState(cachedState); + blockStateCache.add(cachedState); + blockStateCache.setHeadState(cachedState); checkpointStateCache.add(checkpoint, cachedState); const forkChoice = initializeForkChoice( @@ -284,7 +284,7 @@ export class BeaconChain implements IBeaconChain { const regen = new QueuedStateRegenerator({ config, forkChoice, - stateCache, + blockStateCache, checkpointStateCache, db, metrics, diff --git a/packages/beacon-node/src/chain/regen/queued.ts b/packages/beacon-node/src/chain/regen/queued.ts index 1b2456d2b325..148ec756497d 100644 --- a/packages/beacon-node/src/chain/regen/queued.ts +++ b/packages/beacon-node/src/chain/regen/queued.ts @@ -34,7 +34,7 @@ export class QueuedStateRegenerator implements IStateRegenerator { private readonly regen: StateRegenerator; private readonly forkChoice: IForkChoice; - private readonly stateCache: BlockStateCache; + private readonly blockStateCache: BlockStateCache; private readonly checkpointStateCache: CheckpointStateCache; private readonly metrics: Metrics | null; private readonly logger: Logger; @@ -47,7 +47,7 @@ export class QueuedStateRegenerator implements IStateRegenerator { modules.metrics ? modules.metrics.regenQueue : undefined ); this.forkChoice = modules.forkChoice; - this.stateCache = modules.stateCache; + this.blockStateCache = modules.blockStateCache; this.checkpointStateCache = modules.checkpointStateCache; this.metrics = modules.metrics; this.logger = modules.logger; @@ -64,12 +64,12 @@ export class QueuedStateRegenerator implements IStateRegenerator { } dropCache(): void { - this.stateCache.clear(); + this.blockStateCache.clear(); this.checkpointStateCache.clear(); } dumpCacheSummary(): routes.lodestar.StateCacheItem[] { - return [...this.stateCache.dumpSummary(), ...this.checkpointStateCache.dumpSummary()]; + return [...this.blockStateCache.dumpSummary(), ...this.checkpointStateCache.dumpSummary()]; } /** @@ -77,7 +77,7 @@ export class QueuedStateRegenerator implements IStateRegenerator { * This is not for block processing so don't transfer cache */ getStateSync(stateRoot: RootHex): CachedBeaconStateAllForks | null { - return this.stateCache.get(stateRoot, {dontTransferCache: true}); + return this.blockStateCache.get(stateRoot, {dontTransferCache: true}); } /** @@ -113,7 +113,7 @@ export class QueuedStateRegenerator implements IStateRegenerator { // Otherwise the state transition may not be cached and wasted. Queue for regen since the // work required will still be significant. if (parentEpoch === blockEpoch) { - const state = this.stateCache.get(parentBlock.stateRoot, opts); + const state = this.blockStateCache.get(parentBlock.stateRoot, opts); if (state) { return state; } @@ -139,22 +139,23 @@ export class QueuedStateRegenerator implements IStateRegenerator { getClosestHeadState(head: ProtoBlock): CachedBeaconStateAllForks | null { const opts = {dontTransferCache: true}; return ( - this.checkpointStateCache.getLatest(head.blockRoot, Infinity, opts) || this.stateCache.get(head.stateRoot, opts) + this.checkpointStateCache.getLatest(head.blockRoot, Infinity, opts) || + this.blockStateCache.get(head.stateRoot, opts) ); } pruneOnCheckpoint(finalizedEpoch: Epoch, justifiedEpoch: Epoch, headStateRoot: RootHex): void { this.checkpointStateCache.prune(finalizedEpoch, justifiedEpoch); - this.stateCache.prune(headStateRoot); + this.blockStateCache.prune(headStateRoot); } pruneOnFinalized(finalizedEpoch: number): void { this.checkpointStateCache.pruneFinalized(finalizedEpoch); - this.stateCache.deleteAllBeforeEpoch(finalizedEpoch); + this.blockStateCache.deleteAllBeforeEpoch(finalizedEpoch); } processState(blockRootHex: RootHex, postState: CachedBeaconStateAllForks): void { - this.stateCache.add(postState); + this.blockStateCache.add(postState); this.checkpointStateCache.processState(blockRootHex, postState).catch((e) => { this.logger.debug("Error processing block state", {blockRootHex, slot: postState.slot}, e); }); @@ -170,10 +171,10 @@ export class QueuedStateRegenerator implements IStateRegenerator { const headState = newHeadStateRoot === toHexString(maybeHeadState.hashTreeRoot()) ? maybeHeadState - : this.stateCache.get(newHeadStateRoot, cloneOpts); + : this.blockStateCache.get(newHeadStateRoot, cloneOpts); if (headState) { - this.stateCache.setHeadState(headState); + this.blockStateCache.setHeadState(headState); } else { // Trigger regen on head change if necessary this.logger.warn("Head state not available, triggering regen", {stateRoot: newHeadStateRoot}); @@ -182,9 +183,9 @@ export class QueuedStateRegenerator implements IStateRegenerator { // head has changed, so the existing cached head state is no longer useful. Set strong reference to null to free // up memory for regen step below. During regen, node won't be functional but eventually head will be available // for legacy StateContextCache only - this.stateCache.setHeadState(null); + this.blockStateCache.setHeadState(null); this.regen.getState(newHeadStateRoot, RegenCaller.processBlock, cloneOpts, allowDiskReload).then( - (headStateRegen) => this.stateCache.setHeadState(headStateRegen), + (headStateRegen) => this.blockStateCache.setHeadState(headStateRegen), (e) => this.logger.error("Error on head state regen", {}, e) ); } @@ -261,7 +262,7 @@ export class QueuedStateRegenerator implements IStateRegenerator { this.metrics?.regenFnCallTotal.inc({caller: rCaller, entrypoint: RegenFnName.getState}); // First attempt to fetch the state from cache before queueing - const state = this.stateCache.get(stateRoot, opts); + const state = this.blockStateCache.get(stateRoot, opts); if (state) { return state; } diff --git a/packages/beacon-node/src/chain/regen/regen.ts b/packages/beacon-node/src/chain/regen/regen.ts index ccfbd44a8f7b..f57c37cc95a5 100644 --- a/packages/beacon-node/src/chain/regen/regen.ts +++ b/packages/beacon-node/src/chain/regen/regen.ts @@ -24,7 +24,7 @@ import {RegenError, RegenErrorCode} from "./errors.js"; export type RegenModules = { db: IBeaconDb; forkChoice: IForkChoice; - stateCache: BlockStateCache; + blockStateCache: BlockStateCache; checkpointStateCache: CheckpointStateCache; config: ChainForkConfig; emitter: ChainEventEmitter; @@ -150,7 +150,7 @@ export class StateRegenerator implements IStateRegeneratorInternal { allowDiskReload = false ): Promise { // Trivial case, state at stateRoot is already cached - const cachedStateCtx = this.modules.stateCache.get(stateRoot, opts); + const cachedStateCtx = this.modules.blockStateCache.get(stateRoot, opts); if (cachedStateCtx) { return cachedStateCtx; } @@ -167,7 +167,7 @@ export class StateRegenerator implements IStateRegeneratorInternal { const {checkpointStateCache} = this.modules; // iterateAncestorBlocks only returns ancestor blocks, not the block itself for (const b of this.modules.forkChoice.iterateAncestorBlocks(block.blockRoot)) { - state = this.modules.stateCache.get(b.stateRoot, opts); + state = this.modules.blockStateCache.get(b.stateRoot, opts); if (state) { break; } @@ -235,7 +235,7 @@ export class StateRegenerator implements IStateRegeneratorInternal { if (allowDiskReload) { // also with allowDiskReload flag, we "reload" it to the state cache too - this.modules.stateCache.add(state); + this.modules.blockStateCache.add(state); } // this avoids keeping our node busy processing blocks diff --git a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts b/packages/beacon-node/src/chain/stateCache/blockStateCacheImpl.ts similarity index 95% rename from packages/beacon-node/src/chain/stateCache/stateContextCache.ts rename to packages/beacon-node/src/chain/stateCache/blockStateCacheImpl.ts index e15f46b91a9f..fdeb3ed5a659 100644 --- a/packages/beacon-node/src/chain/stateCache/stateContextCache.ts +++ b/packages/beacon-node/src/chain/stateCache/blockStateCacheImpl.ts @@ -10,11 +10,11 @@ import {BlockStateCache} from "./types.js"; const MAX_STATES = 3 * 32; /** - * Old implementation of StateCache + * Old implementation of StateCache (used to call `StateContextCache`) * - Prune per checkpoint so number of states ranges from 96 to 128 * - Keep a separate head state to make sure it is always available */ -export class StateContextCache implements BlockStateCache { +export class BlockStateCacheImpl implements BlockStateCache { /** * Max number of states allowed in the cache */ @@ -83,7 +83,7 @@ export class StateContextCache implements BlockStateCache { * See ./fifoBlockStateCache.ts for implementation */ getSeedState(): CachedBeaconStateAllForks { - throw Error("Not implemented for StateContextCache"); + throw Error("Not implemented for BlockStateCacheImpl"); } clear(): void { diff --git a/packages/beacon-node/src/chain/stateCache/index.ts b/packages/beacon-node/src/chain/stateCache/index.ts index 2281566730d7..a38589b86005 100644 --- a/packages/beacon-node/src/chain/stateCache/index.ts +++ b/packages/beacon-node/src/chain/stateCache/index.ts @@ -1,3 +1,3 @@ -export * from "./stateContextCache.js"; +export * from "./blockStateCacheImpl.js"; export * from "./inMemoryCheckpointsCache.js"; export * from "./fifoBlockStateCache.js"; diff --git a/packages/beacon-node/test/unit/chain/stateCache/stateContextCache.test.ts b/packages/beacon-node/test/unit/chain/stateCache/blockStateCacheImpl.test.ts similarity index 88% rename from packages/beacon-node/test/unit/chain/stateCache/stateContextCache.test.ts rename to packages/beacon-node/test/unit/chain/stateCache/blockStateCacheImpl.test.ts index cca4d7ea7734..b89a71399237 100644 --- a/packages/beacon-node/test/unit/chain/stateCache/stateContextCache.test.ts +++ b/packages/beacon-node/test/unit/chain/stateCache/blockStateCacheImpl.test.ts @@ -3,12 +3,12 @@ import {describe, it, expect, beforeEach} from "vitest"; import {EpochShuffling} from "@lodestar/state-transition"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {Root} from "@lodestar/types"; -import {StateContextCache} from "../../../../src/chain/stateCache/index.js"; +import {BlockStateCacheImpl} from "../../../../src/chain/stateCache/index.js"; import {generateCachedState} from "../../../utils/state.js"; import {ZERO_HASH} from "../../../../src/constants/index.js"; -describe("StateContextCache", function () { - let cache: StateContextCache; +describe("BlockStateCacheImpl", function () { + let cache: BlockStateCacheImpl; let key1: Root, key2: Root; const shuffling: EpochShuffling = { epoch: 0, @@ -20,7 +20,7 @@ describe("StateContextCache", function () { beforeEach(function () { // max 2 items - cache = new StateContextCache({maxStates: 2}); + cache = new BlockStateCacheImpl({maxStates: 2}); const state1 = generateCachedState({slot: 0}); key1 = state1.hashTreeRoot(); state1.epochCtx.currentShuffling = {...shuffling, epoch: 0};