Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: move requests from execution payload to beacon block body #7094

Merged
merged 8 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 27 additions & 9 deletions packages/beacon-node/src/execution/engine/http.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {ExecutionPayload, Root, RootHex, Wei} from "@lodestar/types";
import {SLOTS_PER_EPOCH, ForkName, ForkSeq} from "@lodestar/params";
import {ExecutionPayload, ExecutionRequests, Root, RootHex, Wei} from "@lodestar/types";
import {SLOTS_PER_EPOCH, ForkName, ForkSeq, isForkPostElectra} from "@lodestar/params";
import {Logger} from "@lodestar/logger";
import {
ErrorJsonRpcResponse,
Expand Down Expand Up @@ -37,6 +37,7 @@ import {
ExecutionPayloadBody,
assertReqSizeLimit,
deserializeExecutionPayloadBody,
serializeExecutionRequests,
} from "./types.js";
import {getExecutionEngineState} from "./utils.js";

Expand Down Expand Up @@ -195,7 +196,8 @@ export class ExecutionEngineHttp implements IExecutionEngine {
fork: ForkName,
executionPayload: ExecutionPayload,
versionedHashes?: VersionedHashes,
parentBlockRoot?: Root
parentBlockRoot?: Root,
executionRequests?: ExecutionRequests
): Promise<ExecutePayloadResponse> {
const method =
ForkSeq[fork] >= ForkSeq.electra
Expand All @@ -220,12 +222,28 @@ export class ExecutionEngineHttp implements IExecutionEngine {
const serializedVersionedHashes = serializeVersionedHashes(versionedHashes);
const parentBeaconBlockRoot = serializeBeaconBlockRoot(parentBlockRoot);

const method = ForkSeq[fork] >= ForkSeq.electra ? "engine_newPayloadV4" : "engine_newPayloadV3";
engineRequest = {
method,
params: [serializedExecutionPayload, serializedVersionedHashes, parentBeaconBlockRoot],
methodOpts: notifyNewPayloadOpts,
};
if (ForkSeq[fork] >= ForkSeq.electra) {
if (executionRequests === undefined) {
throw Error(`executionRequests required in notifyNewPayload for fork=${fork}`);
}
const serializedExecutionRequests = serializeExecutionRequests(executionRequests);
engineRequest = {
method: "engine_newPayloadV4",
params: [
serializedExecutionPayload,
serializedVersionedHashes,
parentBeaconBlockRoot,
serializedExecutionRequests,
],
methodOpts: notifyNewPayloadOpts,
};
} else {
engineRequest = {
method: "engine_newPayloadV3",
params: [serializedExecutionPayload, serializedVersionedHashes, parentBeaconBlockRoot],
methodOpts: notifyNewPayloadOpts,
};
}
} else {
const method = ForkSeq[fork] >= ForkSeq.capella ? "engine_newPayloadV2" : "engine_newPayloadV1";
engineRequest = {
Expand Down
4 changes: 2 additions & 2 deletions packages/beacon-node/src/execution/engine/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import {KZGCommitment, Blob, KZGProof} from "@lodestar/types/deneb";
import {Root, RootHex, capella, Wei, ExecutionPayload} from "@lodestar/types";

import {DATA} from "../../eth1/provider/utils.js";
import {PayloadIdCache, PayloadId, WithdrawalV1, DepositRequestV1} from "./payloadIdCache.js";
import {PayloadIdCache, PayloadId, WithdrawalV1} from "./payloadIdCache.js";
import {ExecutionPayloadBody} from "./types.js";

export {PayloadIdCache, type PayloadId, type WithdrawalV1, type DepositRequestV1};
export {PayloadIdCache, type PayloadId, type WithdrawalV1};

export enum ExecutionPayloadStatus {
/** given payload is valid */
Expand Down
20 changes: 0 additions & 20 deletions packages/beacon-node/src/execution/engine/payloadIdCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,6 @@ export type WithdrawalV1 = {
amount: QUANTITY;
};

export type DepositRequestV1 = {
pubkey: DATA;
withdrawalCredentials: DATA;
amount: QUANTITY;
signature: DATA;
index: QUANTITY;
};

export type WithdrawalRequestV1 = {
sourceAddress: DATA;
validatorPubkey: DATA;
amount: QUANTITY;
};

export type ConsolidationRequestV1 = {
sourceAddress: DATA;
sourcePubkey: DATA;
targetPubkey: DATA;
};

type FcuAttributes = {headBlockHash: DATA; finalizedBlockHash: DATA} & Omit<PayloadAttributesRpc, "withdrawals">;

export class PayloadIdCache {
Expand Down
130 changes: 80 additions & 50 deletions packages/beacon-node/src/execution/engine/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {capella, deneb, electra, Wei, bellatrix, Root, ExecutionPayload} from "@lodestar/types";
import {capella, deneb, electra, Wei, bellatrix, Root, ExecutionPayload, ExecutionRequests} from "@lodestar/types";
import {
BYTES_PER_LOGS_BLOOM,
FIELD_ELEMENTS_PER_BLOB,
Expand All @@ -17,7 +17,7 @@ import {
quantityToBigint,
} from "../../eth1/provider/utils.js";
import {ExecutionPayloadStatus, BlobsBundle, PayloadAttributes, VersionedHashes} from "./interface.js";
import {WithdrawalV1, DepositRequestV1, WithdrawalRequestV1, ConsolidationRequestV1} from "./payloadIdCache.js";
import {WithdrawalV1} from "./payloadIdCache.js";

/* eslint-disable @typescript-eslint/naming-convention */

Expand All @@ -28,7 +28,7 @@ export type EngineApiRpcParamTypes = {
engine_newPayloadV1: [ExecutionPayloadRpc];
engine_newPayloadV2: [ExecutionPayloadRpc];
engine_newPayloadV3: [ExecutionPayloadRpc, VersionedHashesRpc, DATA];
engine_newPayloadV4: [ExecutionPayloadRpc, VersionedHashesRpc, DATA];
engine_newPayloadV4: [ExecutionPayloadRpc, VersionedHashesRpc, DATA, ExecutionRequestsRpc];
/**
* 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 @@ -131,9 +131,9 @@ export type ExecutionPayloadBodyRpc = {
withdrawals: WithdrawalV1[] | null | undefined;
// currently there is a discepancy between EL and CL field name references for deposit requests
// its likely CL receipt will be renamed to requests
depositRequests: DepositRequestV1[] | null | undefined;
withdrawalRequests: WithdrawalRequestV1[] | null | undefined;
consolidationRequests: ConsolidationRequestV1[] | null | undefined;
depositRequests: DepositRequestRpc[] | null | undefined;
withdrawalRequests: WithdrawalRequestRpc[] | null | undefined;
consolidationRequests: ConsolidationRequestRpc[] | null | undefined;
};

export type ExecutionPayloadBody = {
Expand Down Expand Up @@ -175,9 +175,29 @@ export type WithdrawalRpc = {
amount: QUANTITY;
};

export type DepositRequestRpc = DepositRequestV1;
export type WithdrawalRequestRpc = WithdrawalRequestV1;
export type ConsolidationRequestRpc = ConsolidationRequestV1;
export type ExecutionRequestsRpc = {
deposits: DepositRequestRpc[];
withdrawals: WithdrawalRequestRpc[];
consolidations: ConsolidationRequestRpc[];
};

export type DepositRequestRpc = {
pubkey: DATA;
withdrawalCredentials: DATA;
amount: QUANTITY;
signature: DATA;
index: QUANTITY;
};
export type WithdrawalRequestRpc = {
sourceAddress: DATA;
validatorPubkey: DATA;
amount: QUANTITY;
};
export type ConsolidationRequestRpc = {
sourceAddress: DATA;
sourcePubkey: DATA;
targetPubkey: DATA;
};

export type VersionedHashesRpc = DATA[];

Expand Down Expand Up @@ -241,12 +261,8 @@ export function serializeExecutionPayload(fork: ForkName, data: ExecutionPayload
payload.excessBlobGas = numToQuantity(excessBlobGas);
}

// ELECTRA adds depositRequests/depositRequests to the ExecutionPayload
// No changes in Electra
if (ForkSeq[fork] >= ForkSeq.electra) {
const {depositRequests, withdrawalRequests, consolidationRequests} = data as electra.ExecutionPayload;
payload.depositRequests = depositRequests.map(serializeDepositRequest);
payload.withdrawalRequests = withdrawalRequests.map(serializeWithdrawalRequest);
payload.consolidationRequests = consolidationRequests.map(serializeConsolidationRequest);
}

return payload;
Expand Down Expand Up @@ -334,33 +350,32 @@ export function parseExecutionPayload(
(executionPayload as deneb.ExecutionPayload).excessBlobGas = quantityToBigint(excessBlobGas);
}

// No changes in Electra
if (ForkSeq[fork] >= ForkSeq.electra) {
// electra adds depositRequests/depositRequests
const {depositRequests, withdrawalRequests, consolidationRequests} = data;
// Geth can also reply with null
if (depositRequests == null) {
throw Error(
`depositRequests missing for ${fork} >= electra executionPayload number=${executionPayload.blockNumber} hash=${data.blockHash}`
);
}
(executionPayload as electra.ExecutionPayload).depositRequests = depositRequests.map(deserializeDepositRequest);

if (withdrawalRequests == null) {
throw Error(
`withdrawalRequests missing for ${fork} >= electra executionPayload number=${executionPayload.blockNumber} hash=${data.blockHash}`
);
}
(executionPayload as electra.ExecutionPayload).withdrawalRequests =
withdrawalRequests.map(deserializeWithdrawalRequest);

if (consolidationRequests == null) {
throw Error(
`consolidationRequests missing for ${fork} >= electra executionPayload number=${executionPayload.blockNumber} hash=${data.blockHash}`
);
}
(executionPayload as electra.ExecutionPayload).consolidationRequests = consolidationRequests.map(
deserializeConsolidationRequest
);
// // electra adds depositRequests/depositRequests
// const {depositRequests, withdrawalRequests, consolidationRequests} = data;
// // Geth can also reply with null
// if (depositRequests == null) {
// throw Error(
// `depositRequests missing for ${fork} >= electra executionPayload number=${executionPayload.blockNumber} hash=${data.blockHash}`
// );
// }
// (executionPayload as electra.ExecutionPayload).depositRequests = depositRequests.map(deserializeDepositRequest);
// if (withdrawalRequests == null) {
// throw Error(
// `withdrawalRequests missing for ${fork} >= electra executionPayload number=${executionPayload.blockNumber} hash=${data.blockHash}`
// );
// }
// (executionPayload as electra.ExecutionPayload).withdrawalRequests =
// withdrawalRequests.map(deserializeWithdrawalRequest);
// if (consolidationRequests == null) {
// throw Error(
// `consolidationRequests missing for ${fork} >= electra executionPayload number=${executionPayload.blockNumber} hash=${data.blockHash}`
// );
// }
// (executionPayload as electra.ExecutionPayload).consolidationRequests = consolidationRequests.map(
// deserializeConsolidationRequest
// );
}

return {executionPayload, executionPayloadValue, blobsBundle, shouldOverrideBuilder};
Expand Down Expand Up @@ -429,7 +444,7 @@ export function deserializeWithdrawal(serialized: WithdrawalRpc): capella.Withdr
} as capella.Withdrawal;
}

export function serializeDepositRequest(depositRequest: electra.DepositRequest): DepositRequestRpc {
function serializeDepositRequest(depositRequest: electra.DepositRequest): DepositRequestRpc {
return {
pubkey: bytesToData(depositRequest.pubkey),
withdrawalCredentials: bytesToData(depositRequest.withdrawalCredentials),
Expand All @@ -439,7 +454,7 @@ export function serializeDepositRequest(depositRequest: electra.DepositRequest):
};
}

export function deserializeDepositRequest(serialized: DepositRequestRpc): electra.DepositRequest {
function deserializeDepositRequest(serialized: DepositRequestRpc): electra.DepositRequest {
return {
pubkey: dataToBytes(serialized.pubkey, 48),
withdrawalCredentials: dataToBytes(serialized.withdrawalCredentials, 32),
Expand All @@ -449,42 +464,57 @@ export function deserializeDepositRequest(serialized: DepositRequestRpc): electr
} as electra.DepositRequest;
}

export function serializeWithdrawalRequest(withdrawalRequest: electra.WithdrawalRequest): WithdrawalRequestRpc {
function serializeWithdrawalRequest(withdrawalRequest: electra.WithdrawalRequest): WithdrawalRequestRpc {
return {
sourceAddress: bytesToData(withdrawalRequest.sourceAddress),
validatorPubkey: bytesToData(withdrawalRequest.validatorPubkey),
amount: numToQuantity(withdrawalRequest.amount),
};
}

export function deserializeWithdrawalRequest(withdrawalRequest: WithdrawalRequestRpc): electra.WithdrawalRequest {
function deserializeWithdrawalRequest(withdrawalRequest: WithdrawalRequestRpc): electra.WithdrawalRequest {
return {
sourceAddress: dataToBytes(withdrawalRequest.sourceAddress, 20),
validatorPubkey: dataToBytes(withdrawalRequest.validatorPubkey, 48),
amount: quantityToBigint(withdrawalRequest.amount),
};
}

export function serializeConsolidationRequest(
consolidationRequest: electra.ConsolidationRequest
): ConsolidationRequestRpc {
function serializeConsolidationRequest(consolidationRequest: electra.ConsolidationRequest): ConsolidationRequestRpc {
return {
sourceAddress: bytesToData(consolidationRequest.sourceAddress),
sourcePubkey: bytesToData(consolidationRequest.sourcePubkey),
targetPubkey: bytesToData(consolidationRequest.targetPubkey),
};
}

export function deserializeConsolidationRequest(
consolidationRequest: ConsolidationRequestRpc
): electra.ConsolidationRequest {
function deserializeConsolidationRequest(consolidationRequest: ConsolidationRequestRpc): electra.ConsolidationRequest {
return {
sourceAddress: dataToBytes(consolidationRequest.sourceAddress, 20),
sourcePubkey: dataToBytes(consolidationRequest.sourcePubkey, 48),
targetPubkey: dataToBytes(consolidationRequest.targetPubkey, 48),
};
}

export function serializeExecutionRequests(executionRequests: ExecutionRequests): ExecutionRequestsRpc {
const {deposits, withdrawals, consolidations} = executionRequests;
return {
deposits: deposits.map(serializeDepositRequest),
withdrawals: withdrawals.map(serializeWithdrawalRequest),
consolidations: consolidations.map(serializeConsolidationRequest),
};
}

export function deserializeExecutionRequests(executionRequests: ExecutionRequestsRpc): ExecutionRequests {
const {deposits, withdrawals, consolidations} = executionRequests;
return {
deposits: deposits.map(deserializeDepositRequest),
withdrawals: withdrawals.map(deserializeWithdrawalRequest),
consolidations: consolidations.map(deserializeConsolidationRequest),
};
}

// TODO ELectra: remove requests field
export function deserializeExecutionPayloadBody(data: ExecutionPayloadBodyRpc | null): ExecutionPayloadBody | null {
return data
? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ describe("UpgradeLightClientHeader", function () {
capella: ssz.capella.LightClientHeader.defaultValue(),
bellatrix: ssz.altair.LightClientHeader.defaultValue(),
deneb: ssz.deneb.LightClientHeader.defaultValue(),
electra: ssz.electra.LightClientHeader.defaultValue(),
electra: ssz.deneb.LightClientHeader.defaultValue(),
};

testSlots = {
Expand Down
17 changes: 1 addition & 16 deletions packages/light-client/src/spec/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,7 @@ export function upgradeLightClientHeader(

// eslint-disable-next-line no-fallthrough
case ForkName.electra:
(upgradedHeader as LightClientHeader<ForkName.electra>).execution.depositRequestsRoot =
ssz.electra.LightClientHeader.fields.execution.fields.depositRequestsRoot.defaultValue();
(upgradedHeader as LightClientHeader<ForkName.electra>).execution.withdrawalRequestsRoot =
ssz.electra.LightClientHeader.fields.execution.fields.withdrawalRequestsRoot.defaultValue();
(upgradedHeader as LightClientHeader<ForkName.electra>).execution.consolidationRequestsRoot =
ssz.electra.LightClientHeader.fields.execution.fields.consolidationRequestsRoot.defaultValue();
// No changes to LightClientHeader in Electra

// Break if no further upgrades is required else fall through
if (ForkSeq[targetFork] <= ForkSeq.electra) break;
Expand Down Expand Up @@ -170,16 +165,6 @@ export function isValidLightClientHeader(config: ChainForkConfig, header: LightC
}
}

if (epoch < config.ELECTRA_FORK_EPOCH) {
if (
(header as LightClientHeader<ForkName.electra>).execution.depositRequestsRoot !== undefined ||
(header as LightClientHeader<ForkName.electra>).execution.withdrawalRequestsRoot !== undefined ||
(header as LightClientHeader<ForkName.electra>).execution.consolidationRequestsRoot !== undefined
) {
return false;
}
}

return isValidMerkleBranch(
config
.getExecutionForkTypes(header.beacon.slot)
Expand Down
6 changes: 3 additions & 3 deletions packages/state-transition/src/block/processOperations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,15 @@ export function processOperations(
const stateElectra = state as CachedBeaconStateElectra;
const bodyElectra = body as electra.BeaconBlockBody;

for (const depositRequest of bodyElectra.executionPayload.depositRequests) {
for (const depositRequest of bodyElectra.executionRequests.deposits) {
processDepositRequest(fork, stateElectra, depositRequest);
}

for (const elWithdrawalRequest of bodyElectra.executionPayload.withdrawalRequests) {
for (const elWithdrawalRequest of bodyElectra.executionRequests.withdrawals) {
processWithdrawalRequest(fork, stateElectra, elWithdrawalRequest);
}

for (const elConsolidationRequest of bodyElectra.executionPayload.consolidationRequests) {
for (const elConsolidationRequest of bodyElectra.executionRequests.consolidations) {
processConsolidationRequest(stateElectra, elConsolidationRequest);
}
}
Expand Down
Loading
Loading