Skip to content

Commit

Permalink
feat: add finalized metadata field to HTTP API responses (#6645)
Browse files Browse the repository at this point in the history
* feat: add finalized metadata field to HTTP API responses

* Clean up getState type casts

* Fix finalized when getting block root

* Add comment for block from hot db

* Fix case where slot equals finalized block slot

* Calculate epoch from unmodded slot
  • Loading branch information
nflaig authored Apr 11, 2024
1 parent 4773dd2 commit 5ccae1c
Show file tree
Hide file tree
Showing 25 changed files with 326 additions and 165 deletions.
29 changes: 22 additions & 7 deletions packages/api/src/beacon/routes/beacon/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
ContainerDataExecutionOptimistic,
WithExecutionOptimistic,
ContainerData,
WithFinalized,
} from "../../../utils/index.js";
import {HttpStatusCode} from "../../../utils/client/httpStatusCode.js";
import {parseAcceptHeader, writeAcceptHeader} from "../../../utils/acceptHeader.js";
Expand All @@ -32,6 +33,11 @@ export type BlockId = RootHex | Slot | "head" | "genesis" | "finalized";
*/
export type ExecutionOptimistic = boolean;

/**
* True if the response references the finalized history of the chain, as determined by fork choice.
*/
export type Finalized = boolean;

export type BlockHeaderResponse = {
root: Root;
canonical: boolean;
Expand Down Expand Up @@ -66,6 +72,7 @@ export type BlockV2Response<T extends ResponseFormat = "json"> = T extends "ssz"
[HttpStatusCode.OK]: {
data: allForks.SignedBeaconBlock;
executionOptimistic: ExecutionOptimistic;
finalized: Finalized;
version: ForkName;
};
},
Expand Down Expand Up @@ -103,6 +110,7 @@ export type Api = {
[HttpStatusCode.OK]: {
data: phase0.Attestation[];
executionOptimistic: ExecutionOptimistic;
finalized: Finalized;
};
},
HttpStatusCode.BAD_REQUEST | HttpStatusCode.NOT_FOUND
Expand All @@ -121,6 +129,7 @@ export type Api = {
[HttpStatusCode.OK]: {
data: BlockHeaderResponse;
executionOptimistic: ExecutionOptimistic;
finalized: Finalized;
};
},
HttpStatusCode.BAD_REQUEST | HttpStatusCode.NOT_FOUND
Expand All @@ -139,6 +148,7 @@ export type Api = {
[HttpStatusCode.OK]: {
data: BlockHeaderResponse[];
executionOptimistic: ExecutionOptimistic;
finalized: Finalized;
};
},
HttpStatusCode.BAD_REQUEST
Expand All @@ -157,6 +167,7 @@ export type Api = {
[HttpStatusCode.OK]: {
data: {root: Root};
executionOptimistic: ExecutionOptimistic;
finalized: Finalized;
};
},
HttpStatusCode.BAD_REQUEST | HttpStatusCode.NOT_FOUND
Expand Down Expand Up @@ -236,7 +247,11 @@ export type Api = {
indices?: number[]
): Promise<
ApiClientResponse<{
[HttpStatusCode.OK]: {executionOptimistic: ExecutionOptimistic; data: deneb.BlobSidecars};
[HttpStatusCode.OK]: {
data: deneb.BlobSidecars;
executionOptimistic: ExecutionOptimistic;
finalized: Finalized;
};
}>
>;
};
Expand Down Expand Up @@ -395,11 +410,11 @@ export function getReturnTypes(): ReturnTypes<Api> {

return {
getBlock: ContainerData(ssz.phase0.SignedBeaconBlock),
getBlockV2: WithExecutionOptimistic(WithVersion((fork) => ssz[fork].SignedBeaconBlock)),
getBlockAttestations: ContainerDataExecutionOptimistic(ArrayOf(ssz.phase0.Attestation)),
getBlockHeader: ContainerDataExecutionOptimistic(BeaconHeaderResType),
getBlockHeaders: ContainerDataExecutionOptimistic(ArrayOf(BeaconHeaderResType)),
getBlockRoot: ContainerDataExecutionOptimistic(RootContainer),
getBlobSidecars: ContainerDataExecutionOptimistic(ssz.deneb.BlobSidecars),
getBlockV2: WithFinalized(WithExecutionOptimistic(WithVersion((fork) => ssz[fork].SignedBeaconBlock))),
getBlockAttestations: WithFinalized(ContainerDataExecutionOptimistic(ArrayOf(ssz.phase0.Attestation))),
getBlockHeader: WithFinalized(ContainerDataExecutionOptimistic(BeaconHeaderResType)),
getBlockHeaders: WithFinalized(ContainerDataExecutionOptimistic(ArrayOf(BeaconHeaderResType))),
getBlockRoot: WithFinalized(ContainerDataExecutionOptimistic(RootContainer)),
getBlobSidecars: WithFinalized(ContainerDataExecutionOptimistic(ssz.deneb.BlobSidecars)),
};
}
40 changes: 31 additions & 9 deletions packages/api/src/beacon/routes/beacon/rewards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
ReqSerializers,
ContainerDataExecutionOptimistic,
ArrayOf,
WithFinalized,
} from "../../../utils/index.js";
import {HttpStatusCode} from "../../../utils/client/httpStatusCode.js";
import {ApiClientResponse} from "../../../interfaces.js";
Expand All @@ -22,6 +23,11 @@ import {ValidatorId} from "./state.js";
*/
export type ExecutionOptimistic = boolean;

/**
* True if the response references the finalized history of the chain, as determined by fork choice.
*/
export type Finalized = boolean;

/**
* Rewards info for a single block. Every reward value is in Gwei.
*/
Expand Down Expand Up @@ -88,11 +94,15 @@ export type Api = {
* @param blockId Block identifier.
* Can be one of: "head" (canonical head in node's view), "genesis", "finalized", \<slot\>, \<hex encoded blockRoot with 0x prefix\>.
*/
getBlockRewards(
blockId: BlockId
): Promise<
getBlockRewards(blockId: BlockId): Promise<
ApiClientResponse<
{[HttpStatusCode.OK]: {data: BlockRewards; executionOptimistic: ExecutionOptimistic}},
{
[HttpStatusCode.OK]: {
data: BlockRewards;
executionOptimistic: ExecutionOptimistic;
finalized: Finalized;
};
},
HttpStatusCode.BAD_REQUEST | HttpStatusCode.NOT_FOUND
>
>;
Expand All @@ -108,7 +118,13 @@ export type Api = {
validatorIds?: ValidatorId[]
): Promise<
ApiClientResponse<
{[HttpStatusCode.OK]: {data: AttestationsRewards; executionOptimistic: ExecutionOptimistic}},
{
[HttpStatusCode.OK]: {
data: AttestationsRewards;
executionOptimistic: ExecutionOptimistic;
finalized: Finalized;
};
},
HttpStatusCode.BAD_REQUEST | HttpStatusCode.NOT_FOUND
>
>;
Expand All @@ -126,7 +142,13 @@ export type Api = {
validatorIds?: ValidatorId[]
): Promise<
ApiClientResponse<
{[HttpStatusCode.OK]: {data: SyncCommitteeRewards; executionOptimistic: ExecutionOptimistic}},
{
[HttpStatusCode.OK]: {
data: SyncCommitteeRewards;
executionOptimistic: ExecutionOptimistic;
finalized: Finalized;
};
},
HttpStatusCode.BAD_REQUEST | HttpStatusCode.NOT_FOUND
>
>;
Expand Down Expand Up @@ -228,8 +250,8 @@ export function getReturnTypes(): ReturnTypes<Api> {
);

return {
getBlockRewards: ContainerDataExecutionOptimistic(BlockRewardsResponse),
getAttestationsRewards: ContainerDataExecutionOptimistic(AttestationsRewardsResponse),
getSyncCommitteeRewards: ContainerDataExecutionOptimistic(ArrayOf(SyncCommitteeRewardsResponse)),
getBlockRewards: WithFinalized(ContainerDataExecutionOptimistic(BlockRewardsResponse)),
getAttestationsRewards: WithFinalized(ContainerDataExecutionOptimistic(AttestationsRewardsResponse)),
getSyncCommitteeRewards: WithFinalized(ContainerDataExecutionOptimistic(ArrayOf(SyncCommitteeRewardsResponse))),
};
}
108 changes: 81 additions & 27 deletions packages/api/src/beacon/routes/beacon/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
Schema,
ReqSerializers,
ReqSerializer,
WithFinalized,
} from "../../../utils/index.js";

// See /packages/api/src/routes/index.ts for reasoning and instructions to add new routes
Expand All @@ -23,6 +24,11 @@ export type ValidatorId = string | number;
*/
export type ExecutionOptimistic = boolean;

/**
* True if the response references the finalized history of the chain, as determined by fork choice.
*/
export type Finalized = boolean;

export type ValidatorStatus =
| "active"
| "pending_initialized"
Expand Down Expand Up @@ -85,11 +91,15 @@ export type Api = {
* @param stateId State identifier.
* Can be one of: "head" (canonical head in node's view), "genesis", "finalized", "justified", \<slot\>, \<hex encoded stateRoot with 0x prefix\>.
*/
getStateRoot(
stateId: StateId
): Promise<
getStateRoot(stateId: StateId): Promise<
ApiClientResponse<
{[HttpStatusCode.OK]: {data: {root: Root}; executionOptimistic: ExecutionOptimistic}},
{
[HttpStatusCode.OK]: {
data: {root: Root};
executionOptimistic: ExecutionOptimistic;
finalized: Finalized;
};
},
HttpStatusCode.BAD_REQUEST | HttpStatusCode.NOT_FOUND
>
>;
Expand All @@ -100,11 +110,15 @@ export type Api = {
* @param stateId State identifier.
* Can be one of: "head" (canonical head in node's view), "genesis", "finalized", "justified", \<slot\>, \<hex encoded stateRoot with 0x prefix\>.
*/
getStateFork(
stateId: StateId
): Promise<
getStateFork(stateId: StateId): Promise<
ApiClientResponse<
{[HttpStatusCode.OK]: {data: phase0.Fork; executionOptimistic: ExecutionOptimistic}},
{
[HttpStatusCode.OK]: {
data: phase0.Fork;
executionOptimistic: ExecutionOptimistic;
finalized: Finalized;
};
},
HttpStatusCode.BAD_REQUEST | HttpStatusCode.NOT_FOUND
>
>;
Expand All @@ -121,7 +135,13 @@ export type Api = {
epoch?: Epoch
): Promise<
ApiClientResponse<
{[HttpStatusCode.OK]: {data: {randao: Root}; executionOptimistic: ExecutionOptimistic}},
{
[HttpStatusCode.OK]: {
data: {randao: Root};
executionOptimistic: ExecutionOptimistic;
finalized: Finalized;
};
},
HttpStatusCode.BAD_REQUEST | HttpStatusCode.NOT_FOUND
>
>;
Expand All @@ -133,11 +153,15 @@ export type Api = {
* @param stateId State identifier.
* Can be one of: "head" (canonical head in node's view), "genesis", "finalized", "justified", \<slot\>, \<hex encoded stateRoot with 0x prefix\>.
*/
getStateFinalityCheckpoints(
stateId: StateId
): Promise<
getStateFinalityCheckpoints(stateId: StateId): Promise<
ApiClientResponse<
{[HttpStatusCode.OK]: {data: FinalityCheckpoints; executionOptimistic: ExecutionOptimistic}},
{
[HttpStatusCode.OK]: {
data: FinalityCheckpoints;
executionOptimistic: ExecutionOptimistic;
finalized: Finalized;
};
},
HttpStatusCode.BAD_REQUEST | HttpStatusCode.NOT_FOUND
>
>;
Expand All @@ -155,7 +179,13 @@ export type Api = {
filters?: ValidatorFilters
): Promise<
ApiClientResponse<
{[HttpStatusCode.OK]: {data: ValidatorResponse[]; executionOptimistic: ExecutionOptimistic}},
{
[HttpStatusCode.OK]: {
data: ValidatorResponse[];
executionOptimistic: ExecutionOptimistic;
finalized: Finalized;
};
},
HttpStatusCode.BAD_REQUEST | HttpStatusCode.NOT_FOUND
>
>;
Expand All @@ -172,7 +202,13 @@ export type Api = {
validatorId: ValidatorId
): Promise<
ApiClientResponse<
{[HttpStatusCode.OK]: {data: ValidatorResponse; executionOptimistic: ExecutionOptimistic}},
{
[HttpStatusCode.OK]: {
data: ValidatorResponse;
executionOptimistic: ExecutionOptimistic;
finalized: Finalized;
};
},
HttpStatusCode.BAD_REQUEST | HttpStatusCode.NOT_FOUND
>
>;
Expand All @@ -189,7 +225,13 @@ export type Api = {
indices?: ValidatorId[]
): Promise<
ApiClientResponse<
{[HttpStatusCode.OK]: {data: ValidatorBalance[]; executionOptimistic: ExecutionOptimistic}},
{
[HttpStatusCode.OK]: {
data: ValidatorBalance[];
executionOptimistic: ExecutionOptimistic;
finalized: Finalized;
};
},
HttpStatusCode.BAD_REQUEST
>
>;
Expand All @@ -208,7 +250,13 @@ export type Api = {
filters?: CommitteesFilters
): Promise<
ApiClientResponse<
{[HttpStatusCode.OK]: {data: EpochCommitteeResponse[]; executionOptimistic: ExecutionOptimistic}},
{
[HttpStatusCode.OK]: {
data: EpochCommitteeResponse[];
executionOptimistic: ExecutionOptimistic;
finalized: Finalized;
};
},
HttpStatusCode.BAD_REQUEST | HttpStatusCode.NOT_FOUND
>
>;
Expand All @@ -218,7 +266,13 @@ export type Api = {
epoch?: Epoch
): Promise<
ApiClientResponse<
{[HttpStatusCode.OK]: {data: EpochSyncCommitteeResponse; executionOptimistic: ExecutionOptimistic}},
{
[HttpStatusCode.OK]: {
data: EpochSyncCommitteeResponse;
executionOptimistic: ExecutionOptimistic;
finalized: Finalized;
};
},
HttpStatusCode.BAD_REQUEST | HttpStatusCode.NOT_FOUND
>
>;
Expand Down Expand Up @@ -376,14 +430,14 @@ export function getReturnTypes(): ReturnTypes<Api> {
);

return {
getStateRoot: ContainerDataExecutionOptimistic(RootContainer),
getStateFork: ContainerDataExecutionOptimistic(ssz.phase0.Fork),
getStateRandao: ContainerDataExecutionOptimistic(RandaoContainer),
getStateFinalityCheckpoints: ContainerDataExecutionOptimistic(FinalityCheckpoints),
getStateValidators: ContainerDataExecutionOptimistic(ArrayOf(ValidatorResponse)),
getStateValidator: ContainerDataExecutionOptimistic(ValidatorResponse),
getStateValidatorBalances: ContainerDataExecutionOptimistic(ArrayOf(ValidatorBalance)),
getEpochCommittees: ContainerDataExecutionOptimistic(ArrayOf(EpochCommitteeResponse)),
getEpochSyncCommittees: ContainerDataExecutionOptimistic(EpochSyncCommitteesResponse),
getStateRoot: WithFinalized(ContainerDataExecutionOptimistic(RootContainer)),
getStateFork: WithFinalized(ContainerDataExecutionOptimistic(ssz.phase0.Fork)),
getStateRandao: WithFinalized(ContainerDataExecutionOptimistic(RandaoContainer)),
getStateFinalityCheckpoints: WithFinalized(ContainerDataExecutionOptimistic(FinalityCheckpoints)),
getStateValidators: WithFinalized(ContainerDataExecutionOptimistic(ArrayOf(ValidatorResponse))),
getStateValidator: WithFinalized(ContainerDataExecutionOptimistic(ValidatorResponse)),
getStateValidatorBalances: WithFinalized(ContainerDataExecutionOptimistic(ArrayOf(ValidatorBalance))),
getEpochCommittees: WithFinalized(ContainerDataExecutionOptimistic(ArrayOf(EpochCommitteeResponse))),
getEpochSyncCommittees: WithFinalized(ContainerDataExecutionOptimistic(EpochSyncCommitteesResponse)),
};
}
Loading

0 comments on commit 5ccae1c

Please sign in to comment.