Skip to content

Commit

Permalink
feat: implement eip 4788 for deneb (#5703)
Browse files Browse the repository at this point in the history
* feat: implement eip 4788 for deneb

* fixes

* lint
  • Loading branch information
g11tech authored Jun 26, 2023
1 parent 50daa01 commit f5d12a8
Show file tree
Hide file tree
Showing 11 changed files with 114 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -293,7 +293,13 @@ export async function verifyBlockExecutionPayload(
ForkSeq[fork] >= ForkSeq.deneb
? (block.message.body as deneb.BeaconBlockBody).blobKzgCommitments.map(kzgCommitmentToVersionedHash)
: undefined;
const execResult = await chain.executionEngine.notifyNewPayload(fork, executionPayloadEnabled, versionedHashes);
const parentBlockRoot = ForkSeq[fork] >= ForkSeq.deneb ? block.message.parentRoot : undefined;
const execResult = await chain.executionEngine.notifyNewPayload(
fork,
executionPayloadEnabled,
versionedHashes,
parentBlockRoot
);

chain.metrics?.engineNotifyNewPayloadResult.inc({result: execResult.status});

Expand Down
1 change: 1 addition & 0 deletions packages/beacon-node/src/chain/prepareNextSlot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ export class PrepareNextSlotScheduler {
this.chain,
this.logger,
fork as ForkExecution, // State is of execution type
fromHex(headRoot),
safeBlockHash,
finalizedBlockHash,
prepareState,
Expand Down
77 changes: 54 additions & 23 deletions packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import {
} from "@lodestar/state-transition";
import {ChainForkConfig} from "@lodestar/config";
import {ForkSeq, ForkExecution, isForkExecution} from "@lodestar/params";
import {toHex, sleep, Logger, fromHex} from "@lodestar/utils";
import {toHex, sleep, Logger} from "@lodestar/utils";

import type {BeaconChain} from "../chain.js";
import {PayloadId, IExecutionEngine, IExecutionBuilder, PayloadAttributes} from "../../execution/index.js";
Expand Down Expand Up @@ -154,6 +154,7 @@ export async function produceBlockBody<T extends BlockType>(
this,
this.logger,
fork,
parentBlockRoot,
safeBlockHash,
finalizedBlockHash ?? ZERO_HASH_HEX,
currentState as CachedBeaconStateBellatrix,
Expand Down Expand Up @@ -196,6 +197,7 @@ export async function produceBlockBody<T extends BlockType>(
this,
this.logger,
fork,
parentBlockRoot,
safeBlockHash,
finalizedBlockHash ?? ZERO_HASH_HEX,
currentState as CachedBeaconStateExecutions,
Expand Down Expand Up @@ -316,6 +318,7 @@ export async function prepareExecutionPayload(
},
logger: Logger,
fork: ForkExecution,
parentBlockRoot: Root,
safeBlockHash: RootHex,
finalizedBlockHash: RootHex,
state: CachedBeaconStateExecutions,
Expand Down Expand Up @@ -357,15 +360,12 @@ export async function prepareExecutionPayload(
prepType = PayloadPreparationType.Fresh;
}

const attributes: PayloadAttributes = {
timestamp,
prevRandao,
suggestedFeeRecipient,
};

if (ForkSeq[fork] >= ForkSeq.capella) {
attributes.withdrawals = getExpectedWithdrawals(state as CachedBeaconStateCapella).withdrawals;
}
const attributes: PayloadAttributes = preparePayloadAttributes(fork, chain, {
prepareState: state,
prepareSlot: state.slot,
parentBlockRoot,
feeRecipient: suggestedFeeRecipient,
});

payloadId = await chain.executionEngine.notifyForkchoiceUpdate(
fork,
Expand Down Expand Up @@ -469,19 +469,12 @@ export async function getPayloadAttributesForSSE(

if (!parentHashRes.isPremerge) {
const {parentHash} = parentHashRes;
const timestamp = computeTimeAtSlot(chain.config, prepareSlot, prepareState.genesisTime);
const prevRandao = getRandaoMix(prepareState, prepareState.epochCtx.epoch);
const payloadAttributes = {
timestamp,
prevRandao,
suggestedFeeRecipient: fromHex(feeRecipient),
};

if (ForkSeq[fork] >= ForkSeq.capella) {
(payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals = getExpectedWithdrawals(
prepareState as CachedBeaconStateCapella
).withdrawals;
}
const payloadAttributes = preparePayloadAttributes(fork, chain, {
prepareState,
prepareSlot,
parentBlockRoot,
feeRecipient,
});

const ssePayloadAttributes: allForks.SSEPayloadAttributes = {
proposerIndex: prepareState.epochCtx.getBeaconProposer(prepareSlot),
Expand All @@ -497,4 +490,42 @@ export async function getPayloadAttributesForSSE(
}
}

function preparePayloadAttributes(
fork: ForkExecution,
chain: {
config: ChainForkConfig;
},
{
prepareState,
prepareSlot,
parentBlockRoot,
feeRecipient,
}: {
prepareState: CachedBeaconStateExecutions;
prepareSlot: Slot;
parentBlockRoot: Root;
feeRecipient: string;
}
): allForks.SSEPayloadAttributes["payloadAttributes"] {
const timestamp = computeTimeAtSlot(chain.config, prepareSlot, prepareState.genesisTime);
const prevRandao = getRandaoMix(prepareState, prepareState.epochCtx.epoch);
const payloadAttributes = {
timestamp,
prevRandao,
suggestedFeeRecipient: feeRecipient,
};

if (ForkSeq[fork] >= ForkSeq.capella) {
(payloadAttributes as capella.SSEPayloadAttributes["payloadAttributes"]).withdrawals = getExpectedWithdrawals(
prepareState as CachedBeaconStateCapella
).withdrawals;
}

if (ForkSeq[fork] >= ForkSeq.deneb) {
(payloadAttributes as deneb.SSEPayloadAttributes["payloadAttributes"]).parentBeaconBlockRoot = parentBlockRoot;
}

return payloadAttributes;
}

/** process_sync_committee_contributions is implemented in syncCommitteeContribution.getSyncAggregate */
19 changes: 13 additions & 6 deletions packages/beacon-node/src/execution/engine/http.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {RootHex, allForks, Wei} from "@lodestar/types";
import {Root, RootHex, allForks, Wei} from "@lodestar/types";
import {SLOTS_PER_EPOCH, ForkName, ForkSeq} from "@lodestar/params";

import {ErrorJsonRpcResponse, HttpRpcError} from "../../eth1/provider/jsonRpcHttpClient.js";
Expand All @@ -25,6 +25,7 @@ import {
serializeExecutionPayload,
serializeVersionedHashes,
serializePayloadAttributes,
serializeBeaconBlockRoot,
ExecutionPayloadBody,
assertReqSizeLimit,
deserializeExecutionPayloadBody,
Expand Down Expand Up @@ -138,7 +139,8 @@ export class ExecutionEngineHttp implements IExecutionEngine {
async notifyNewPayload(
fork: ForkName,
executionPayload: allForks.ExecutionPayload,
versionedHashes?: VersionedHashes
versionedHashes?: VersionedHashes,
parentBlockRoot?: Root
): Promise<ExecutePayloadResponse> {
const method =
ForkSeq[fork] >= ForkSeq.deneb
Expand All @@ -148,18 +150,23 @@ export class ExecutionEngineHttp implements IExecutionEngine {
: "engine_newPayloadV1";

const serializedExecutionPayload = serializeExecutionPayload(fork, executionPayload);
const serializedVersionedHashes =
versionedHashes !== undefined ? serializeVersionedHashes(versionedHashes) : undefined;

let engingRequest: EngineRequest;
if (ForkSeq[fork] >= ForkSeq.deneb) {
if (serializedVersionedHashes === undefined) {
if (versionedHashes === undefined) {
throw Error(`versionedHashes required in notifyNewPayload for fork=${fork}`);
}
if (parentBlockRoot === undefined) {
throw Error(`parentBlockRoot required in notifyNewPayload for fork=${fork}`);
}

const serializedVersionedHashes = serializeVersionedHashes(versionedHashes);
const parentBeaconBlockRoot = serializeBeaconBlockRoot(parentBlockRoot);

const method = "engine_newPayloadV3";
engingRequest = {
method,
params: [serializedExecutionPayload, serializedVersionedHashes],
params: [serializedExecutionPayload, serializedVersionedHashes, parentBeaconBlockRoot],
methodOpts: notifyNewPayloadOpts,
};
} else {
Expand Down
6 changes: 4 additions & 2 deletions packages/beacon-node/src/execution/engine/interface.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {ForkName} from "@lodestar/params";
import {KZGCommitment, Blob, KZGProof} from "@lodestar/types/deneb";
import {RootHex, allForks, capella, Wei} from "@lodestar/types";
import {Root, RootHex, allForks, capella, Wei} from "@lodestar/types";

import {DATA, QUANTITY} from "../../eth1/provider/utils.js";
import {PayloadIdCache, PayloadId, WithdrawalV1} from "./payloadIdCache.js";
Expand Down Expand Up @@ -52,6 +52,7 @@ export type PayloadAttributes = {
// avoid any conversions
suggestedFeeRecipient: string;
withdrawals?: capella.Withdrawal[];
parentBeaconBlockRoot?: Uint8Array;
};

export type TransitionConfigurationV1 = {
Expand Down Expand Up @@ -92,7 +93,8 @@ export interface IExecutionEngine {
notifyNewPayload(
fork: ForkName,
executionPayload: allForks.ExecutionPayload,
versionedHashes?: VersionedHashes
versionedHashes?: VersionedHashes,
parentBeaconBlockRoot?: Root
): Promise<ExecutePayloadResponse>;

/**
Expand Down
8 changes: 6 additions & 2 deletions packages/beacon-node/src/execution/engine/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {allForks, capella, deneb, Wei, bellatrix} from "@lodestar/types";
import {allForks, capella, deneb, Wei, bellatrix, Root} from "@lodestar/types";
import {
BYTES_PER_LOGS_BLOOM,
FIELD_ELEMENTS_PER_BLOB,
Expand Down Expand Up @@ -33,7 +33,7 @@ export type EngineApiRpcParamTypes = {
*/
engine_newPayloadV1: [ExecutionPayloadRpc];
engine_newPayloadV2: [ExecutionPayloadRpc];
engine_newPayloadV3: [ExecutionPayloadRpc, VersionedHashesRpc];
engine_newPayloadV3: [ExecutionPayloadRpc, VersionedHashesRpc, DATA];
/**
* 1. Object - Payload validity status with respect to the consensus rules:
* - blockHash: DATA, 32 Bytes - block hash value of the payload
Expand Down Expand Up @@ -283,6 +283,10 @@ export function serializePayloadAttributes(data: PayloadAttributes): PayloadAttr
};
}

export function serializeBeaconBlockRoot(data: Root): DATA {
return bytesToData(data);
}

export function deserializePayloadAttributes(data: PayloadAttributesRpc): PayloadAttributes {
return {
timestamp: quantityToNum(data.timestamp),
Expand Down
2 changes: 1 addition & 1 deletion packages/types/src/allForks/sszTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export const allForksExecution = {
ExecutionPayloadHeader: deneb.ExecutionPayloadHeader,
BuilderBid: deneb.BuilderBid,
SignedBuilderBid: deneb.SignedBuilderBid,
SSEPayloadAttributes: capella.SSEPayloadAttributes,
SSEPayloadAttributes: deneb.SSEPayloadAttributes,
},
};

Expand Down
9 changes: 7 additions & 2 deletions packages/types/src/allForks/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,10 @@ export type LightClientStore = altair.LightClientStore | capella.LightClientStor

export type SignedBeaconBlockAndBlobsSidecar = deneb.SignedBeaconBlockAndBlobsSidecar;

export type SSEPayloadAttributes = bellatrix.SSEPayloadAttributes | capella.SSEPayloadAttributes;
export type SSEPayloadAttributes =
| bellatrix.SSEPayloadAttributes
| capella.SSEPayloadAttributes
| deneb.SSEPayloadAttributes;
/**
* Types known to change between forks
*/
Expand Down Expand Up @@ -222,7 +225,9 @@ export type AllForksExecutionSSZTypes = {
typeof bellatrixSsz.SignedBuilderBid | typeof capellaSsz.SignedBuilderBid | typeof denebSsz.SignedBuilderBid
>;
SSEPayloadAttributes: AllForksTypeOf<
typeof bellatrixSsz.SSEPayloadAttributes | typeof capellaSsz.SSEPayloadAttributes
| typeof bellatrixSsz.SSEPayloadAttributes
| typeof capellaSsz.SSEPayloadAttributes
| typeof denebSsz.SSEPayloadAttributes
>;
};

Expand Down
3 changes: 2 additions & 1 deletion packages/types/src/bellatrix/sszTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
import {ssz as primitiveSsz} from "../primitive/index.js";
import {ssz as phase0Ssz} from "../phase0/index.js";
import {ssz as altairSsz} from "../altair/index.js";
import {stringType} from "../utils/StringType.js";

const {
Bytes32,
Expand Down Expand Up @@ -218,7 +219,7 @@ export const SignedBuilderBid = new ContainerType(

// PayloadAttributes primarily for SSE event
export const PayloadAttributes = new ContainerType(
{timestamp: UintNum64, prevRandao: Bytes32, suggestedFeeRecipient: ExecutionAddress},
{timestamp: UintNum64, prevRandao: Bytes32, suggestedFeeRecipient: stringType},
{typeName: "PayloadAttributes", jsonCase: "eth2"}
);

Expand Down
18 changes: 18 additions & 0 deletions packages/types/src/deneb/sszTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
import {ssz as primitiveSsz} from "../primitive/index.js";
import {ssz as phase0Ssz} from "../phase0/index.js";
import {ssz as altairSsz} from "../altair/index.js";
import {ssz as bellatrixSsz} from "../bellatrix/index.js";
import {ssz as capellaSsz} from "../capella/index.js";

const {
Expand Down Expand Up @@ -385,3 +386,20 @@ export const LightClientStore = new ContainerType(
},
{typeName: "LightClientStore", jsonCase: "eth2"}
);

// PayloadAttributes primarily for SSE event
export const PayloadAttributes = new ContainerType(
{
...capellaSsz.PayloadAttributes.fields,
parentBeaconBlockRoot: Root,
},
{typeName: "PayloadAttributes", jsonCase: "eth2"}
);

export const SSEPayloadAttributes = new ContainerType(
{
...bellatrixSsz.SSEPayloadAttributesCommon.fields,
payloadAttributes: PayloadAttributes,
},
{typeName: "SSEPayloadAttributes", jsonCase: "eth2"}
);
1 change: 1 addition & 0 deletions packages/types/src/deneb/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export type FullOrBlindedExecutionPayload = ExecutionPayload | ExecutionPayloadH

export type BuilderBid = ValueOf<typeof ssz.BuilderBid>;
export type SignedBuilderBid = ValueOf<typeof ssz.SignedBuilderBid>;
export type SSEPayloadAttributes = ValueOf<typeof ssz.SSEPayloadAttributes>;

export type LightClientHeader = ValueOf<typeof ssz.LightClientHeader>;
export type LightClientBootstrap = ValueOf<typeof ssz.LightClientBootstrap>;
Expand Down

0 comments on commit f5d12a8

Please sign in to comment.