diff --git a/packages/api/src/beacon/routes/beacon/state.ts b/packages/api/src/beacon/routes/beacon/state.ts index d1284558f98f..59bf300d6b5f 100644 --- a/packages/api/src/beacon/routes/beacon/state.ts +++ b/packages/api/src/beacon/routes/beacon/state.ts @@ -1,10 +1,15 @@ import {ContainerType, ValueOf} from "@chainsafe/ssz"; import {ChainForkConfig} from "@lodestar/config"; import {MAX_VALIDATORS_PER_COMMITTEE} from "@lodestar/params"; -import {CommitteeIndex, Epoch, RootHex, Slot, StringType, ValidatorStatus, phase0, ssz} from "@lodestar/types"; +import {CommitteeIndex, Epoch, RootHex, Slot, StringType, ValidatorStatus, electra, phase0, ssz} from "@lodestar/types"; import {ArrayOf, JsonOnlyReq} from "../../../utils/codecs.js"; import {Endpoint, RequestCodec, RouteDefinitions, Schema} from "../../../utils/index.js"; -import {ExecutionOptimisticAndFinalizedCodec, ExecutionOptimisticAndFinalizedMeta} from "../../../utils/metadata.js"; +import { + ExecutionOptimisticAndFinalizedCodec, + ExecutionOptimisticAndFinalizedMeta, + ExecutionOptimisticFinalizedAndVersionCodec, + ExecutionOptimisticFinalizedAndVersionMeta, +} from "../../../utils/metadata.js"; import {fromValidatorIdsStr, toValidatorIdsStr} from "../../../utils/serdes.js"; import {WireFormat} from "../../../utils/wireFormat.js"; import {RootResponse, RootResponseType} from "./block.js"; @@ -266,6 +271,32 @@ export type Endpoints = { EpochSyncCommitteeResponse, ExecutionOptimisticAndFinalizedMeta >; + + /** + * Get State Pending Deposits + * + * Returns pending deposits for state with given 'stateId'. + */ + getPendingDeposits: Endpoint< + "GET", + StateArgs, + {params: {state_id: string}}, + electra.PendingDeposits, + ExecutionOptimisticFinalizedAndVersionMeta + >; + + /** + * Get State Pending Partial Withdrawals + * + * Returns pending partial withdrawals for state with given 'stateId'. + */ + getPendingPartialWithdrawals: Endpoint< + "GET", + StateArgs, + {params: {state_id: string}}, + electra.PendingPartialWithdrawals, + ExecutionOptimisticFinalizedAndVersionMeta + >; }; // biome-ignore lint/suspicious/noExplicitAny: @@ -483,5 +514,23 @@ export function getDefinitions(_config: ChainForkConfig): RouteDefinitions = { meta: {executionOptimistic: true, finalized: false}, }, }, + getPendingDeposits: { + args: {stateId: "head"}, + res: { + data: [ssz.electra.PendingDeposit.defaultValue()], + meta: {executionOptimistic: true, finalized: false, version: ForkName.electra}, + }, + }, + getPendingPartialWithdrawals: { + args: {stateId: "head"}, + res: { + data: [ssz.electra.PendingPartialWithdrawal.defaultValue()], + meta: {executionOptimistic: true, finalized: false, version: ForkName.electra}, + }, + }, // rewards diff --git a/packages/beacon-node/src/api/impl/beacon/state/index.ts b/packages/beacon-node/src/api/impl/beacon/state/index.ts index 916507cc56fc..90fa4791fa37 100644 --- a/packages/beacon-node/src/api/impl/beacon/state/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/state/index.ts @@ -1,8 +1,9 @@ import {routes} from "@lodestar/api"; import {ApplicationMethods} from "@lodestar/api/server"; -import {EPOCHS_PER_HISTORICAL_VECTOR} from "@lodestar/params"; +import {EPOCHS_PER_HISTORICAL_VECTOR, isForkPostElectra} from "@lodestar/params"; import { BeaconStateAllForks, + BeaconStateElectra, CachedBeaconStateAltair, computeEpochAtSlot, computeStartSlotAtEpoch, @@ -296,5 +297,37 @@ export function getBeaconStateApi({ meta: {executionOptimistic, finalized}, }; }, + + async getPendingDeposits({stateId}, context) { + const {state, executionOptimistic, finalized} = await getState(stateId); + const fork = config.getForkName(state.slot); + + if (!isForkPostElectra(fork)) { + throw new ApiError(400, `Cannot retrieve pending deposits for pre-electra state fork=${fork}`); + } + + const {pendingDeposits} = state as BeaconStateElectra; + + return { + data: context?.returnBytes ? pendingDeposits.serialize() : pendingDeposits.toValue(), + meta: {executionOptimistic, finalized, version: fork}, + }; + }, + + async getPendingPartialWithdrawals({stateId}, context) { + const {state, executionOptimistic, finalized} = await getState(stateId); + const fork = config.getForkName(state.slot); + + if (!isForkPostElectra(fork)) { + throw new ApiError(400, `Cannot retrieve pending partial withdrawals for pre-electra state fork=${fork}`); + } + + const {pendingPartialWithdrawals} = state as BeaconStateElectra; + + return { + data: context?.returnBytes ? pendingPartialWithdrawals.serialize() : pendingPartialWithdrawals.toValue(), + meta: {executionOptimistic, finalized, version: fork}, + }; + }, }; } diff --git a/packages/types/src/electra/sszTypes.ts b/packages/types/src/electra/sszTypes.ts index 081853b26ade..e8a12761bc81 100644 --- a/packages/types/src/electra/sszTypes.ts +++ b/packages/types/src/electra/sszTypes.ts @@ -287,6 +287,11 @@ export const PendingPartialWithdrawal = new ContainerType( {typeName: "PendingPartialWithdrawal", jsonCase: "eth2"} ); +export const PendingPartialWithdrawals = new ListCompositeType( + PendingPartialWithdrawal, + PENDING_PARTIAL_WITHDRAWALS_LIMIT +); + export const PendingConsolidation = new ContainerType( { sourceIndex: ValidatorIndex, @@ -295,6 +300,8 @@ export const PendingConsolidation = new ContainerType( {typeName: "PendingConsolidation", jsonCase: "eth2"} ); +export const PendingConsolidations = new ListCompositeType(PendingConsolidation, PENDING_CONSOLIDATIONS_LIMIT); + // In EIP-7251, we spread deneb fields as new fields are appended at the end export const BeaconState = new ContainerType( { @@ -345,8 +352,8 @@ export const BeaconState = new ContainerType( consolidationBalanceToConsume: Gwei, // New in ELECTRA:EIP7251 earliestConsolidationEpoch: Epoch, // New in ELECTRA:EIP7251 pendingDeposits: PendingDeposits, // New in ELECTRA:EIP7251 - pendingPartialWithdrawals: new ListCompositeType(PendingPartialWithdrawal, PENDING_PARTIAL_WITHDRAWALS_LIMIT), // New in ELECTRA:EIP7251 - pendingConsolidations: new ListCompositeType(PendingConsolidation, PENDING_CONSOLIDATIONS_LIMIT), // New in ELECTRA:EIP7251 + pendingPartialWithdrawals: PendingPartialWithdrawals, // New in ELECTRA:EIP7251 + pendingConsolidations: PendingConsolidations, // New in ELECTRA:EIP7251 }, {typeName: "BeaconState", jsonCase: "eth2"} ); diff --git a/packages/types/src/electra/types.ts b/packages/types/src/electra/types.ts index ee7585692d47..00be610626d7 100644 --- a/packages/types/src/electra/types.ts +++ b/packages/types/src/electra/types.ts @@ -44,8 +44,11 @@ export type LightClientOptimisticUpdate = ValueOf; export type PendingDeposit = ValueOf; +export type PendingDeposits = ValueOf; export type PendingPartialWithdrawal = ValueOf; +export type PendingPartialWithdrawals = ValueOf; export type PendingConsolidation = ValueOf; +export type PendingConsolidations = ValueOf; export type BlockContents = ValueOf; export type SignedBlockContents = ValueOf;