UNPKG

@lodestar/beacon-node

Version:

A Typescript implementation of the beacon chain

83 lines 4.34 kB
import { computeEpochAtSlot } from "@lodestar/state-transition"; import { BLOB_AND_PROOF_V2_RPC_BYTES } from "../execution/engine/types.js"; import { callInNextEventLoop } from "../util/eventLoop.js"; import { DataColumnEngineResult, getBlobSidecarsFromExecution, getDataColumnSidecarsFromExecution, } from "../util/execution.js"; import { isBlockInputBlobs } from "./blocks/blockInput/index.js"; import { PayloadEnvelopeInput } from "./blocks/payloadEnvelopeInput/index.js"; /** * Tracks getBlobsV2 calls to the execution engine to avoid duplicate and multiple in-flight calls */ export class GetBlobsTracker { logger; executionEngine; emitter; metrics; config; activeReconstructions = new Set(); // Preallocate buffers for getBlobsV2 RPC calls // See https://github.com/ChainSafe/lodestar/pull/8282 for context blobsAndProofsBuffers = []; constructor(init) { this.logger = init.logger; this.executionEngine = init.executionEngine; this.emitter = init.emitter; this.metrics = init.metrics; this.config = init.config; } triggerGetBlobs(input) { if (this.activeReconstructions.has(input.blockRootHex)) { return; } if (!(input instanceof PayloadEnvelopeInput) && isBlockInputBlobs(input)) { // there is not preallocation for blob sidecars like there is for columns sidecars so no need to // store the index for the preallocated buffers this.activeReconstructions.add(input.blockRootHex); callInNextEventLoop(() => { const logCtx = { slot: input.slot, root: input.blockRootHex }; this.logger.verbose("Trigger getBlobsV1 for block", logCtx); getBlobSidecarsFromExecution(this.config, this.executionEngine, this.metrics, this.emitter, input).finally(() => { this.logger.verbose("Completed getBlobsV1 for block", logCtx); this.activeReconstructions.delete(input.blockRootHex); }); }); return; } let freeIndex = this.blobsAndProofsBuffers.findIndex(({ inUse }) => !inUse); if (freeIndex === -1) { freeIndex = this.blobsAndProofsBuffers.length; this.blobsAndProofsBuffers[freeIndex] = { inUse: false, buffers: [] }; } const maxBlobs = this.config.getMaxBlobsPerBlock(computeEpochAtSlot(input.slot)); // double check that there is enough pre-allocated space (blob schedule may have changed since the last use) const timer = this.metrics?.peerDas.getBlobsV2PreAllocationTime.startTimer(); for (let i = 0; i < maxBlobs; i++) { if (this.blobsAndProofsBuffers[freeIndex].buffers[i] === undefined) { this.blobsAndProofsBuffers[freeIndex].buffers[i] = new Uint8Array(BLOB_AND_PROOF_V2_RPC_BYTES); } } timer?.(); // We don't care about the outcome of this call, // just that it has been triggered for this block root. this.activeReconstructions.add(input.blockRootHex); this.blobsAndProofsBuffers[freeIndex].inUse = true; callInNextEventLoop(() => { const logCtx = { slot: input.slot, root: input.blockRootHex }; this.logger.verbose("Trigger getBlobsV2 for block", logCtx); getDataColumnSidecarsFromExecution(this.config, this.executionEngine, this.emitter, input, this.metrics, this.blobsAndProofsBuffers[freeIndex].buffers) .then((result) => { this.logger.debug("getBlobsV2 result for block", { ...logCtx, result }); this.metrics?.dataColumns.dataColumnEngineResult.inc({ result }); }) .catch((error) => { this.logger.debug("Error during getBlobsV2 for block", logCtx, error); this.metrics?.dataColumns.dataColumnEngineResult.inc({ result: DataColumnEngineResult.Failed }); }) .finally(() => { this.logger.verbose("Completed getBlobsV2 for block", logCtx); this.activeReconstructions.delete(input.blockRootHex); this.blobsAndProofsBuffers[freeIndex].inUse = false; }); }); } } //# sourceMappingURL=GetBlobsTracker.js.map