@lodestar/beacon-node
Version:
A Typescript implementation of the beacon chain
99 lines • 3.86 kB
JavaScript
import { GENESIS_SLOT } from "@lodestar/params";
import { getValidatorStatus } from "@lodestar/types";
import { fromHex } from "@lodestar/utils";
import { ApiError, ValidationError } from "../../errors.js";
export function resolveStateId(forkChoice, stateId) {
if (stateId === "head") {
return forkChoice.getHead().stateRoot;
}
if (stateId === "genesis") {
return GENESIS_SLOT;
}
if (stateId === "finalized") {
return forkChoice.getFinalizedCheckpoint();
}
if (stateId === "justified") {
return forkChoice.getJustifiedCheckpoint();
}
if (typeof stateId === "string" && stateId.startsWith("0x")) {
return stateId;
}
// id must be slot
const blockSlot = parseInt(String(stateId), 10);
if (Number.isNaN(blockSlot) && Number.isNaN(blockSlot - 0)) {
throw new ValidationError(`Invalid block id '${stateId}'`, "blockId");
}
return blockSlot;
}
export async function getStateResponseWithRegen(chain, inStateId) {
const stateId = resolveStateId(chain.forkChoice, inStateId);
const res = typeof stateId === "string"
? await chain.getStateByStateRoot(stateId, { allowRegen: true })
: typeof stateId === "number"
? stateId > chain.clock.currentSlot
? null // Don't try to serve future slots
: stateId >= chain.forkChoice.getFinalizedBlock().slot
? await chain.getStateBySlot(stateId, { allowRegen: true })
: await chain.getHistoricalStateBySlot(stateId)
: await chain.getStateOrBytesByCheckpoint(stateId);
if (!res) {
throw new ApiError(404, `State not found for id '${inStateId}'`);
}
return res;
}
export function toValidatorResponse(index, validator, balance, currentEpoch) {
return {
index,
status: getValidatorStatus(validator, currentEpoch),
balance,
validator,
};
}
export function filterStateValidatorsByStatus(statuses, state, pubkeyCache, currentEpoch) {
const responses = [];
const validators = state.getValidatorsByStatus(new Set(statuses), currentEpoch);
for (const validator of validators) {
const resp = getStateValidatorIndex(validator.pubkey, state, pubkeyCache);
if (resp.valid) {
responses.push(toValidatorResponse(resp.validatorIndex, validator, state.getBalance(resp.validatorIndex), currentEpoch));
}
}
return responses;
}
export function getStateValidatorIndex(id, state, pubkeyCache) {
if (typeof id === "string") {
// mutate `id` and fallthrough to below
if (id.startsWith("0x")) {
try {
id = fromHex(id);
}
catch (_e) {
return { valid: false, code: 400, reason: "Invalid pubkey hex encoding" };
}
}
else {
id = Number(id);
}
}
if (typeof id === "number") {
const validatorIndex = id;
// validator is invalid or added later than given stateId
if (!Number.isSafeInteger(validatorIndex)) {
return { valid: false, code: 400, reason: "Invalid validator index" };
}
if (validatorIndex >= state.validatorCount) {
return { valid: false, code: 404, reason: "Validator index from future state" };
}
return { valid: true, validatorIndex };
}
// typeof id === Uint8Array
const validatorIndex = pubkeyCache.getIndex(id);
if (validatorIndex === null) {
return { valid: false, code: 404, reason: "Validator pubkey not found in state" };
}
if (validatorIndex >= state.validatorCount) {
return { valid: false, code: 404, reason: "Validator pubkey from future state" };
}
return { valid: true, validatorIndex };
}
//# sourceMappingURL=utils.js.map