Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
3 changes: 2 additions & 1 deletion packages/beacon-node/src/execution/engine/payloadIdCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ export type DepositReceiptV1 = {
index: QUANTITY;
};

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

type FcuAttributes = {headBlockHash: DATA; finalizedBlockHash: DATA} & Omit<PayloadAttributesRpc, "withdrawals">;
Expand Down
50 changes: 31 additions & 19 deletions packages/beacon-node/src/execution/engine/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
quantityToBigint,
} from "../../eth1/provider/utils.js";
import {ExecutionPayloadStatus, BlobsBundle, PayloadAttributes, VersionedHashes} from "./interface.js";
import {WithdrawalV1, DepositReceiptV1, ExecutionLayerExitV1} from "./payloadIdCache.js";
import {WithdrawalV1, DepositReceiptV1, ExecutionLayerWithdrawalRequestV1} from "./payloadIdCache.js";

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

Expand Down Expand Up @@ -119,14 +119,14 @@ export type ExecutionPayloadBodyRpc = {
transactions: DATA[];
withdrawals: WithdrawalV1[] | null | undefined;
depositReceipts: DepositReceiptV1[] | null | undefined;
exits: ExecutionLayerExitV1[] | null | undefined;
withdrawalRequests: ExecutionLayerWithdrawalRequestV1[] | null | undefined;
};

export type ExecutionPayloadBody = {
transactions: bellatrix.Transaction[];
withdrawals: capella.Withdrawals | null;
depositReceipts: electra.DepositReceipts | null;
exits: electra.ExecutionLayerExits | null;
withdrawalRequests: electra.ExecutionLayerWithdrawalRequests | null;
};

export type ExecutionPayloadRpc = {
Expand All @@ -149,7 +149,7 @@ export type ExecutionPayloadRpc = {
excessBlobGas?: QUANTITY; // DENEB
parentBeaconBlockRoot?: QUANTITY; // DENEB
depositReceipts?: DepositReceiptRpc[]; // ELECTRA
exits?: ExecutionLayerExitRpc[]; // ELECTRA
withdrawalRequests?: ExecutionLayerWithdrawalRequestRpc[]; // ELECTRA
};

export type WithdrawalRpc = {
Expand All @@ -160,7 +160,7 @@ export type WithdrawalRpc = {
};

export type DepositReceiptRpc = DepositReceiptV1;
export type ExecutionLayerExitRpc = ExecutionLayerExitV1;
export type ExecutionLayerWithdrawalRequestRpc = ExecutionLayerWithdrawalRequestV1;

export type VersionedHashesRpc = DATA[];

Expand Down Expand Up @@ -215,9 +215,9 @@ export function serializeExecutionPayload(fork: ForkName, data: allForks.Executi

// ELECTRA adds depositReceipts to the ExecutionPayload
if (ForkSeq[fork] >= ForkSeq.electra) {
const {depositReceipts, exits} = data as electra.ExecutionPayload;
const {depositReceipts, withdrawalRequests} = data as electra.ExecutionPayload;
payload.depositReceipts = depositReceipts.map(serializeDepositReceipt);
payload.exits = exits.map(serializeExecutionLayerExit);
payload.withdrawalRequests = withdrawalRequests.map(serializeExecutionLayerWithdrawalRequest);
}

return payload;
Expand Down Expand Up @@ -306,7 +306,7 @@ export function parseExecutionPayload(
}

if (ForkSeq[fork] >= ForkSeq.electra) {
const {depositReceipts, exits} = data;
const {depositReceipts, withdrawalRequests} = data;
// Geth can also reply with null
if (depositReceipts == null) {
throw Error(
Expand All @@ -315,12 +315,14 @@ export function parseExecutionPayload(
}
(executionPayload as electra.ExecutionPayload).depositReceipts = depositReceipts.map(deserializeDepositReceipt);

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

return {executionPayload, executionPayloadValue, blobsBundle, shouldOverrideBuilder};
Expand Down Expand Up @@ -409,17 +411,23 @@ export function deserializeDepositReceipt(serialized: DepositReceiptRpc): electr
} as electra.DepositReceipt;
}

export function serializeExecutionLayerExit(exit: electra.ExecutionLayerExit): ExecutionLayerExitRpc {
export function serializeExecutionLayerWithdrawalRequest(
withdrawalRequest: electra.ExecutionLayerWithdrawalRequest
): ExecutionLayerWithdrawalRequestRpc {
return {
sourceAddress: bytesToData(exit.sourceAddress),
validatorPubkey: bytesToData(exit.validatorPubkey),
sourceAddress: bytesToData(withdrawalRequest.sourceAddress),
validatorPubkey: bytesToData(withdrawalRequest.validatorPubkey),
amount: numToQuantity(withdrawalRequest.amount),
};
}

export function deserializeExecutionLayerExit(exit: ExecutionLayerExitRpc): electra.ExecutionLayerExit {
export function deserializeExecutionLayerWithdrawalRequest(
withdrawalRequest: ExecutionLayerWithdrawalRequestRpc
): electra.ExecutionLayerWithdrawalRequest {
return {
sourceAddress: dataToBytes(exit.sourceAddress, 20),
validatorPubkey: dataToBytes(exit.validatorPubkey, 48),
sourceAddress: dataToBytes(withdrawalRequest.sourceAddress, 20),
validatorPubkey: dataToBytes(withdrawalRequest.validatorPubkey, 48),
amount: quantityToNum(withdrawalRequest.amount),
};
}

Expand All @@ -429,7 +437,9 @@ export function deserializeExecutionPayloadBody(data: ExecutionPayloadBodyRpc |
transactions: data.transactions.map((tran) => dataToBytes(tran, null)),
withdrawals: data.withdrawals ? data.withdrawals.map(deserializeWithdrawal) : null,
depositReceipts: data.depositReceipts ? data.depositReceipts.map(deserializeDepositReceipt) : null,
exits: data.exits ? data.exits.map(deserializeExecutionLayerExit) : null,
withdrawalRequests: data.withdrawalRequests
? data.withdrawalRequests.map(deserializeExecutionLayerWithdrawalRequest)
: null,
}
: null;
}
Expand All @@ -440,7 +450,9 @@ export function serializeExecutionPayloadBody(data: ExecutionPayloadBody | null)
transactions: data.transactions.map((tran) => bytesToData(tran)),
withdrawals: data.withdrawals ? data.withdrawals.map(serializeWithdrawal) : null,
depositReceipts: data.depositReceipts ? data.depositReceipts.map(serializeDepositReceipt) : null,
exits: data.exits ? data.exits.map(serializeExecutionLayerExit) : null,
withdrawalRequests: data.withdrawalRequests
? data.withdrawalRequests.map(serializeExecutionLayerWithdrawalRequest)
: null,
}
: null;
}
Expand Down
6 changes: 3 additions & 3 deletions packages/light-client/src/spec/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,8 @@ export function upgradeLightClientHeader(
case ForkName.electra:
(upgradedHeader as electra.LightClientHeader).execution.depositReceiptsRoot =
ssz.electra.LightClientHeader.fields.execution.fields.depositReceiptsRoot.defaultValue();
(upgradedHeader as electra.LightClientHeader).execution.exitsRoot =
ssz.electra.LightClientHeader.fields.execution.fields.exitsRoot.defaultValue();
(upgradedHeader as electra.LightClientHeader).execution.withdrawalRequestsRoot =
ssz.electra.LightClientHeader.fields.execution.fields.withdrawalRequestsRoot.defaultValue();

// Break if no further upgrades is required else fall through
if (ForkSeq[targetFork] <= ForkSeq.electra) break;
Expand Down Expand Up @@ -149,7 +149,7 @@ export function isValidLightClientHeader(config: ChainForkConfig, header: allFor
if (epoch < config.ELECTRA_FORK_EPOCH) {
if (
(header as electra.LightClientHeader).execution.depositReceiptsRoot !== undefined ||
(header as electra.LightClientHeader).execution.exitsRoot !== undefined
(header as electra.LightClientHeader).execution.withdrawalRequestsRoot !== undefined
) {
return false;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/params/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export const {
KZG_COMMITMENT_INCLUSION_PROOF_DEPTH,

MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD,
MAX_EXECUTION_LAYER_EXITS,
MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD,
MAX_ATTESTER_SLASHINGS_ELECTRA,
MAX_ATTESTATIONS_ELECTRA,
} = activePreset;
Expand Down
2 changes: 1 addition & 1 deletion packages/params/src/presets/mainnet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export const mainnetPreset: BeaconPreset = {

// ELECTRA
MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: 8192,
MAX_EXECUTION_LAYER_EXITS: 16,
MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: 16,
MAX_ATTESTER_SLASHINGS_ELECTRA: 1,
MAX_ATTESTATIONS_ELECTRA: 8,
};
2 changes: 1 addition & 1 deletion packages/params/src/presets/minimal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export const minimalPreset: BeaconPreset = {

// ELECTRA
MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: 4,
MAX_EXECUTION_LAYER_EXITS: 16,
MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: 16,
MAX_ATTESTER_SLASHINGS_ELECTRA: 1,
MAX_ATTESTATIONS_ELECTRA: 8,
};
4 changes: 2 additions & 2 deletions packages/params/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export type BeaconPreset = {

// ELECTRA
MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: number;
MAX_EXECUTION_LAYER_EXITS: number;
MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: number;
MAX_ATTESTER_SLASHINGS_ELECTRA: number;
MAX_ATTESTATIONS_ELECTRA: number;
};
Expand Down Expand Up @@ -176,7 +176,7 @@ export const beaconPresetTypes: BeaconPresetTypes = {

// ELECTRA
MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: "number",
MAX_EXECUTION_LAYER_EXITS: "number",
MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: "number",
MAX_ATTESTER_SLASHINGS_ELECTRA: "number",
MAX_ATTESTATIONS_ELECTRA: "number",
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,33 @@ import {isActiveValidator} from "../util/index.js";
import {CachedBeaconStateElectra} from "../types.js";
import {initiateValidatorExit} from "./index.js";

const FULL_EXIT_REQUEST_AMOUNT = 0;
/**
* Process execution layer exit messages and initiate exit incase they belong to a valid active validator
* otherwise silent ignore.
*/
export function processExecutionLayerExit(state: CachedBeaconStateElectra, exit: electra.ExecutionLayerExit): void {
const validator = isValidExecutionLayerExit(state, exit);
if (validator === null) {
return;
}
export function processExecutionLayerWithdrawalRequest(
state: CachedBeaconStateElectra,
withdrawalRequest: electra.ExecutionLayerWithdrawalRequest
): void {
const isFullExitRequest = withdrawalRequest.amount === FULL_EXIT_REQUEST_AMOUNT;

if (isFullExitRequest) {
const validator = isValidExecutionLayerExit(state, withdrawalRequest);
if (validator === null) {
return;
}

initiateValidatorExit(state, validator);
initiateValidatorExit(state, validator);
} else {
// partial withdral request add codeblock
}
}

// TODO electra : add pending withdrawal check before exit
export function isValidExecutionLayerExit(
state: CachedBeaconStateElectra,
exit: electra.ExecutionLayerExit
exit: electra.ExecutionLayerWithdrawalRequest
): CompositeViewDU<typeof ssz.phase0.Validator> | null {
const {config, epochCtx} = state;
const validatorIndex = epochCtx.getValidatorIndex(exit.validatorPubkey);
Expand Down
8 changes: 4 additions & 4 deletions packages/state-transition/src/block/processOperations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {processProposerSlashing} from "./processProposerSlashing.js";
import {processAttesterSlashing} from "./processAttesterSlashing.js";
import {processDeposit} from "./processDeposit.js";
import {processVoluntaryExit} from "./processVoluntaryExit.js";
import {processExecutionLayerExit} from "./processExecutionLayerExit.js";
import {processExecutionLayerWithdrawalRequest} from "./processExecutionLayerWithdrawalRequest.js";
import {processBlsToExecutionChange} from "./processBlsToExecutionChange.js";
import {processDepositReceipt} from "./processDepositReceipt.js";
import {ProcessBlockOpts} from "./types.js";
Expand All @@ -19,7 +19,7 @@ export {
processAttestations,
processDeposit,
processVoluntaryExit,
processExecutionLayerExit,
processExecutionLayerWithdrawalRequest,
processBlsToExecutionChange,
processDepositReceipt,
};
Expand Down Expand Up @@ -55,8 +55,8 @@ export function processOperations(
processVoluntaryExit(state, voluntaryExit, opts.verifySignatures);
}
if (fork >= ForkSeq.electra) {
for (const elExit of (body as electra.BeaconBlockBody).executionPayload.exits) {
processExecutionLayerExit(state as CachedBeaconStateElectra, elExit);
for (const elWithdrawalRequest of (body as electra.BeaconBlockBody).executionPayload.withdrawalRequests) {
processExecutionLayerWithdrawalRequest(state as CachedBeaconStateElectra, elWithdrawalRequest);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export function upgradeStateToElectra(stateDeneb: CachedBeaconStateDeneb): Cache
epoch: stateDeneb.epochCtx.epoch,
});

// latestExecutionPayloadHeader's depositReceiptsRoot and exitsRoot set to zeros by default
// latestExecutionPayloadHeader's depositReceiptsRoot and withdrawalRequestsRoot set to zeros by default
// default value of depositReceiptsStartIndex is UNSET_DEPOSIT_RECEIPTS_START_INDEX
stateElectra.depositReceiptsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX;

Expand Down
7 changes: 4 additions & 3 deletions packages/state-transition/src/util/execution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,10 @@ export function executionPayloadToPayloadHeader(
if (fork >= ForkSeq.electra) {
(bellatrixPayloadFields as electra.ExecutionPayloadHeader).depositReceiptsRoot =
ssz.electra.DepositReceipts.hashTreeRoot((payload as electra.ExecutionPayload).depositReceipts);
(bellatrixPayloadFields as electra.ExecutionPayloadHeader).exitsRoot = ssz.electra.ExecutionLayerExits.hashTreeRoot(
(payload as electra.ExecutionPayload).exits
);
(bellatrixPayloadFields as electra.ExecutionPayloadHeader).withdrawalRequestsRoot =
ssz.electra.ExecutionLayerWithdrawalRequests.hashTreeRoot(
(payload as electra.ExecutionPayload).withdrawalRequests
);
}

return bellatrixPayloadFields;
Expand Down
16 changes: 10 additions & 6 deletions packages/types/src/electra/sszTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
MAX_COMMITTEES_PER_SLOT,
MAX_ATTESTATIONS_ELECTRA,
MAX_ATTESTER_SLASHINGS_ELECTRA,
MAX_EXECUTION_LAYER_EXITS,
MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD,
} from "@lodestar/params";
import {ssz as primitiveSsz} from "../primitive/index.js";
import {ssz as phase0Ssz} from "../phase0/index.js";
Expand Down Expand Up @@ -117,20 +117,24 @@ export const DepositReceipt = new ContainerType(

export const DepositReceipts = new ListCompositeType(DepositReceipt, MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD);

export const ExecutionLayerExit = new ContainerType(
export const ExecutionLayerWithdrawalRequest = new ContainerType(
{
sourceAddress: ExecutionAddress,
validatorPubkey: BLSPubkey,
amount: UintNum64,
},
{typeName: "ExecutionLayerExit", jsonCase: "eth2"}
{typeName: "ExecutionLayerWithdrawalRequest", jsonCase: "eth2"}
);
export const ExecutionLayerWithdrawalRequests = new ListCompositeType(
ExecutionLayerWithdrawalRequest,
MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD
);
export const ExecutionLayerExits = new ListCompositeType(ExecutionLayerExit, MAX_EXECUTION_LAYER_EXITS);

export const ExecutionPayload = new ContainerType(
{
...denebSsz.ExecutionPayload.fields,
depositReceipts: DepositReceipts, // New in ELECTRA
exits: ExecutionLayerExits, // New in ELECTRA
withdrawalRequests: ExecutionLayerWithdrawalRequests, // New in ELECTRA
},
{typeName: "ExecutionPayload", jsonCase: "eth2"}
);
Expand All @@ -139,7 +143,7 @@ export const ExecutionPayloadHeader = new ContainerType(
{
...denebSsz.ExecutionPayloadHeader.fields,
depositReceiptsRoot: Root, // New in ELECTRA
exitsRoot: Root, // New in ELECTRA
withdrawalRequestsRoot: Root, // New in ELECTRA
},
{typeName: "ExecutionPayloadHeader", jsonCase: "eth2"}
);
Expand Down
4 changes: 2 additions & 2 deletions packages/types/src/electra/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ export type SignedAggregateAndProof = ValueOf<typeof ssz.SignedAggregateAndProof
export type DepositReceipt = ValueOf<typeof ssz.DepositReceipt>;
export type DepositReceipts = ValueOf<typeof ssz.DepositReceipts>;

export type ExecutionLayerExit = ValueOf<typeof ssz.ExecutionLayerExit>;
export type ExecutionLayerExits = ValueOf<typeof ssz.ExecutionLayerExits>;
export type ExecutionLayerWithdrawalRequest = ValueOf<typeof ssz.ExecutionLayerWithdrawalRequest>;
export type ExecutionLayerWithdrawalRequests = ValueOf<typeof ssz.ExecutionLayerWithdrawalRequests>;

export type ExecutionPayload = ValueOf<typeof ssz.ExecutionPayload>;
export type ExecutionPayloadHeader = ValueOf<typeof ssz.ExecutionPayloadHeader>;
Expand Down
2 changes: 1 addition & 1 deletion packages/validator/src/util/params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ function getSpecCriticalParams(localConfig: ChainConfig): Record<keyof ConfigWit

// ELECTRA
MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: electraForkRelevant,
MAX_EXECUTION_LAYER_EXITS: electraForkRelevant,
MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: electraForkRelevant,
MAX_ATTESTER_SLASHINGS_ELECTRA: electraForkRelevant,
MAX_ATTESTATIONS_ELECTRA: electraForkRelevant,
};
Expand Down