@lodestar/beacon-node
Version:
A Typescript implementation of the beacon chain
144 lines (120 loc) • 5.09 kB
text/typescript
import {ChainForkConfig} from "@lodestar/config";
import {Db, LevelDbControllerMetrics, encodeKey} from "@lodestar/db";
import {Bucket} from "./buckets.js";
import {IBeaconDb} from "./interface.js";
import {CheckpointStateRepository} from "./repositories/checkpointState.js";
import {
AttesterSlashingRepository,
BLSToExecutionChangeRepository,
BackfilledRanges,
BestLightClientUpdateRepository,
BlobSidecarsArchiveRepository,
BlobSidecarsRepository,
BlockArchiveRepository,
BlockRepository,
CheckpointHeaderRepository,
DataColumnSidecarArchiveRepository,
DataColumnSidecarRepository,
ExecutionPayloadEnvelopeArchiveRepository,
ExecutionPayloadEnvelopeRepository,
ProposerSlashingRepository,
StateArchiveRepository,
SyncCommitteeRepository,
SyncCommitteeWitnessRepository,
VoluntaryExitRepository,
} from "./repositories/index.js";
export type BeaconDbModules = {
config: ChainForkConfig;
db: Db;
};
export class BeaconDb implements IBeaconDb {
block: BlockRepository;
blockArchive: BlockArchiveRepository;
blobSidecars: BlobSidecarsRepository;
blobSidecarsArchive: BlobSidecarsArchiveRepository;
dataColumnSidecar: DataColumnSidecarRepository;
dataColumnSidecarArchive: DataColumnSidecarArchiveRepository;
executionPayloadEnvelope: ExecutionPayloadEnvelopeRepository;
executionPayloadEnvelopeArchive: ExecutionPayloadEnvelopeArchiveRepository;
stateArchive: StateArchiveRepository;
checkpointState: CheckpointStateRepository;
voluntaryExit: VoluntaryExitRepository;
proposerSlashing: ProposerSlashingRepository;
attesterSlashing: AttesterSlashingRepository;
blsToExecutionChange: BLSToExecutionChangeRepository;
// lightclient
bestLightClientUpdate: BestLightClientUpdateRepository;
checkpointHeader: CheckpointHeaderRepository;
syncCommittee: SyncCommitteeRepository;
syncCommitteeWitness: SyncCommitteeWitnessRepository;
backfilledRanges: BackfilledRanges;
constructor(
config: ChainForkConfig,
protected readonly db: Db
) {
// Warning: If code is ever run in the constructor, must change this stub to not extend 'packages/beacon-node/test/utils/stub/beaconDb.ts' -
this.block = new BlockRepository(config, db);
this.blockArchive = new BlockArchiveRepository(config, db);
this.blobSidecars = new BlobSidecarsRepository(config, db);
this.blobSidecarsArchive = new BlobSidecarsArchiveRepository(config, db);
this.dataColumnSidecar = new DataColumnSidecarRepository(config, db);
this.dataColumnSidecarArchive = new DataColumnSidecarArchiveRepository(config, db);
this.executionPayloadEnvelope = new ExecutionPayloadEnvelopeRepository(config, db);
this.executionPayloadEnvelopeArchive = new ExecutionPayloadEnvelopeArchiveRepository(config, db);
this.stateArchive = new StateArchiveRepository(config, db);
this.checkpointState = new CheckpointStateRepository(config, db);
this.voluntaryExit = new VoluntaryExitRepository(config, db);
this.blsToExecutionChange = new BLSToExecutionChangeRepository(config, db);
this.proposerSlashing = new ProposerSlashingRepository(config, db);
this.attesterSlashing = new AttesterSlashingRepository(config, db);
// lightclient
this.bestLightClientUpdate = new BestLightClientUpdateRepository(config, db);
this.checkpointHeader = new CheckpointHeaderRepository(config, db);
this.syncCommittee = new SyncCommitteeRepository(config, db);
this.syncCommitteeWitness = new SyncCommitteeWitnessRepository(config, db);
this.backfilledRanges = new BackfilledRanges(config, db);
}
close(): Promise<void> {
return this.db.close();
}
setMetrics(metrics: LevelDbControllerMetrics): void {
this.db.setMetrics(metrics);
}
async pruneHotDb(): Promise<void> {
// Prune all hot blobs
await this.blobSidecars.batchDelete(await this.blobSidecars.keys());
// Prune all hot blocks
// TODO: Enable once it's deemed safe
// await this.block.batchDelete(await this.block.keys());
}
async deleteDeprecatedEth1Data(): Promise<void> {
const deprecatedBuckets = [
Bucket.phase0_eth1Data,
Bucket.index_depositDataRoot,
Bucket.phase0_depositData,
Bucket.phase0_depositEvent,
Bucket.phase0_preGenesisState,
Bucket.phase0_preGenesisStateLastProcessedBlock,
];
for (const bucket of deprecatedBuckets) {
await this.deleteBucketData(bucket);
}
}
private async deleteBucketData(bucket: Bucket): Promise<void> {
const minKey = encodeKey(bucket, Buffer.alloc(0));
const maxKey = encodeKey(bucket + 1, Buffer.alloc(0));
// Batch delete to avoid loading all keys into memory at once
const BATCH_DELETE_SIZE = 1000;
let keysBatch: Uint8Array[] = [];
for await (const key of this.db.keysStream({gte: minKey, lt: maxKey})) {
keysBatch.push(key);
if (keysBatch.length >= BATCH_DELETE_SIZE) {
await this.db.batchDelete(keysBatch);
keysBatch = [];
}
}
if (keysBatch.length > 0) {
await this.db.batchDelete(keysBatch);
}
}
}