Skip to content

Commit e54ea93

Browse files
committed
feat: upgrade 7002 exits to withdrawal request (#6736)
* feat: upgrade 7002 exits to withdrawal request * fix types * fix types and references * further fix the types references and get build passing * update the process ops fn but needs to be extended by maxeb
1 parent 95f954f commit e54ea93

File tree

14 files changed

+81
-52
lines changed

14 files changed

+81
-52
lines changed

packages/beacon-node/src/execution/engine/payloadIdCache.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@ export type DepositReceiptV1 = {
2626
index: QUANTITY;
2727
};
2828

29-
export type ExecutionLayerExitV1 = {
29+
export type ExecutionLayerWithdrawalRequestV1 = {
3030
sourceAddress: DATA;
3131
validatorPubkey: DATA;
32+
amount: QUANTITY;
3233
};
3334

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

packages/beacon-node/src/execution/engine/types.ts

+31-19
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717
quantityToBigint,
1818
} from "../../eth1/provider/utils.js";
1919
import {ExecutionPayloadStatus, BlobsBundle, PayloadAttributes, VersionedHashes} from "./interface.js";
20-
import {WithdrawalV1, DepositReceiptV1, ExecutionLayerExitV1} from "./payloadIdCache.js";
20+
import {WithdrawalV1, DepositReceiptV1, ExecutionLayerWithdrawalRequestV1} from "./payloadIdCache.js";
2121

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

@@ -119,14 +119,14 @@ export type ExecutionPayloadBodyRpc = {
119119
transactions: DATA[];
120120
withdrawals: WithdrawalV1[] | null | undefined;
121121
depositReceipts: DepositReceiptV1[] | null | undefined;
122-
exits: ExecutionLayerExitV1[] | null | undefined;
122+
withdrawalRequests: ExecutionLayerWithdrawalRequestV1[] | null | undefined;
123123
};
124124

125125
export type ExecutionPayloadBody = {
126126
transactions: bellatrix.Transaction[];
127127
withdrawals: capella.Withdrawals | null;
128128
depositReceipts: electra.DepositReceipts | null;
129-
exits: electra.ExecutionLayerExits | null;
129+
withdrawalRequests: electra.ExecutionLayerWithdrawalRequests | null;
130130
};
131131

132132
export type ExecutionPayloadRpc = {
@@ -149,7 +149,7 @@ export type ExecutionPayloadRpc = {
149149
excessBlobGas?: QUANTITY; // DENEB
150150
parentBeaconBlockRoot?: QUANTITY; // DENEB
151151
depositReceipts?: DepositReceiptRpc[]; // ELECTRA
152-
exits?: ExecutionLayerExitRpc[]; // ELECTRA
152+
withdrawalRequests?: ExecutionLayerWithdrawalRequestRpc[]; // ELECTRA
153153
};
154154

155155
export type WithdrawalRpc = {
@@ -160,7 +160,7 @@ export type WithdrawalRpc = {
160160
};
161161

162162
export type DepositReceiptRpc = DepositReceiptV1;
163-
export type ExecutionLayerExitRpc = ExecutionLayerExitV1;
163+
export type ExecutionLayerWithdrawalRequestRpc = ExecutionLayerWithdrawalRequestV1;
164164

165165
export type VersionedHashesRpc = DATA[];
166166

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

216216
// ELECTRA adds depositReceipts to the ExecutionPayload
217217
if (ForkSeq[fork] >= ForkSeq.electra) {
218-
const {depositReceipts, exits} = data as electra.ExecutionPayload;
218+
const {depositReceipts, withdrawalRequests} = data as electra.ExecutionPayload;
219219
payload.depositReceipts = depositReceipts.map(serializeDepositReceipt);
220-
payload.exits = exits.map(serializeExecutionLayerExit);
220+
payload.withdrawalRequests = withdrawalRequests.map(serializeExecutionLayerWithdrawalRequest);
221221
}
222222

223223
return payload;
@@ -306,7 +306,7 @@ export function parseExecutionPayload(
306306
}
307307

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

318-
if (exits == null) {
318+
if (withdrawalRequests == null) {
319319
throw Error(
320-
`exits missing for ${fork} >= electra executionPayload number=${executionPayload.blockNumber} hash=${data.blockHash}`
320+
`withdrawalRequests missing for ${fork} >= electra executionPayload number=${executionPayload.blockNumber} hash=${data.blockHash}`
321321
);
322322
}
323-
(executionPayload as electra.ExecutionPayload).exits = exits.map(deserializeExecutionLayerExit);
323+
(executionPayload as electra.ExecutionPayload).withdrawalRequests = withdrawalRequests.map(
324+
deserializeExecutionLayerWithdrawalRequest
325+
);
324326
}
325327

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

412-
export function serializeExecutionLayerExit(exit: electra.ExecutionLayerExit): ExecutionLayerExitRpc {
414+
export function serializeExecutionLayerWithdrawalRequest(
415+
withdrawalRequest: electra.ExecutionLayerWithdrawalRequest
416+
): ExecutionLayerWithdrawalRequestRpc {
413417
return {
414-
sourceAddress: bytesToData(exit.sourceAddress),
415-
validatorPubkey: bytesToData(exit.validatorPubkey),
418+
sourceAddress: bytesToData(withdrawalRequest.sourceAddress),
419+
validatorPubkey: bytesToData(withdrawalRequest.validatorPubkey),
420+
amount: numToQuantity(withdrawalRequest.amount),
416421
};
417422
}
418423

419-
export function deserializeExecutionLayerExit(exit: ExecutionLayerExitRpc): electra.ExecutionLayerExit {
424+
export function deserializeExecutionLayerWithdrawalRequest(
425+
withdrawalRequest: ExecutionLayerWithdrawalRequestRpc
426+
): electra.ExecutionLayerWithdrawalRequest {
420427
return {
421-
sourceAddress: dataToBytes(exit.sourceAddress, 20),
422-
validatorPubkey: dataToBytes(exit.validatorPubkey, 48),
428+
sourceAddress: dataToBytes(withdrawalRequest.sourceAddress, 20),
429+
validatorPubkey: dataToBytes(withdrawalRequest.validatorPubkey, 48),
430+
amount: quantityToNum(withdrawalRequest.amount),
423431
};
424432
}
425433

@@ -429,7 +437,9 @@ export function deserializeExecutionPayloadBody(data: ExecutionPayloadBodyRpc |
429437
transactions: data.transactions.map((tran) => dataToBytes(tran, null)),
430438
withdrawals: data.withdrawals ? data.withdrawals.map(deserializeWithdrawal) : null,
431439
depositReceipts: data.depositReceipts ? data.depositReceipts.map(deserializeDepositReceipt) : null,
432-
exits: data.exits ? data.exits.map(deserializeExecutionLayerExit) : null,
440+
withdrawalRequests: data.withdrawalRequests
441+
? data.withdrawalRequests.map(deserializeExecutionLayerWithdrawalRequest)
442+
: null,
433443
}
434444
: null;
435445
}
@@ -440,7 +450,9 @@ export function serializeExecutionPayloadBody(data: ExecutionPayloadBody | null)
440450
transactions: data.transactions.map((tran) => bytesToData(tran)),
441451
withdrawals: data.withdrawals ? data.withdrawals.map(serializeWithdrawal) : null,
442452
depositReceipts: data.depositReceipts ? data.depositReceipts.map(serializeDepositReceipt) : null,
443-
exits: data.exits ? data.exits.map(serializeExecutionLayerExit) : null,
453+
withdrawalRequests: data.withdrawalRequests
454+
? data.withdrawalRequests.map(serializeExecutionLayerWithdrawalRequest)
455+
: null,
444456
}
445457
: null;
446458
}

packages/light-client/src/spec/utils.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,8 @@ export function upgradeLightClientHeader(
108108
case ForkName.electra:
109109
(upgradedHeader as electra.LightClientHeader).execution.depositReceiptsRoot =
110110
ssz.electra.LightClientHeader.fields.execution.fields.depositReceiptsRoot.defaultValue();
111-
(upgradedHeader as electra.LightClientHeader).execution.exitsRoot =
112-
ssz.electra.LightClientHeader.fields.execution.fields.exitsRoot.defaultValue();
111+
(upgradedHeader as electra.LightClientHeader).execution.withdrawalRequestsRoot =
112+
ssz.electra.LightClientHeader.fields.execution.fields.withdrawalRequestsRoot.defaultValue();
113113

114114
// Break if no further upgrades is required else fall through
115115
if (ForkSeq[targetFork] <= ForkSeq.electra) break;
@@ -149,7 +149,7 @@ export function isValidLightClientHeader(config: ChainForkConfig, header: allFor
149149
if (epoch < config.ELECTRA_FORK_EPOCH) {
150150
if (
151151
(header as electra.LightClientHeader).execution.depositReceiptsRoot !== undefined ||
152-
(header as electra.LightClientHeader).execution.exitsRoot !== undefined
152+
(header as electra.LightClientHeader).execution.withdrawalRequestsRoot !== undefined
153153
) {
154154
return false;
155155
}

packages/params/src/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ export const {
9595
KZG_COMMITMENT_INCLUSION_PROOF_DEPTH,
9696

9797
MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD,
98-
MAX_EXECUTION_LAYER_EXITS,
98+
MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD,
9999
MAX_ATTESTER_SLASHINGS_ELECTRA,
100100
MAX_ATTESTATIONS_ELECTRA,
101101
} = activePreset;

packages/params/src/presets/mainnet.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ export const mainnetPreset: BeaconPreset = {
121121

122122
// ELECTRA
123123
MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: 8192,
124-
MAX_EXECUTION_LAYER_EXITS: 16,
124+
MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: 16,
125125
MAX_ATTESTER_SLASHINGS_ELECTRA: 1,
126126
MAX_ATTESTATIONS_ELECTRA: 8,
127127
};

packages/params/src/presets/minimal.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ export const minimalPreset: BeaconPreset = {
122122

123123
// ELECTRA
124124
MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: 4,
125-
MAX_EXECUTION_LAYER_EXITS: 16,
125+
MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: 16,
126126
MAX_ATTESTER_SLASHINGS_ELECTRA: 1,
127127
MAX_ATTESTATIONS_ELECTRA: 8,
128128
};

packages/params/src/types.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ export type BeaconPreset = {
8585

8686
// ELECTRA
8787
MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: number;
88-
MAX_EXECUTION_LAYER_EXITS: number;
88+
MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: number;
8989
MAX_ATTESTER_SLASHINGS_ELECTRA: number;
9090
MAX_ATTESTATIONS_ELECTRA: number;
9191
};
@@ -176,7 +176,7 @@ export const beaconPresetTypes: BeaconPresetTypes = {
176176

177177
// ELECTRA
178178
MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: "number",
179-
MAX_EXECUTION_LAYER_EXITS: "number",
179+
MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: "number",
180180
MAX_ATTESTER_SLASHINGS_ELECTRA: "number",
181181
MAX_ATTESTATIONS_ELECTRA: "number",
182182
};

packages/state-transition/src/block/processExecutionLayerExit.ts packages/state-transition/src/block/processExecutionLayerWithdrawalRequest.ts

+18-7
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,33 @@ import {isActiveValidator} from "../util/index.js";
66
import {CachedBeaconStateElectra} from "../types.js";
77
import {initiateValidatorExit} from "./index.js";
88

9+
const FULL_EXIT_REQUEST_AMOUNT = 0;
910
/**
1011
* Process execution layer exit messages and initiate exit incase they belong to a valid active validator
1112
* otherwise silent ignore.
1213
*/
13-
export function processExecutionLayerExit(state: CachedBeaconStateElectra, exit: electra.ExecutionLayerExit): void {
14-
const validator = isValidExecutionLayerExit(state, exit);
15-
if (validator === null) {
16-
return;
17-
}
14+
export function processExecutionLayerWithdrawalRequest(
15+
state: CachedBeaconStateElectra,
16+
withdrawalRequest: electra.ExecutionLayerWithdrawalRequest
17+
): void {
18+
const isFullExitRequest = withdrawalRequest.amount === FULL_EXIT_REQUEST_AMOUNT;
19+
20+
if (isFullExitRequest) {
21+
const validator = isValidExecutionLayerExit(state, withdrawalRequest);
22+
if (validator === null) {
23+
return;
24+
}
1825

19-
initiateValidatorExit(state, validator);
26+
initiateValidatorExit(state, validator);
27+
} else {
28+
// partial withdral request add codeblock
29+
}
2030
}
2131

32+
// TODO electra : add pending withdrawal check before exit
2233
export function isValidExecutionLayerExit(
2334
state: CachedBeaconStateElectra,
24-
exit: electra.ExecutionLayerExit
35+
exit: electra.ExecutionLayerWithdrawalRequest
2536
): CompositeViewDU<typeof ssz.phase0.Validator> | null {
2637
const {config, epochCtx} = state;
2738
const validatorIndex = epochCtx.getValidatorIndex(exit.validatorPubkey);

packages/state-transition/src/block/processOperations.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {processProposerSlashing} from "./processProposerSlashing.js";
88
import {processAttesterSlashing} from "./processAttesterSlashing.js";
99
import {processDeposit} from "./processDeposit.js";
1010
import {processVoluntaryExit} from "./processVoluntaryExit.js";
11-
import {processExecutionLayerExit} from "./processExecutionLayerExit.js";
11+
import {processExecutionLayerWithdrawalRequest} from "./processExecutionLayerWithdrawalRequest.js";
1212
import {processBlsToExecutionChange} from "./processBlsToExecutionChange.js";
1313
import {processDepositReceipt} from "./processDepositReceipt.js";
1414
import {ProcessBlockOpts} from "./types.js";
@@ -19,7 +19,7 @@ export {
1919
processAttestations,
2020
processDeposit,
2121
processVoluntaryExit,
22-
processExecutionLayerExit,
22+
processExecutionLayerWithdrawalRequest,
2323
processBlsToExecutionChange,
2424
processDepositReceipt,
2525
};
@@ -55,8 +55,8 @@ export function processOperations(
5555
processVoluntaryExit(state, voluntaryExit, opts.verifySignatures);
5656
}
5757
if (fork >= ForkSeq.electra) {
58-
for (const elExit of (body as electra.BeaconBlockBody).executionPayload.exits) {
59-
processExecutionLayerExit(state as CachedBeaconStateElectra, elExit);
58+
for (const elWithdrawalRequest of (body as electra.BeaconBlockBody).executionPayload.withdrawalRequests) {
59+
processExecutionLayerWithdrawalRequest(state as CachedBeaconStateElectra, elWithdrawalRequest);
6060
}
6161
}
6262

packages/state-transition/src/slot/upgradeStateToElectra.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export function upgradeStateToElectra(stateDeneb: CachedBeaconStateDeneb): Cache
2020
epoch: stateDeneb.epochCtx.epoch,
2121
});
2222

23-
// latestExecutionPayloadHeader's depositReceiptsRoot and exitsRoot set to zeros by default
23+
// latestExecutionPayloadHeader's depositReceiptsRoot and withdrawalRequestsRoot set to zeros by default
2424
// default value of depositReceiptsStartIndex is UNSET_DEPOSIT_RECEIPTS_START_INDEX
2525
stateElectra.depositReceiptsStartIndex = UNSET_DEPOSIT_RECEIPTS_START_INDEX;
2626

packages/state-transition/src/util/execution.ts

+4-3
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,10 @@ export function executionPayloadToPayloadHeader(
173173
if (fork >= ForkSeq.electra) {
174174
(bellatrixPayloadFields as electra.ExecutionPayloadHeader).depositReceiptsRoot =
175175
ssz.electra.DepositReceipts.hashTreeRoot((payload as electra.ExecutionPayload).depositReceipts);
176-
(bellatrixPayloadFields as electra.ExecutionPayloadHeader).exitsRoot = ssz.electra.ExecutionLayerExits.hashTreeRoot(
177-
(payload as electra.ExecutionPayload).exits
178-
);
176+
(bellatrixPayloadFields as electra.ExecutionPayloadHeader).withdrawalRequestsRoot =
177+
ssz.electra.ExecutionLayerWithdrawalRequests.hashTreeRoot(
178+
(payload as electra.ExecutionPayload).withdrawalRequests
179+
);
179180
}
180181

181182
return bellatrixPayloadFields;

packages/types/src/electra/sszTypes.ts

+10-6
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
MAX_COMMITTEES_PER_SLOT,
1717
MAX_ATTESTATIONS_ELECTRA,
1818
MAX_ATTESTER_SLASHINGS_ELECTRA,
19-
MAX_EXECUTION_LAYER_EXITS,
19+
MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD,
2020
} from "@lodestar/params";
2121
import {ssz as primitiveSsz} from "../primitive/index.js";
2222
import {ssz as phase0Ssz} from "../phase0/index.js";
@@ -117,20 +117,24 @@ export const DepositReceipt = new ContainerType(
117117

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

120-
export const ExecutionLayerExit = new ContainerType(
120+
export const ExecutionLayerWithdrawalRequest = new ContainerType(
121121
{
122122
sourceAddress: ExecutionAddress,
123123
validatorPubkey: BLSPubkey,
124+
amount: UintNum64,
124125
},
125-
{typeName: "ExecutionLayerExit", jsonCase: "eth2"}
126+
{typeName: "ExecutionLayerWithdrawalRequest", jsonCase: "eth2"}
127+
);
128+
export const ExecutionLayerWithdrawalRequests = new ListCompositeType(
129+
ExecutionLayerWithdrawalRequest,
130+
MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD
126131
);
127-
export const ExecutionLayerExits = new ListCompositeType(ExecutionLayerExit, MAX_EXECUTION_LAYER_EXITS);
128132

129133
export const ExecutionPayload = new ContainerType(
130134
{
131135
...denebSsz.ExecutionPayload.fields,
132136
depositReceipts: DepositReceipts, // New in ELECTRA
133-
exits: ExecutionLayerExits, // New in ELECTRA
137+
withdrawalRequests: ExecutionLayerWithdrawalRequests, // New in ELECTRA
134138
},
135139
{typeName: "ExecutionPayload", jsonCase: "eth2"}
136140
);
@@ -139,7 +143,7 @@ export const ExecutionPayloadHeader = new ContainerType(
139143
{
140144
...denebSsz.ExecutionPayloadHeader.fields,
141145
depositReceiptsRoot: Root, // New in ELECTRA
142-
exitsRoot: Root, // New in ELECTRA
146+
withdrawalRequestsRoot: Root, // New in ELECTRA
143147
},
144148
{typeName: "ExecutionPayloadHeader", jsonCase: "eth2"}
145149
);

packages/types/src/electra/types.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ export type SignedAggregateAndProof = ValueOf<typeof ssz.SignedAggregateAndProof
1212
export type DepositReceipt = ValueOf<typeof ssz.DepositReceipt>;
1313
export type DepositReceipts = ValueOf<typeof ssz.DepositReceipts>;
1414

15-
export type ExecutionLayerExit = ValueOf<typeof ssz.ExecutionLayerExit>;
16-
export type ExecutionLayerExits = ValueOf<typeof ssz.ExecutionLayerExits>;
15+
export type ExecutionLayerWithdrawalRequest = ValueOf<typeof ssz.ExecutionLayerWithdrawalRequest>;
16+
export type ExecutionLayerWithdrawalRequests = ValueOf<typeof ssz.ExecutionLayerWithdrawalRequests>;
1717

1818
export type ExecutionPayload = ValueOf<typeof ssz.ExecutionPayload>;
1919
export type ExecutionPayloadHeader = ValueOf<typeof ssz.ExecutionPayloadHeader>;

packages/validator/src/util/params.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ function getSpecCriticalParams(localConfig: ChainConfig): Record<keyof ConfigWit
224224

225225
// ELECTRA
226226
MAX_DEPOSIT_RECEIPTS_PER_PAYLOAD: electraForkRelevant,
227-
MAX_EXECUTION_LAYER_EXITS: electraForkRelevant,
227+
MAX_WITHDRAWAL_REQUESTS_PER_PAYLOAD: electraForkRelevant,
228228
MAX_ATTESTER_SLASHINGS_ELECTRA: electraForkRelevant,
229229
MAX_ATTESTATIONS_ELECTRA: electraForkRelevant,
230230
};

0 commit comments

Comments
 (0)