Skip to content

Commit

Permalink
De-couple block production
Browse files Browse the repository at this point in the history
  • Loading branch information
dapplion committed Nov 15, 2022
1 parent 513b873 commit 26a0794
Show file tree
Hide file tree
Showing 11 changed files with 138 additions and 178 deletions.
12 changes: 0 additions & 12 deletions packages/api/src/beacon/routes/beacon/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import {ContainerType} from "@chainsafe/ssz";
import {ForkName} from "@lodestar/params";
import {IChainForkConfig} from "@lodestar/config";
import {phase0, allForks, Slot, Root, ssz, RootHex} from "@lodestar/types";
import {SignedBeaconBlockAndBlobsSidecar} from "@lodestar/types/eip4844";

import {
RoutesData,
Expand Down Expand Up @@ -111,8 +110,6 @@ export type Api = {
* transactions beacon node gets in response.
*/
publishBlindedBlock(block: allForks.SignedBlindedBeaconBlock): Promise<void>;

publishBlockWithBlobs(blockWithBlobs: SignedBeaconBlockAndBlobsSidecar): Promise<void>;
};

/**
Expand All @@ -126,7 +123,6 @@ export const routesData: RoutesData<Api> = {
getBlockHeaders: {url: "/eth/v1/beacon/headers", method: "GET"},
getBlockRoot: {url: "/eth/v1/beacon/blocks/{block_id}/root", method: "GET"},
publishBlock: {url: "/eth/v1/beacon/blocks", method: "POST"},
publishBlockWithBlobs: {url: "/eth/v1/beacon/blocksWithBlobs", method: "POST"},
publishBlindedBlock: {url: "/eth/v1/beacon/blinded_blocks", method: "POST"},
};

Expand All @@ -142,7 +138,6 @@ export type ReqTypes = {
getBlockHeaders: {query: {slot?: number; parent_root?: string}};
getBlockRoot: BlockIdOnlyReq;
publishBlock: {body: unknown};
publishBlockWithBlobs: {body: unknown};
publishBlindedBlock: {body: unknown};
};

Expand All @@ -162,12 +157,6 @@ export function getReqSerializers(config: IChainForkConfig): ReqSerializers<Api,
fromJson: (data) => getSignedBeaconBlockType((data as unknown) as allForks.SignedBeaconBlock).fromJson(data),
};

const BlockWithBlobsSsz = ssz.eip4844.SignedBeaconBlockAndBlobsSidecar;
const SignedBeaconBlockWithBlobs: TypeJson<SignedBeaconBlockAndBlobsSidecar> = {
toJson: (data) => BlockWithBlobsSsz.toJson(data),
fromJson: (data) => BlockWithBlobsSsz.fromJson(data),
};

const getSignedBlindedBeaconBlockType = (
data: allForks.SignedBlindedBeaconBlock
): allForks.AllForksBlindedSSZTypes["SignedBeaconBlock"] =>
Expand All @@ -191,7 +180,6 @@ export function getReqSerializers(config: IChainForkConfig): ReqSerializers<Api,
},
getBlockRoot: blockIdOnlyReq,
publishBlock: reqOnlyBody(AllForksSignedBeaconBlock, Schema.Object),
publishBlockWithBlobs: reqOnlyBody(SignedBeaconBlockWithBlobs, Schema.Object),
publishBlindedBlock: reqOnlyBody(AllForksSignedBlindedBeaconBlock, Schema.Object),
};
}
Expand Down
12 changes: 0 additions & 12 deletions packages/api/src/beacon/routes/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
Epoch,
phase0,
bellatrix,
eip4844,
Root,
Slot,
ssz,
Expand All @@ -24,7 +23,6 @@ import {
ArrayOf,
ContainerData,
Schema,
WithBlobs,
WithVersion,
reqOnlyBody,
ReqSerializers,
Expand Down Expand Up @@ -167,12 +165,6 @@ export type Api = {
graffiti: string
): Promise<{data: allForks.BeaconBlock; version: ForkName}>;

produceBlockWithBlobs(
slot: Slot,
randaoReveal: BLSSignature,
graffiti: string
): Promise<{data: allForks.BeaconBlock; version: ForkName; blobs: eip4844.Blobs}>;

produceBlindedBlock(
slot: Slot,
randaoReveal: BLSSignature,
Expand Down Expand Up @@ -253,7 +245,6 @@ export const routesData: RoutesData<Api> = {
getSyncCommitteeDuties: {url: "/eth/v1/validator/duties/sync/{epoch}", method: "POST"},
produceBlock: {url: "/eth/v1/validator/blocks/{slot}", method: "GET"},
produceBlockV2: {url: "/eth/v2/validator/blocks/{slot}", method: "GET"},
produceBlockWithBlobs: {url: "/eth/v3/validator/blocks/{slot}", method: "GET"},
produceBlindedBlock: {url: "/eth/v1/validator/blinded_blocks/{slot}", method: "GET"},
produceAttestationData: {url: "/eth/v1/validator/attestation_data", method: "GET"},
produceSyncCommitteeContribution: {url: "/eth/v1/validator/sync_committee_contribution", method: "GET"},
Expand All @@ -274,7 +265,6 @@ export type ReqTypes = {
getSyncCommitteeDuties: {params: {epoch: Epoch}; body: U64Str[]};
produceBlock: {params: {slot: number}; query: {randao_reveal: string; graffiti: string}};
produceBlockV2: {params: {slot: number}; query: {randao_reveal: string; graffiti: string}};
produceBlockWithBlobs: {params: {slot: number}; query: {randao_reveal: string; graffiti: string}};
produceBlindedBlock: {params: {slot: number}; query: {randao_reveal: string; graffiti: string}};
produceAttestationData: {query: {slot: number; committee_index: number}};
produceSyncCommitteeContribution: {query: {slot: number; subcommittee_index: number; beacon_block_root: string}};
Expand Down Expand Up @@ -350,7 +340,6 @@ export function getReqSerializers(): ReqSerializers<Api, ReqTypes> {

produceBlock: produceBlock,
produceBlockV2: produceBlock,
produceBlockWithBlobs: produceBlock,
produceBlindedBlock: produceBlock,

produceAttestationData: {
Expand Down Expand Up @@ -454,7 +443,6 @@ export function getReturnTypes(): ReturnTypes<Api> {
getSyncCommitteeDuties: ContainerDataExecutionOptimistic(ArrayOf(SyncDuty)),
produceBlock: ContainerData(ssz.phase0.BeaconBlock),
produceBlockV2: WithVersion((fork: ForkName) => ssz[fork].BeaconBlock),
produceBlockWithBlobs: WithBlobs(WithVersion((fork: ForkName) => ssz[fork].BeaconBlock)),
produceBlindedBlock: WithVersion((fork: ForkName) => {
if (fork === ForkName.phase0 || fork === ForkName.altair) {
throw Error(`No BlindedBlock for fork ${fork} previous to bellatrix`);
Expand Down
22 changes: 0 additions & 22 deletions packages/beacon-node/src/api/impl/beacon/blocks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,27 +202,5 @@ export function getBeaconBlockApi({
}),
]);
},

async publishBlockWithBlobs(signedBeaconBlockAndBlobsSidecar) {
const {beaconBlock} = signedBeaconBlockAndBlobsSidecar;
const {message} = beaconBlock;

const seenTimestampSec = Date.now() / 1000;
await waitForSlot(message.slot);

metrics?.registerBeaconBlock(OpSource.api, seenTimestampSec, message);

await Promise.all([
network.gossip.publishSignedBeaconBlockAndBlobsSidecar(signedBeaconBlockAndBlobsSidecar),
// TODO EIP-4844 processBlock for signedBeaconBlockAndBlobsSidecar
// We need to save the blob?
chain.processBlock(beaconBlock).catch((e) => {
if (e instanceof BlockError && e.type.code === BlockErrorCode.PARENT_UNKNOWN) {
network.events.emit(NetworkEvent.unknownBlockParent, beaconBlock, network.peerId.toString());
}
throw e;
}),
]);
},
};
}
31 changes: 0 additions & 31 deletions packages/beacon-node/src/api/impl/validator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,40 +237,9 @@ export function getValidatorApi({chain, config, logger, metrics, network, sync}:
}
};

const produceBlockWithBlobs: routes.validator.Api["produceBlockWithBlobs"] = async function produceBlock(
slot,
randaoReveal,
graffiti
) {
let timer;
metrics?.blockProductionRequests.inc();
try {
notWhileSyncing();
await waitForSlot(slot); // Must never request for a future slot > currentSlot

// Process the queued attestations in the forkchoice for correct head estimation
// forkChoice.updateTime() might have already been called by the onSlot clock
// handler, in which case this should just return.
chain.forkChoice.updateTime(slot);
chain.recomputeForkChoiceHead();

timer = metrics?.blockProductionTime.startTimer();
const {block, blobs} = await chain.produceBlockWithBlobs({
slot,
randaoReveal,
graffiti: toGraffitiBuffer(graffiti || ""),
});
metrics?.blockProductionSuccess.inc();
return {data: block, version: config.getForkName(block.slot), blobs};
} finally {
if (timer) timer();
}
};

return {
produceBlock: produceBlock,
produceBlockV2: produceBlock,
produceBlockWithBlobs,
produceBlindedBlock,

async produceAttestationData(committeeIndex, slot) {
Expand Down
52 changes: 38 additions & 14 deletions packages/beacon-node/src/chain/chain.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import path from "node:path";
import {computeAggregateKzgProof} from "c-kzg";
import {
BeaconStateAllForks,
CachedBeaconStateAllForks,
Expand Down Expand Up @@ -60,7 +61,7 @@ import {SeenBlockAttesters} from "./seenCache/seenBlockAttesters.js";
import {BeaconProposerCache} from "./beaconProposerCache.js";
import {CheckpointBalancesCache} from "./balancesCache.js";
import {AssembledBlockType, BlockType} from "./produceBlock/index.js";
import {BlockAttributes, produceBlockBody} from "./produceBlock/produceBlockBody.js";
import {BlobsResultType, BlockAttributes, produceBlockBody} from "./produceBlock/produceBlockBody.js";
import {computeNewStateRoot} from "./produceBlock/computeNewStateRoot.js";

export class BeaconChain implements IBeaconChain {
Expand Down Expand Up @@ -118,6 +119,8 @@ export class BeaconChain implements IBeaconChain {
private successfulExchangeTransition = false;
private readonly exchangeTransitionConfigurationEverySlots: number;

private readonly producedBlobsCache = new Map<RootHex, eip4844.Blobs>();

private readonly faultInspectionWindow: number;
private readonly allowedFaults: number;
private processShutdownCallback: ProcessShutdownCallback;
Expand Down Expand Up @@ -340,26 +343,18 @@ export class BeaconChain implements IBeaconChain {
return await this.db.block.get(fromHexString(block.blockRoot));
}

async produceBlock(blockAttributes: BlockAttributes): Promise<allForks.BeaconBlock> {
const {block} = await this.produceBlockWrapper<BlockType.Full>(BlockType.Full, blockAttributes);
return block;
}

async produceBlockWithBlobs(
blockAttributes: BlockAttributes
): Promise<{block: allForks.BeaconBlock; blobs: eip4844.Blobs}> {
produceBlock(blockAttributes: BlockAttributes): Promise<allForks.BeaconBlock> {
return this.produceBlockWrapper<BlockType.Full>(BlockType.Full, blockAttributes);
}

async produceBlindedBlock(blockAttributes: BlockAttributes): Promise<allForks.BlindedBeaconBlock> {
const {block} = await this.produceBlockWrapper<BlockType.Blinded>(BlockType.Blinded, blockAttributes);
return block;
produceBlindedBlock(blockAttributes: BlockAttributes): Promise<allForks.BlindedBeaconBlock> {
return this.produceBlockWrapper<BlockType.Blinded>(BlockType.Blinded, blockAttributes);
}

async produceBlockWrapper<T extends BlockType>(
blockType: T,
{randaoReveal, graffiti, slot}: BlockAttributes
): Promise<{block: AssembledBlockType<T>; blobs: eip4844.Blobs}> {
): Promise<AssembledBlockType<T>> {
const head = this.forkChoice.getHead();
const state = await this.regen.getBlockSlotState(head.blockRoot, slot, RegenCaller.produceBlock);
const parentBlockRoot = fromHexString(head.blockRoot);
Expand All @@ -386,7 +381,36 @@ export class BeaconChain implements IBeaconChain {

block.stateRoot = computeNewStateRoot(this.metrics, state, block);

return {block, blobs: blobs ?? []};
// Cache for latter broadcasting
if (blobs.type === BlobsResultType.produced) {
this.producedBlobsCache.set(blobs.blockRoot, blobs.blobs);
}

return block;
}

/**
* https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/validator.md#sidecar
* def get_blobs_sidecar(block: BeaconBlock, blobs: Sequence[Blob]) -> BlobsSidecar:
* return BlobsSidecar(
* beacon_block_root=hash_tree_root(block),
* beacon_block_slot=block.slot,
* blobs=blobs,
* kzg_aggregated_proof=compute_proof_from_blobs(blobs),
* )
*/
getBlobsSidecar(beaconBlockRoot: RootHex): eip4844.BlobsSidecar {
const blobs = this.producedBlobsCache.get(beaconBlockRoot);
if (!blobs) {
throw Error(`No blobs for beaconBlockRoot ${beaconBlockRoot}`);
}

return {
beaconBlockRoot: beaconBlockRoot,
beaconBlockSlot: blobs.slot,
blobs: blobs,
kzgAggregatedProof: computeAggregateKzgProof(blobs),
};
}

async processBlock(block: allForks.SignedBeaconBlock, opts?: ImportBlockOpts): Promise<void> {
Expand Down
1 change: 0 additions & 1 deletion packages/beacon-node/src/chain/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ export interface IBeaconChain {
getCanonicalBlockAtSlot(slot: Slot): Promise<allForks.SignedBeaconBlock | null>;

produceBlock(blockAttributes: BlockAttributes): Promise<allForks.BeaconBlock>;
produceBlockWithBlobs(blockAttributes: BlockAttributes): Promise<{block: allForks.BeaconBlock; blobs: eip4844.Blobs}>;
produceBlindedBlock(blockAttributes: BlockAttributes): Promise<allForks.BlindedBeaconBlock>;

/** Process a block until complete */
Expand Down
1 change: 1 addition & 0 deletions packages/beacon-node/src/chain/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export type IChainOptions = BlockProcessOpts &
faultInspectionWindow?: number;
/** Number of missed slots allowed in the faultInspectionWindow for builder circuit*/
allowedFaults?: number;
sanityCheckExecutionEngineBlocks?: boolean;
};

export type BlockProcessOpts = {
Expand Down
Loading

0 comments on commit 26a0794

Please sign in to comment.