UNPKG

@lodestar/beacon-node

Version:

A Typescript implementation of the beacon chain

129 lines 5.16 kB
import { Repository } from "@lodestar/db"; import { ssz } from "@lodestar/types"; import { bytesToInt } from "@lodestar/utils"; import all from "it-all"; import { getSignedBlockTypeFromBytes } from "../../util/multifork.js"; import { Bucket, getBucketNameByValue } from "../buckets.js"; import { getParentRootIndexKey, getRootIndexKey } from "./blockArchiveIndex.js"; import { deleteParentRootIndex, deleteRootIndex, storeParentRootIndex, storeRootIndex } from "./blockArchiveIndex.js"; /** * Stores finalized blocks. Block slot is identifier. */ export class BlockArchiveRepository extends Repository { constructor(config, db) { const bucket = Bucket.allForks_blockArchive; const type = ssz.phase0.SignedBeaconBlock; // Pick some type but won't be used super(config, db, bucket, type, getBucketNameByValue(bucket)); } // Overrides for multi-fork encodeValue(value) { return this.config.getForkTypes(value.message.slot).SignedBeaconBlock.serialize(value); } decodeValue(data) { return getSignedBlockTypeFromBytes(this.config, data).deserialize(data); } // Handle key as slot getId(value) { return value.message.slot; } decodeKey(data) { return bytesToInt(super.decodeKey(data), "be"); } // Overrides to index async put(key, value) { const blockRoot = this.config.getForkTypes(value.message.slot).BeaconBlock.hashTreeRoot(value.message); const slot = value.message.slot; await Promise.all([ super.put(key, value), storeRootIndex(this.db, slot, blockRoot), storeParentRootIndex(this.db, slot, value.message.parentRoot), ]); } async batchPut(items) { await Promise.all([ super.batchPut(items), Array.from(items).map((item) => { const slot = item.value.message.slot; const blockRoot = this.config.getForkTypes(slot).BeaconBlock.hashTreeRoot(item.value.message); return storeRootIndex(this.db, slot, blockRoot); }), Array.from(items).map((item) => { const slot = item.value.message.slot; const parentRoot = item.value.message.parentRoot; return storeParentRootIndex(this.db, slot, parentRoot); }), ]); } async batchPutBinary(items) { await Promise.all([ super.batchPutBinary(items), Array.from(items).map((item) => storeRootIndex(this.db, item.slot, item.blockRoot)), Array.from(items).map((item) => storeParentRootIndex(this.db, item.slot, item.parentRoot)), ]); } async remove(value) { await Promise.all([ super.remove(value), deleteRootIndex(this.db, this.config.getForkTypes(value.message.slot).SignedBeaconBlock, value), deleteParentRootIndex(this.db, value), ]); } async batchRemove(values) { await Promise.all([ super.batchRemove(values), Array.from(values).map((value) => deleteRootIndex(this.db, this.config.getForkTypes(value.message.slot).SignedBeaconBlock, value)), Array.from(values).map((value) => deleteParentRootIndex(this.db, value)), ]); } async *valuesStream(opts) { const firstSlot = this.getFirstSlot(opts); const valuesStream = super.valuesStream(opts); const step = opts?.step ?? 1; for await (const value of valuesStream) { if ((value.message.slot - firstSlot) % step === 0) { yield value; } } } async values(opts) { return all(this.valuesStream(opts)); } // INDEX async getByRoot(root) { const slot = await this.getSlotByRoot(root); return slot !== null ? this.get(slot) : null; } async getBinaryEntryByRoot(root) { const slot = await this.getSlotByRoot(root); return slot !== null ? { key: slot, value: await this.getBinary(slot) } : null; } async getByParentRoot(root) { const slot = await this.getSlotByParentRoot(root); return slot !== null ? this.get(slot) : null; } async getSlotByRoot(root) { return this.parseSlot(await this.db.get(getRootIndexKey(root))); } async getSlotByParentRoot(root) { return this.parseSlot(await this.db.get(getParentRootIndexKey(root))); } parseSlot(slotBytes) { if (!slotBytes) return null; const slot = bytesToInt(slotBytes, "be"); // TODO: Is this necessary? How can bytesToInt return a non-integer? return Number.isInteger(slot) ? slot : null; } getFirstSlot(opts) { const dbFilterOpts = this.dbFilterOptions(opts); const firstSlot = dbFilterOpts.gt ? this.decodeKey(dbFilterOpts.gt) + 1 : dbFilterOpts.gte ? this.decodeKey(dbFilterOpts.gte) : null; if (firstSlot === null) throw Error("specify opts.gt or opts.gte"); return firstSlot; } } //# sourceMappingURL=blockArchive.js.map