@lodestar/beacon-node
Version:
A Typescript implementation of the beacon chain
131 lines • 5.03 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 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