UNPKG

@lodestar/api

Version:

A Typescript REST client for the Ethereum Consensus API

228 lines (219 loc) 7.83 kB
import {ChainForkConfig} from "@lodestar/config"; import {ForkName, VALIDATOR_REGISTRY_LIMIT, isForkPostDeneb} from "@lodestar/params"; import { ArrayOf, BLSPubkey, ExecutionPayload, ExecutionPayloadAndBlobsBundle, Root, SignedBlindedBeaconBlock, SignedBuilderBid, Slot, WithOptionalBytes, bellatrix, ssz, } from "@lodestar/types"; import {fromHex, toPubkeyHex, toRootHex} from "@lodestar/utils"; import { EmptyArgs, EmptyMeta, EmptyRequest, EmptyRequestCodec, EmptyResponseCodec, EmptyResponseData, WithVersion, } from "../utils/codecs.js"; import {getPostBellatrixForkTypes, getPostDenebForkTypes, toForkName} from "../utils/fork.js"; import {fromHeaders} from "../utils/headers.js"; import {Endpoint, RouteDefinitions, Schema} from "../utils/index.js"; import {MetaHeader, VersionCodec, VersionMeta} from "../utils/metadata.js"; import {WireFormat} from "../utils/wireFormat.js"; // Mev-boost might not return any data if there are no bids from builders or min-bid threshold was not reached. // In this case, we receive a success response (204) which is not handled as an error. The generic response // handler already checks the status code and will not attempt to parse the body, but it will return no value. // It is important that this type indicates that there might be no value to ensure it is properly handled downstream. export type MaybeSignedBuilderBid = SignedBuilderBid | undefined; const RegistrationsType = ArrayOf(ssz.bellatrix.SignedValidatorRegistrationV1, VALIDATOR_REGISTRY_LIMIT); export type Endpoints = { status: Endpoint< // ⏎ "GET", EmptyArgs, EmptyRequest, EmptyResponseData, EmptyMeta >; registerValidator: Endpoint< "POST", {registrations: bellatrix.SignedValidatorRegistrationV1[]}, {body: unknown}, EmptyResponseData, EmptyMeta >; getHeader: Endpoint< "GET", { slot: Slot; parentHash: Root; proposerPubkey: BLSPubkey; }, {params: {slot: Slot; parent_hash: string; pubkey: string}}, MaybeSignedBuilderBid, VersionMeta >; submitBlindedBlock: Endpoint< "POST", {signedBlindedBlock: WithOptionalBytes<SignedBlindedBeaconBlock>}, {body: unknown; headers: {[MetaHeader.Version]: string}}, ExecutionPayload | ExecutionPayloadAndBlobsBundle, VersionMeta >; submitBlindedBlockV2: Endpoint< "POST", {signedBlindedBlock: WithOptionalBytes<SignedBlindedBeaconBlock>}, {body: unknown; headers: {[MetaHeader.Version]: string}}, EmptyResponseData, EmptyMeta >; }; export function getDefinitions(config: ChainForkConfig): RouteDefinitions<Endpoints> { return { status: { url: "/eth/v1/builder/status", method: "GET", req: EmptyRequestCodec, resp: EmptyResponseCodec, }, registerValidator: { url: "/eth/v1/builder/validators", method: "POST", req: { writeReqJson: ({registrations}) => ({body: RegistrationsType.toJson(registrations)}), parseReqJson: ({body}) => ({registrations: RegistrationsType.fromJson(body)}), writeReqSsz: ({registrations}) => ({body: RegistrationsType.serialize(registrations)}), parseReqSsz: ({body}) => ({registrations: RegistrationsType.deserialize(body)}), schema: {body: Schema.ObjectArray}, }, resp: EmptyResponseCodec, init: { requestWireFormat: WireFormat.ssz, }, }, getHeader: { url: "/eth/v1/builder/header/{slot}/{parent_hash}/{pubkey}", method: "GET", req: { writeReq: ({slot, parentHash, proposerPubkey: proposerPubKey}) => ({ params: {slot, parent_hash: toRootHex(parentHash), pubkey: toPubkeyHex(proposerPubKey)}, }), parseReq: ({params}) => ({ slot: params.slot, parentHash: fromHex(params.parent_hash), proposerPubkey: fromHex(params.pubkey), }), schema: { params: {slot: Schema.UintRequired, parent_hash: Schema.StringRequired, pubkey: Schema.StringRequired}, }, }, resp: { data: WithVersion<MaybeSignedBuilderBid, VersionMeta>( (fork: ForkName) => getPostBellatrixForkTypes(fork).SignedBuilderBid ), meta: VersionCodec, }, }, submitBlindedBlock: { url: "/eth/v1/builder/blinded_blocks", method: "POST", req: { writeReqJson: ({signedBlindedBlock}) => { const fork = config.getForkName(signedBlindedBlock.data.message.slot); return { body: getPostBellatrixForkTypes(fork).SignedBlindedBeaconBlock.toJson(signedBlindedBlock.data), headers: { [MetaHeader.Version]: fork, }, }; }, parseReqJson: ({body, headers}) => { const fork = toForkName(fromHeaders(headers, MetaHeader.Version)); return { signedBlindedBlock: {data: getPostBellatrixForkTypes(fork).SignedBlindedBeaconBlock.fromJson(body)}, }; }, writeReqSsz: ({signedBlindedBlock}) => { const fork = config.getForkName(signedBlindedBlock.data.message.slot); return { body: signedBlindedBlock.bytes ?? getPostBellatrixForkTypes(fork).SignedBlindedBeaconBlock.serialize(signedBlindedBlock.data), headers: { [MetaHeader.Version]: fork, }, }; }, parseReqSsz: ({body, headers}) => { const fork = toForkName(fromHeaders(headers, MetaHeader.Version)); return { signedBlindedBlock: {data: getPostBellatrixForkTypes(fork).SignedBlindedBeaconBlock.deserialize(body)}, }; }, schema: { body: Schema.Object, headers: {[MetaHeader.Version]: Schema.String}, }, }, resp: { data: WithVersion<ExecutionPayload | ExecutionPayloadAndBlobsBundle, VersionMeta>((fork: ForkName) => { return isForkPostDeneb(fork) ? getPostDenebForkTypes(fork).ExecutionPayloadAndBlobsBundle : getPostBellatrixForkTypes(fork).ExecutionPayload; }), meta: VersionCodec, }, }, submitBlindedBlockV2: { url: "/eth/v2/builder/blinded_blocks", method: "POST", req: { writeReqJson: ({signedBlindedBlock}) => { const fork = config.getForkName(signedBlindedBlock.data.message.slot); return { body: getPostBellatrixForkTypes(fork).SignedBlindedBeaconBlock.toJson(signedBlindedBlock.data), headers: { [MetaHeader.Version]: fork, }, }; }, parseReqJson: ({body, headers}) => { const fork = toForkName(fromHeaders(headers, MetaHeader.Version)); return { signedBlindedBlock: {data: getPostBellatrixForkTypes(fork).SignedBlindedBeaconBlock.fromJson(body)}, }; }, writeReqSsz: ({signedBlindedBlock}) => { const fork = config.getForkName(signedBlindedBlock.data.message.slot); return { body: signedBlindedBlock.bytes ?? getPostBellatrixForkTypes(fork).SignedBlindedBeaconBlock.serialize(signedBlindedBlock.data), headers: { [MetaHeader.Version]: fork, }, }; }, parseReqSsz: ({body, headers}) => { const fork = toForkName(fromHeaders(headers, MetaHeader.Version)); return { signedBlindedBlock: {data: getPostBellatrixForkTypes(fork).SignedBlindedBeaconBlock.deserialize(body)}, }; }, schema: { body: Schema.Object, headers: {[MetaHeader.Version]: Schema.String}, }, }, resp: EmptyResponseCodec, }, }; }