UNPKG

@lodestar/beacon-node

Version:

A Typescript implementation of the beacon chain

131 lines 5.03 kB
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 getStateResponse(chain, inStateId) { const stateId = resolveStateId(chain.forkChoice, inStateId); const res = typeof stateId === "string" ? await chain.getStateByStateRoot(stateId) : typeof stateId === "number" ? await chain.getStateBySlot(stateId) : chain.getStateByCheckpoint(stateId); if (!res) { throw new ApiError(404, `State not found for id '${inStateId}'`); } return res; } 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.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; } function mapToGeneralStatus(subStatus) { switch (subStatus) { case "active_ongoing": case "active_exiting": case "active_slashed": return "active"; case "pending_initialized": case "pending_queued": return "pending"; case "exited_slashed": case "exited_unslashed": return "exited"; case "withdrawal_possible": case "withdrawal_done": return "withdrawal"; default: throw new Error(`Unknown substatus: ${subStatus}`); } } export function toValidatorResponse(index, validator, balance, currentEpoch) { return { index, status: getValidatorStatus(validator, currentEpoch), balance, validator, }; } export function filterStateValidatorsByStatus(statuses, state, pubkey2index, currentEpoch) { const responses = []; const validatorsArr = state.validators.getAllReadonlyValues(); const statusSet = new Set(statuses); for (const validator of validatorsArr) { const validatorStatus = getValidatorStatus(validator, currentEpoch); const generalStatus = mapToGeneralStatus(validatorStatus); const resp = getStateValidatorIndex(validator.pubkey, state, pubkey2index); if (resp.valid && (statusSet.has(validatorStatus) || statusSet.has(generalStatus))) { responses.push(toValidatorResponse(resp.validatorIndex, validator, state.balances.get(resp.validatorIndex), currentEpoch)); } } return responses; } export function getStateValidatorIndex(id, state, pubkey2index) { 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.validators.length) { return { valid: false, code: 404, reason: "Validator index from future state" }; } return { valid: true, validatorIndex }; } // typeof id === Uint8Array const validatorIndex = pubkey2index.get(id); if (validatorIndex === null) { return { valid: false, code: 404, reason: "Validator pubkey not found in state" }; } if (validatorIndex >= state.validators.length) { return { valid: false, code: 404, reason: "Validator pubkey from future state" }; } return { valid: true, validatorIndex }; } //# sourceMappingURL=utils.js.map